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