unilink  0.4.3
A simple C++ library for unified async communication
input_validator.hpp
Go to the documentation of this file.
1 /*
2  * Copyright 2025 Jinwoo Sung
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #pragma once
18 
19 #include <algorithm>
20 #include <cctype>
21 #include <cstdint>
22 #include <regex>
23 #include <string>
24 #include <string_view>
25 #include <vector>
26 
30 
31 namespace unilink {
32 namespace util {
33 
41  public:
42  // Network validation
43  static void validate_host(const std::string& host);
44  static void validate_port(uint16_t port);
45  static void validate_ipv4_address(const std::string& address);
46  static void validate_ipv6_address(const std::string& address);
47 
48  // Serial validation
49  static void validate_device_path(const std::string& device);
50  static void validate_baud_rate(uint32_t baud_rate);
51  static void validate_data_bits(uint8_t data_bits);
52  static void validate_stop_bits(uint8_t stop_bits);
53  static void validate_parity(const std::string& parity);
54 
55  // Memory validation
56  static void validate_buffer_size(size_t size);
57  static void validate_memory_alignment(const void* ptr, size_t alignment);
58 
59  // Timeout and interval validation
60  static void validate_timeout(unsigned timeout_ms);
61  static void validate_retry_interval(unsigned interval_ms);
62  static void validate_retry_count(int retry_count);
63 
64  // String validation
65  static void validate_non_empty_string(const std::string& str, const std::string& field_name);
66  static void validate_string_length(const std::string& str, size_t max_length, const std::string& field_name);
67 
68  // Numeric validation
69  static void validate_positive_number(int64_t value, const std::string& field_name);
70  static void validate_range(int64_t value, int64_t min, int64_t max, const std::string& field_name);
71  static void validate_range(size_t value, size_t min, size_t max, const std::string& field_name);
72 
73  // Validation helpers (exposed for public use)
74  static bool is_valid_host(const std::string& host);
75  static bool is_valid_ipv4(std::string_view address);
76  static bool is_valid_ipv6(const std::string& address);
77  static bool is_valid_hostname(std::string_view hostname);
78 
79  private:
80  // Helper methods
81  static bool is_valid_device_path(const std::string& device);
82 
83  // Constants for retry count
84  static constexpr int FINITE_MIN_RETRY_COUNT = 0;
85  static constexpr int FINITE_MAX_RETRY_COUNT = base::constants::MAX_RETRIES_LIMIT;
86 };
87 
88 // Inline implementations for simple validations
89 inline void InputValidator::validate_non_empty_string(const std::string& str, const std::string& field_name) {
90  if (str.empty()) {
91  throw diagnostics::ValidationException(field_name + " cannot be empty", field_name, "non-empty string");
92  }
93 }
94 
95 inline void InputValidator::validate_string_length(const std::string& str, size_t max_length,
96  const std::string& field_name) {
97  if (str.length() > max_length) {
98  throw diagnostics::ValidationException(field_name + " length exceeds maximum allowed length", field_name,
99  "length <= " + std::to_string(max_length));
100  }
101 }
102 
103 inline void InputValidator::validate_positive_number(int64_t value, const std::string& field_name) {
104  if (value <= 0) {
105  throw diagnostics::ValidationException(field_name + " must be positive", field_name, "positive number");
106  }
107 }
108 
109 inline void InputValidator::validate_range(int64_t value, int64_t min, int64_t max, const std::string& field_name) {
110  if (value < min || value > max) {
111  throw diagnostics::ValidationException(field_name + " out of range", field_name,
112  std::to_string(min) + " <= value <= " + std::to_string(max));
113  }
114 }
115 
116 inline void InputValidator::validate_range(size_t value, size_t min, size_t max, const std::string& field_name) {
117  if (value < min || value > max) {
118  throw diagnostics::ValidationException(field_name + " out of range", field_name,
119  std::to_string(min) + " <= value <= " + std::to_string(max));
120  }
121 }
122 
123 inline void InputValidator::validate_buffer_size(size_t size) {
124  validate_range(size, static_cast<size_t>(base::constants::MIN_BUFFER_SIZE),
125  static_cast<size_t>(base::constants::MAX_BUFFER_SIZE), "buffer_size");
126 }
127 
128 inline void InputValidator::validate_timeout(unsigned timeout_ms) {
129  validate_range(static_cast<int64_t>(timeout_ms), static_cast<int64_t>(base::constants::MIN_CONNECTION_TIMEOUT_MS),
130  static_cast<int64_t>(base::constants::MAX_CONNECTION_TIMEOUT_MS), "timeout_ms");
131 }
132 
133 inline void InputValidator::validate_retry_interval(unsigned interval_ms) {
134  validate_range(static_cast<int64_t>(interval_ms), static_cast<int64_t>(base::constants::MIN_RETRY_INTERVAL_MS),
135  static_cast<int64_t>(base::constants::MAX_RETRY_INTERVAL_MS), "retry_interval_ms");
136 }
137 
138 inline void InputValidator::validate_retry_count(int retry_count) {
139  if (retry_count == common::constants::DEFAULT_MAX_RETRIES) { // -1 means infinite, which is valid
140  return;
141  }
142  if (retry_count < FINITE_MIN_RETRY_COUNT || retry_count > FINITE_MAX_RETRY_COUNT) {
143  throw diagnostics::ValidationException("retry_count out of range", "retry_count",
144  std::to_string(FINITE_MIN_RETRY_COUNT) + " <= retry_count <= " +
145  std::to_string(FINITE_MAX_RETRY_COUNT) + " or -1 for infinite");
146  }
147 }
148 
149 inline void InputValidator::validate_port(uint16_t port) {
150  if (port == 0) {
151  throw diagnostics::ValidationException("port cannot be zero", "port", "non-zero port number");
152  }
153  // Port numbers are already constrained by uint16_t type (0-65535)
154 }
155 
156 inline void InputValidator::validate_baud_rate(uint32_t baud_rate) {
157  validate_range(static_cast<int64_t>(baud_rate), static_cast<int64_t>(base::constants::MIN_BAUD_RATE),
158  static_cast<int64_t>(base::constants::MAX_BAUD_RATE), "baud_rate");
159 }
160 
161 inline void InputValidator::validate_data_bits(uint8_t data_bits) {
162  validate_range(static_cast<int64_t>(data_bits), static_cast<int64_t>(base::constants::MIN_DATA_BITS),
163  static_cast<int64_t>(base::constants::MAX_DATA_BITS), "data_bits");
164 }
165 
166 inline void InputValidator::validate_stop_bits(uint8_t stop_bits) {
167  validate_range(static_cast<int64_t>(stop_bits), static_cast<int64_t>(base::constants::MIN_STOP_BITS),
168  static_cast<int64_t>(base::constants::MAX_STOP_BITS), "stop_bits");
169 }
170 
171 inline void InputValidator::validate_memory_alignment(const void* ptr, size_t alignment) {
172  if (ptr == nullptr) {
173  throw diagnostics::ValidationException("memory pointer cannot be null", "ptr", "non-null pointer");
174  }
175 
176  uintptr_t address = reinterpret_cast<uintptr_t>(ptr);
177  if (address % alignment != 0) {
178  throw diagnostics::ValidationException("memory pointer not properly aligned", "ptr",
179  "aligned to " + std::to_string(alignment) + " bytes");
180  }
181 }
182 
183 } // namespace util
184 } // namespace unilink
#define UNILINK_API
Definition: visibility.hpp:37