reifydb_type/value/int/
parse.rs1use std::borrow::Cow;
5
6use num_bigint::BigInt;
7
8use crate::{
9 error::{Error, TypeError},
10 fragment::Fragment,
11 value::{int::Int, r#type::Type},
12};
13
14pub fn parse_int(fragment: Fragment) -> Result<Int, Error> {
15 let raw_value = fragment.text();
17
18 let needs_trimming = raw_value.as_bytes().first().map_or(false, |&b| b.is_ascii_whitespace())
20 || raw_value.as_bytes().last().map_or(false, |&b| b.is_ascii_whitespace());
21 let has_underscores = raw_value.as_bytes().contains(&b'_');
22
23 let value = match (needs_trimming, has_underscores) {
24 (false, false) => Cow::Borrowed(raw_value), (true, false) => Cow::Borrowed(raw_value.trim()),
28 (false, true) => Cow::Owned(raw_value.replace('_', "")),
29 (true, true) => Cow::Owned(raw_value.trim().replace('_', "")),
30 };
31
32 if value.is_empty() {
33 return Err(TypeError::InvalidNumberFormat {
34 target: Type::Int,
35 fragment,
36 }
37 .into());
38 }
39
40 match value.parse::<BigInt>() {
42 Ok(v) => Ok(Int::from(v)),
43 Err(_) => {
44 if let Ok(f) = value.parse::<f64>() {
47 if f.is_infinite() {
48 Err(TypeError::NumberOutOfRange {
49 target: Type::Int,
50 fragment,
51 descriptor: None,
52 }
53 .into())
54 } else {
55 let truncated = f.trunc();
56 if let Ok(bigint) = format!("{:.0}", truncated).parse::<BigInt>() {
58 Ok(Int::from(bigint))
59 } else {
60 Err(TypeError::InvalidNumberFormat {
61 target: Type::Int,
62 fragment,
63 }
64 .into())
65 }
66 }
67 } else {
68 Err(TypeError::InvalidNumberFormat {
69 target: Type::Int,
70 fragment,
71 }
72 .into())
73 }
74 }
75 }
76}
77
78#[cfg(test)]
79pub mod tests {
80 use super::*;
81
82 #[test]
83 fn test_parse_int_valid_zero() {
84 assert_eq!(parse_int(Fragment::testing("0")).unwrap(), Int::zero());
85 }
86
87 #[test]
88 fn test_parse_int_valid_positive() {
89 let result = parse_int(Fragment::testing("12345")).unwrap();
90 assert_eq!(format!("{}", result), "12345");
91 }
92
93 #[test]
94 fn test_parse_int_valid_negative() {
95 let result = parse_int(Fragment::testing("-12345")).unwrap();
96 assert_eq!(format!("{}", result), "-12345");
97 }
98
99 #[test]
100 fn test_parse_int_large_positive() {
101 let large_num = "123456789012345678901234567890";
102 let result = parse_int(Fragment::testing(large_num)).unwrap();
103 assert_eq!(format!("{}", result), large_num);
104 }
105
106 #[test]
107 fn test_parse_int_large_negative() {
108 let large_num = "-123456789012345678901234567890";
109 let result = parse_int(Fragment::testing(large_num)).unwrap();
110 assert_eq!(format!("{}", result), large_num);
111 }
112
113 #[test]
114 fn test_parse_int_scientific_notation() {
115 let result = parse_int(Fragment::testing("1e5")).unwrap();
116 assert_eq!(format!("{}", result), "100000");
117 }
118
119 #[test]
120 fn test_parse_int_scientific_negative() {
121 let result = parse_int(Fragment::testing("-1.5e3")).unwrap();
122 assert_eq!(format!("{}", result), "-1500");
123 }
124
125 #[test]
126 fn test_parse_int_float_truncation() {
127 let result = parse_int(Fragment::testing("123.789")).unwrap();
128 assert_eq!(format!("{}", result), "123");
129 }
130
131 #[test]
132 fn test_parse_int_float_truncation_negative() {
133 let result = parse_int(Fragment::testing("-123.789")).unwrap();
134 assert_eq!(format!("{}", result), "-123");
135 }
136
137 #[test]
138 fn test_parse_int_with_underscores() {
139 let result = parse_int(Fragment::testing("1_234_567")).unwrap();
140 assert_eq!(format!("{}", result), "1234567");
141 }
142
143 #[test]
144 fn test_parse_int_with_leading_space() {
145 let result = parse_int(Fragment::testing(" 12345")).unwrap();
146 assert_eq!(format!("{}", result), "12345");
147 }
148
149 #[test]
150 fn test_parse_int_with_trailing_space() {
151 let result = parse_int(Fragment::testing("12345 ")).unwrap();
152 assert_eq!(format!("{}", result), "12345");
153 }
154
155 #[test]
156 fn test_parse_int_with_both_spaces() {
157 let result = parse_int(Fragment::testing(" -12345 ")).unwrap();
158 assert_eq!(format!("{}", result), "-12345");
159 }
160
161 #[test]
162 fn test_parse_int_invalid_empty() {
163 assert!(parse_int(Fragment::testing("")).is_err());
164 }
165
166 #[test]
167 fn test_parse_int_invalid_whitespace() {
168 assert!(parse_int(Fragment::testing(" ")).is_err());
169 }
170
171 #[test]
172 fn test_parse_int_invalid_text() {
173 assert!(parse_int(Fragment::testing("abc")).is_err());
174 }
175
176 #[test]
177 fn test_parse_int_invalid_multiple_dots() {
178 assert!(parse_int(Fragment::testing("1.2.3")).is_err());
179 }
180
181 #[test]
182 fn test_parse_int_infinity() {
183 assert!(parse_int(Fragment::testing("inf")).is_err());
184 }
185
186 #[test]
187 fn test_parse_int_negative_infinity() {
188 assert!(parse_int(Fragment::testing("-inf")).is_err());
189 }
190}