1pub type Result<T> = anyhow::Result<T>;
15
16pub const VERSION: &str = env!("CARGO_PKG_VERSION");
18
19#[derive(Debug, Clone)]
21pub struct BuildInfo {
22 pub version: &'static str,
24 pub git_hash: Option<&'static str>,
26 pub build_date: Option<&'static str>,
28 pub rust_version: Option<&'static str>,
30 pub features: &'static [&'static str],
32}
33
34impl std::fmt::Display for BuildInfo {
35 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
36 writeln!(f, "dsq-shared {}", self.version)?;
37
38 if let Some(hash) = self.git_hash {
39 writeln!(f, "Git hash: {hash}")?;
40 }
41
42 if let Some(date) = self.build_date {
43 writeln!(f, "Built: {date}")?;
44 }
45
46 if let Some(rust_ver) = self.rust_version {
47 writeln!(f, "Rust: {rust_ver}")?;
48 }
49
50 if !self.features.is_empty() {
51 writeln!(f, "Features: {}", self.features.join(", "))?;
52 }
53
54 Ok(())
55 }
56}
57
58pub mod error {
60 pub fn operation_error(msg: impl Into<String>) -> anyhow::Error {
62 anyhow::anyhow!("Operation error: {}", msg.into())
63 }
64
65 pub fn config_error(msg: impl Into<String>) -> anyhow::Error {
67 anyhow::anyhow!("Configuration error: {}", msg.into())
68 }
69}
70
71pub mod value;
73
74pub mod ops;
76
77pub use value::is_truthy;
79
80pub mod utils {
82 use std::collections::HashMap;
83
84 pub fn hashmap<K, V, I>(pairs: I) -> HashMap<K, V>
86 where
87 I: IntoIterator<Item = (K, V)>,
88 K: std::hash::Hash + Eq,
89 {
90 pairs.into_iter().collect()
91 }
92
93 #[must_use]
95 pub fn is_blank(s: &str) -> bool {
96 s.trim().is_empty()
97 }
98
99 #[must_use]
101 pub fn capitalize_first(s: &str) -> String {
102 let mut chars = s.chars();
103 match chars.next() {
104 None => String::new(),
105 Some(first) => first.to_uppercase().collect::<String>() + chars.as_str(),
106 }
107 }
108}
109
110pub mod constants {
112 pub const DEFAULT_BATCH_SIZE: usize = 1000;
114
115 pub const MAX_BATCH_SIZE: usize = 100_000;
117
118 pub const DEFAULT_BUFFER_SIZE: usize = 8192;
120
121 pub const SMALL_BUFFER_SIZE: usize = 1024;
123
124 pub const LARGE_BUFFER_SIZE: usize = 128 * 1024; pub const DEFAULT_SCHEMA_INFERENCE_LENGTH: usize = 1000;
129
130 pub const MAX_RECURSION_DEPTH: usize = 1000;
132
133 pub const HIGH_THROUGHPUT_BATCH_SIZE: usize = 10000;
135
136 pub const FIELD_SEPARATOR: u8 = 31;
138
139 pub const RECORD_SEPARATOR: u8 = 30;
141
142 pub const CONTENT_SAMPLE_SIZE: usize = 4096;
144
145 pub const DEFAULT_MEMORY_LIMIT: usize = 1024 * 1024 * 1024;
147
148 pub const MAX_MEMORY_FILE_SIZE: usize = 100 * 1024 * 1024;
150}
151
152#[cfg(test)]
153mod tests {
154 use super::*;
155
156 #[test]
157 fn test_version_info() {
158 assert!(VERSION.contains('.'));
160 }
161
162 #[test]
163 fn test_build_info_display_full() {
164 let build_info = BuildInfo {
165 version: "1.0.0",
166 git_hash: Some("abc123"),
167 build_date: Some("2023-01-01"),
168 rust_version: Some("1.70.0"),
169 features: &["default", "serde"],
170 };
171
172 let display = format!("{}", build_info);
173 assert!(display.contains("dsq-shared 1.0.0"));
174 assert!(display.contains("Git hash: abc123"));
175 assert!(display.contains("Built: 2023-01-01"));
176 assert!(display.contains("Rust: 1.70.0"));
177 assert!(display.contains("Features: default, serde"));
178 }
179
180 #[test]
181 fn test_build_info_display_minimal() {
182 let build_info = BuildInfo {
183 version: "2.0.0",
184 git_hash: None,
185 build_date: None,
186 rust_version: None,
187 features: &[],
188 };
189
190 let display = format!("{}", build_info);
191 assert!(display.contains("dsq-shared 2.0.0"));
192 assert!(!display.contains("Git hash:"));
193 assert!(!display.contains("Built:"));
194 assert!(!display.contains("Rust:"));
195 assert!(!display.contains("Features:"));
196 }
197
198 #[test]
199 fn test_build_info_display_partial() {
200 let build_info = BuildInfo {
201 version: "1.5.0",
202 git_hash: Some("def456"),
203 build_date: None,
204 rust_version: Some("1.75.0"),
205 features: &[],
206 };
207
208 let display = format!("{}", build_info);
209 assert!(display.contains("dsq-shared 1.5.0"));
210 assert!(display.contains("Git hash: def456"));
211 assert!(display.contains("Rust: 1.75.0"));
212 assert!(!display.contains("Built:"));
213 assert!(!display.contains("Features:"));
214 }
215
216 #[test]
217 fn test_error_functions() {
218 let err = error::operation_error("test message");
219 assert!(err.to_string().contains("Operation error: test message"));
220
221 let err = error::config_error("config issue");
222 assert!(err
223 .to_string()
224 .contains("Configuration error: config issue"));
225 }
226
227 #[test]
228 fn test_utils_hashmap() {
229 let map = utils::hashmap([("key1", 1), ("key2", 2)]);
230 assert_eq!(map.get("key1"), Some(&1));
231 assert_eq!(map.get("key2"), Some(&2));
232 assert_eq!(map.len(), 2);
233 assert_eq!(map.get("nonexistent"), None);
234 }
235
236 #[test]
237 fn test_utils_hashmap_empty() {
238 let map: std::collections::HashMap<&str, i32> = utils::hashmap([]);
239 assert!(map.is_empty());
240 }
241
242 #[test]
243 fn test_utils_is_blank() {
244 assert!(utils::is_blank(""));
245 assert!(utils::is_blank(" "));
246 assert!(utils::is_blank("\t\n"));
247 assert!(utils::is_blank(" \t \n "));
248 assert!(!utils::is_blank("hello"));
249 assert!(!utils::is_blank(" hello "));
250 assert!(!utils::is_blank("a"));
251 assert!(!utils::is_blank("0"));
252 }
253
254 #[test]
255 fn test_utils_capitalize_first() {
256 assert_eq!(utils::capitalize_first("hello"), "Hello");
257 assert_eq!(utils::capitalize_first("HELLO"), "HELLO");
258 assert_eq!(utils::capitalize_first(""), "");
259 assert_eq!(utils::capitalize_first("a"), "A");
260 assert_eq!(utils::capitalize_first("123"), "123");
261 assert_eq!(utils::capitalize_first(" hello"), " hello");
262 assert_eq!(utils::capitalize_first("ñandu"), "Ñandu"); }
264
265 #[test]
266 fn test_constants() {
267 assert_eq!(constants::DEFAULT_BATCH_SIZE, 1000);
268 assert_eq!(constants::MAX_BATCH_SIZE, 100_000);
269 assert_eq!(constants::DEFAULT_BUFFER_SIZE, 8192);
270 assert_eq!(constants::SMALL_BUFFER_SIZE, 1024);
271 assert_eq!(constants::LARGE_BUFFER_SIZE, 128 * 1024);
272 assert_eq!(constants::DEFAULT_SCHEMA_INFERENCE_LENGTH, 1000);
273 assert_eq!(constants::MAX_RECURSION_DEPTH, 1000);
274 assert_eq!(constants::HIGH_THROUGHPUT_BATCH_SIZE, 10000);
275 assert_eq!(constants::FIELD_SEPARATOR, 31u8);
276 assert_eq!(constants::RECORD_SEPARATOR, 30u8);
277 assert_eq!(constants::CONTENT_SAMPLE_SIZE, 4096);
278 assert_eq!(constants::DEFAULT_MEMORY_LIMIT, 1024 * 1024 * 1024);
279 assert_eq!(constants::MAX_MEMORY_FILE_SIZE, 100 * 1024 * 1024);
280
281 }
284}