reifydb_type/value/number/
parse.rs

1// Copyright (c) reifydb.com 2025
2// This file is licensed under the MIT, see license.md file
3
4use std::{any::TypeId, borrow::Cow, num::IntErrorKind, str::FromStr};
5
6use crate::{
7	Error, Fragment, Type, err,
8	error::diagnostic::number::{invalid_number_format, nan_not_allowed, number_out_of_range},
9	return_error,
10	value::is::{IsFloat, IsInt, IsUint},
11};
12
13pub fn parse_primitive_int<'a, T>(fragment: Fragment) -> Result<T, Error>
14where
15	T: IsInt + 'static,
16{
17	if TypeId::of::<T>() == TypeId::of::<i8>() {
18		Ok(cast::<T, i8>(parse_i8(fragment)?))
19	} else if TypeId::of::<T>() == TypeId::of::<i16>() {
20		Ok(cast::<T, i16>(parse_i16(fragment)?))
21	} else if TypeId::of::<T>() == TypeId::of::<i32>() {
22		Ok(cast::<T, i32>(parse_i32(fragment)?))
23	} else if TypeId::of::<T>() == TypeId::of::<i64>() {
24		Ok(cast::<T, i64>(parse_i64(fragment)?))
25	} else if TypeId::of::<T>() == TypeId::of::<i128>() {
26		Ok(cast::<T, i128>(parse_i128(fragment)?))
27	} else {
28		unreachable!();
29	}
30}
31
32pub fn parse_primitive_uint<'a, T>(fragment: Fragment) -> Result<T, Error>
33where
34	T: IsUint + 'static,
35{
36	if TypeId::of::<T>() == TypeId::of::<u8>() {
37		Ok(cast::<T, u8>(parse_u8(fragment)?))
38	} else if TypeId::of::<T>() == TypeId::of::<u16>() {
39		Ok(cast::<T, u16>(parse_u16(fragment)?))
40	} else if TypeId::of::<T>() == TypeId::of::<u32>() {
41		Ok(cast::<T, u32>(parse_u32(fragment)?))
42	} else if TypeId::of::<T>() == TypeId::of::<u64>() {
43		Ok(cast::<T, u64>(parse_u64(fragment)?))
44	} else if TypeId::of::<T>() == TypeId::of::<u128>() {
45		Ok(cast::<T, u128>(parse_u128(fragment)?))
46	} else {
47		unreachable!();
48	}
49}
50
51pub fn parse_float<'a, T>(fragment: Fragment) -> Result<T, Error>
52where
53	T: IsFloat + 'static,
54{
55	// Fragment is already owned, no conversion needed
56	if fragment.text().to_lowercase().contains("nan") {
57		return_error!(nan_not_allowed());
58	}
59
60	if TypeId::of::<T>() == TypeId::of::<f32>() {
61		Ok(cast::<T, f32>(parse_f32(fragment.clone())?))
62	} else if TypeId::of::<T>() == TypeId::of::<f64>() {
63		Ok(cast::<T, f64>(parse_f64(fragment)?))
64	} else {
65		unreachable!();
66	}
67}
68
69fn cast_float_to_int<T: 'static>(f: f64) -> T {
70	if TypeId::of::<T>() == TypeId::of::<i8>() {
71		cast::<T, i8>(f as i8)
72	} else if TypeId::of::<T>() == TypeId::of::<i16>() {
73		cast::<T, i16>(f as i16)
74	} else if TypeId::of::<T>() == TypeId::of::<i32>() {
75		cast::<T, i32>(f as i32)
76	} else if TypeId::of::<T>() == TypeId::of::<i64>() {
77		cast::<T, i64>(f as i64)
78	} else if TypeId::of::<T>() == TypeId::of::<i128>() {
79		cast::<T, i128>(f as i128)
80	} else if TypeId::of::<T>() == TypeId::of::<u8>() {
81		cast::<T, u8>(f as u8)
82	} else if TypeId::of::<T>() == TypeId::of::<u16>() {
83		cast::<T, u16>(f as u16)
84	} else if TypeId::of::<T>() == TypeId::of::<u32>() {
85		cast::<T, u32>(f as u32)
86	} else if TypeId::of::<T>() == TypeId::of::<u64>() {
87		cast::<T, u64>(f as u64)
88	} else if TypeId::of::<T>() == TypeId::of::<u128>() {
89		cast::<T, u128>(f as u128)
90	} else {
91		unreachable!()
92	}
93}
94
95fn cast<T: 'static, U: 'static>(v: U) -> T {
96	// SAFETY: caller guarantees that T and U are the same type
97	assert_eq!(TypeId::of::<T>(), TypeId::of::<U>());
98	unsafe { std::mem::transmute_copy(&v) }
99}
100
101trait TypeInfo {
102	fn type_enum() -> Type;
103}
104
105impl TypeInfo for i8 {
106	fn type_enum() -> Type {
107		Type::Int1
108	}
109}
110impl TypeInfo for i16 {
111	fn type_enum() -> Type {
112		Type::Int2
113	}
114}
115impl TypeInfo for i32 {
116	fn type_enum() -> Type {
117		Type::Int4
118	}
119}
120impl TypeInfo for i64 {
121	fn type_enum() -> Type {
122		Type::Int8
123	}
124}
125impl TypeInfo for i128 {
126	fn type_enum() -> Type {
127		Type::Int16
128	}
129}
130impl TypeInfo for u8 {
131	fn type_enum() -> Type {
132		Type::Uint1
133	}
134}
135impl TypeInfo for u16 {
136	fn type_enum() -> Type {
137		Type::Uint2
138	}
139}
140impl TypeInfo for u32 {
141	fn type_enum() -> Type {
142		Type::Uint4
143	}
144}
145impl TypeInfo for u64 {
146	fn type_enum() -> Type {
147		Type::Uint8
148	}
149}
150impl TypeInfo for u128 {
151	fn type_enum() -> Type {
152		Type::Uint16
153	}
154}
155impl TypeInfo for f32 {
156	fn type_enum() -> Type {
157		Type::Float4
158	}
159}
160impl TypeInfo for f64 {
161	fn type_enum() -> Type {
162		Type::Float8
163	}
164}
165
166#[inline]
167fn parse_signed_generic<'a, T>(fragment: Fragment) -> Result<T, Error>
168where
169	T: FromStr<Err = std::num::ParseIntError> + TypeInfo + 'static,
170{
171	// Fragment is already owned, no conversion needed
172	let raw_value = fragment.text();
173
174	// Fast path: check if we need any string processing
175	let needs_trimming = raw_value.as_bytes().first().map_or(false, |&b| b.is_ascii_whitespace())
176		|| raw_value.as_bytes().last().map_or(false, |&b| b.is_ascii_whitespace());
177	let has_underscores = raw_value.as_bytes().contains(&b'_');
178
179	let value = match (needs_trimming, has_underscores) {
180		(false, false) => Cow::Borrowed(raw_value), // Fast path -
181		// no processing
182		// needed
183		(true, false) => Cow::Borrowed(raw_value.trim()),
184		(false, true) => Cow::Owned(raw_value.replace('_', "")),
185		(true, true) => Cow::Owned(raw_value.trim().replace('_', "")),
186	};
187
188	if value.is_empty() {
189		return_error!(invalid_number_format(fragment, T::type_enum()));
190	}
191
192	match value.parse::<T>() {
193		Ok(v) => Ok(v),
194		Err(err) => match err.kind() {
195			IntErrorKind::Empty => {
196				err!(invalid_number_format(fragment, T::type_enum()))
197			}
198			IntErrorKind::InvalidDigit => {
199				if let Ok(f) = value.parse::<f64>() {
200					let truncated = f.trunc();
201					let type_enum = T::type_enum();
202					let in_range = match type_enum {
203						Type::Int1 => {
204							truncated >= i8::MIN as f64 && truncated <= i8::MAX as f64
205						}
206						Type::Int2 => {
207							truncated >= i16::MIN as f64 && truncated <= i16::MAX as f64
208						}
209						Type::Int4 => {
210							truncated >= i32::MIN as f64 && truncated <= i32::MAX as f64
211						}
212						Type::Int8 => {
213							truncated >= i64::MIN as f64 && truncated <= i64::MAX as f64
214						}
215						Type::Int16 => {
216							truncated >= i128::MIN as f64 && truncated <= i128::MAX as f64
217						}
218						_ => false,
219					};
220					if in_range {
221						Ok(cast_float_to_int::<T>(truncated))
222					} else {
223						err!(number_out_of_range(fragment, type_enum, None))
224					}
225				} else {
226					err!(invalid_number_format(fragment, T::type_enum()))
227				}
228			}
229			IntErrorKind::PosOverflow => {
230				err!(number_out_of_range(fragment, T::type_enum(), None))
231			}
232			IntErrorKind::NegOverflow => {
233				err!(number_out_of_range(fragment, T::type_enum(), None))
234			}
235			IntErrorKind::Zero => {
236				err!(invalid_number_format(fragment, T::type_enum()))
237			}
238			&_ => unreachable!("{}", err),
239		},
240	}
241}
242
243#[inline]
244fn parse_unsigned_generic<'a, T>(fragment: Fragment) -> Result<T, Error>
245where
246	T: FromStr<Err = std::num::ParseIntError> + TypeInfo + 'static,
247{
248	// Fragment is already owned, no conversion needed
249	let raw_value = fragment.text();
250
251	// Fast path: check if we need any string processing
252	let needs_trimming = raw_value.as_bytes().first().map_or(false, |&b| b.is_ascii_whitespace())
253		|| raw_value.as_bytes().last().map_or(false, |&b| b.is_ascii_whitespace());
254	let has_underscores = raw_value.as_bytes().contains(&b'_');
255
256	let value = match (needs_trimming, has_underscores) {
257		(false, false) => Cow::Borrowed(raw_value), // Fast path -
258		// no processing
259		// needed
260		(true, false) => Cow::Borrowed(raw_value.trim()),
261		(false, true) => Cow::Owned(raw_value.replace('_', "")),
262		(true, true) => Cow::Owned(raw_value.trim().replace('_', "")),
263	};
264
265	if value.is_empty() {
266		return_error!(invalid_number_format(fragment, T::type_enum()));
267	}
268
269	match value.parse::<T>() {
270		Ok(v) => Ok(v),
271		Err(err) => {
272			match err.kind() {
273				IntErrorKind::Empty => {
274					err!(invalid_number_format(fragment, T::type_enum()))
275				}
276				IntErrorKind::InvalidDigit => {
277					if let Ok(f) = value.parse::<f64>() {
278						// For unsigned types, reject
279						// negative values
280						if f < 0.0 {
281							return_error!(number_out_of_range(
282								fragment,
283								T::type_enum(),
284								None
285							));
286						}
287						let truncated = f.trunc();
288						let type_enum = T::type_enum();
289						let in_range = match type_enum {
290							Type::Uint1 => truncated >= 0.0 && truncated <= u8::MAX as f64,
291							Type::Uint2 => truncated >= 0.0 && truncated <= u16::MAX as f64,
292							Type::Uint4 => truncated >= 0.0 && truncated <= u32::MAX as f64,
293							Type::Uint8 => truncated >= 0.0 && truncated <= u64::MAX as f64,
294							Type::Uint16 => {
295								truncated >= 0.0 && truncated <= u128::MAX as f64
296							}
297							_ => false,
298						};
299						if in_range {
300							Ok(cast_float_to_int::<T>(truncated))
301						} else {
302							err!(number_out_of_range(fragment, type_enum, None))
303						}
304					} else {
305						if value.contains("-") {
306							err!(number_out_of_range(fragment, T::type_enum(), None))
307						} else {
308							err!(invalid_number_format(fragment, T::type_enum()))
309						}
310					}
311				}
312				IntErrorKind::PosOverflow => {
313					err!(number_out_of_range(fragment, T::type_enum(), None))
314				}
315				IntErrorKind::NegOverflow => {
316					err!(number_out_of_range(fragment, T::type_enum(), None))
317				}
318				IntErrorKind::Zero => {
319					err!(invalid_number_format(fragment, T::type_enum()))
320				}
321				&_ => unreachable!("{}", err),
322			}
323		}
324	}
325}
326
327#[inline]
328fn parse_float_generic<'a, T>(fragment: Fragment) -> Result<T, Error>
329where
330	T: FromStr<Err = std::num::ParseFloatError> + Copy + TypeInfo + PartialEq + 'static,
331{
332	// Fragment is already owned, no conversion needed
333	let raw_value = fragment.text();
334
335	// Fast path: check if we need any string processing
336	let needs_trimming = raw_value.as_bytes().first().map_or(false, |&b| b.is_ascii_whitespace())
337		|| raw_value.as_bytes().last().map_or(false, |&b| b.is_ascii_whitespace());
338	let has_underscores = raw_value.as_bytes().contains(&b'_');
339
340	let value = match (needs_trimming, has_underscores) {
341		(false, false) => Cow::Borrowed(raw_value), // Fast path -
342		// no processing
343		// needed
344		(true, false) => Cow::Borrowed(raw_value.trim()),
345		(false, true) => Cow::Owned(raw_value.replace('_', "")),
346		(true, true) => Cow::Owned(raw_value.trim().replace('_', "")),
347	};
348
349	if value.is_empty() {
350		return_error!(invalid_number_format(fragment, T::type_enum()));
351	}
352
353	match value.parse::<T>() {
354		Ok(v) => {
355			if TypeId::of::<T>() == TypeId::of::<f32>() {
356				let v_f32 = cast::<f32, T>(v);
357				if v_f32 == f32::INFINITY || v_f32 == f32::NEG_INFINITY {
358					return_error!(number_out_of_range(fragment, T::type_enum(), None));
359				}
360			} else if TypeId::of::<T>() == TypeId::of::<f64>() {
361				let v_f64 = cast::<f64, T>(v);
362				if v_f64 == f64::INFINITY || v_f64 == f64::NEG_INFINITY {
363					return_error!(number_out_of_range(fragment, T::type_enum(), None));
364				}
365			}
366			Ok(v)
367		}
368		Err(_) => err!(invalid_number_format(fragment, T::type_enum())),
369	}
370}
371
372#[inline]
373fn parse_f32<'a>(fragment: Fragment) -> Result<f32, Error> {
374	parse_float_generic::<f32>(fragment)
375}
376
377#[inline]
378fn parse_f64<'a>(fragment: Fragment) -> Result<f64, Error> {
379	parse_float_generic::<f64>(fragment)
380}
381
382#[inline]
383fn parse_i8<'a>(fragment: Fragment) -> Result<i8, Error> {
384	parse_signed_generic::<i8>(fragment)
385}
386
387#[inline]
388fn parse_i16<'a>(fragment: Fragment) -> Result<i16, Error> {
389	parse_signed_generic::<i16>(fragment)
390}
391
392#[inline]
393fn parse_i32<'a>(fragment: Fragment) -> Result<i32, Error> {
394	parse_signed_generic::<i32>(fragment)
395}
396
397#[inline]
398fn parse_i64<'a>(fragment: Fragment) -> Result<i64, Error> {
399	parse_signed_generic::<i64>(fragment)
400}
401
402#[inline]
403fn parse_i128<'a>(fragment: Fragment) -> Result<i128, Error> {
404	parse_signed_generic::<i128>(fragment)
405}
406
407#[inline]
408fn parse_u8<'a>(fragment: Fragment) -> Result<u8, Error> {
409	parse_unsigned_generic::<u8>(fragment)
410}
411
412#[inline]
413fn parse_u16<'a>(fragment: Fragment) -> Result<u16, Error> {
414	parse_unsigned_generic::<u16>(fragment)
415}
416
417#[inline]
418fn parse_u32<'a>(fragment: Fragment) -> Result<u32, Error> {
419	parse_unsigned_generic::<u32>(fragment)
420}
421
422#[inline]
423fn parse_u64<'a>(fragment: Fragment) -> Result<u64, Error> {
424	parse_unsigned_generic::<u64>(fragment)
425}
426
427#[inline]
428fn parse_u128<'a>(fragment: Fragment) -> Result<u128, Error> {
429	parse_unsigned_generic::<u128>(fragment)
430}
431
432#[cfg(test)]
433#[allow(clippy::approx_constant)]
434mod tests {
435
436	mod i8 {
437		use crate::{Fragment, parse_primitive_int};
438
439		#[test]
440		fn test_valid_zero() {
441			assert_eq!(parse_primitive_int::<i8>(Fragment::testing("0")), Ok(0));
442		}
443
444		#[test]
445		fn test_valid_positive() {
446			assert_eq!(parse_primitive_int::<i8>(Fragment::testing("42")), Ok(42));
447		}
448
449		#[test]
450		fn test_valid_negative() {
451			assert_eq!(parse_primitive_int::<i8>(Fragment::testing("-42")), Ok(-42));
452		}
453
454		#[test]
455		fn test_valid_max() {
456			assert_eq!(parse_primitive_int::<i8>(Fragment::testing("127")), Ok(127));
457		}
458
459		#[test]
460		fn test_valid_min() {
461			assert_eq!(parse_primitive_int::<i8>(Fragment::testing("-128")), Ok(-128));
462		}
463
464		#[test]
465		fn test_overflow_positive() {
466			assert!(parse_primitive_int::<i8>(Fragment::testing("128")).is_err());
467		}
468
469		#[test]
470		fn test_overflow_negative() {
471			assert!(parse_primitive_int::<i8>(Fragment::testing("-129")).is_err());
472		}
473
474		#[test]
475		fn test_invalid_text() {
476			assert!(parse_primitive_int::<i8>(Fragment::testing("abc")).is_err());
477		}
478
479		#[test]
480		fn test_invalid_empty() {
481			assert!(parse_primitive_int::<i8>(Fragment::testing("")).is_err());
482		}
483
484		#[test]
485		fn test_invalid_whitespace() {
486			assert!(parse_primitive_int::<i8>(Fragment::testing("   ")).is_err());
487		}
488
489		#[test]
490		fn test_float_truncation_positive() {
491			assert_eq!(parse_primitive_int::<i8>(Fragment::testing("42.9")), Ok(42));
492		}
493
494		#[test]
495		fn test_float_truncation_negative() {
496			assert_eq!(parse_primitive_int::<i8>(Fragment::testing("-42.9")), Ok(-42));
497		}
498
499		#[test]
500		fn test_float_truncation_zero() {
501			assert_eq!(parse_primitive_int::<i8>(Fragment::testing("0.0")), Ok(0));
502		}
503
504		#[test]
505		fn test_float_truncation_negative_zero() {
506			assert_eq!(parse_primitive_int::<i8>(Fragment::testing("-0.0")), Ok(0));
507		}
508
509		#[test]
510		fn test_float_truncation_max() {
511			assert_eq!(parse_primitive_int::<i8>(Fragment::testing("127.9")), Ok(127));
512		}
513
514		#[test]
515		fn test_float_truncation_min() {
516			assert_eq!(parse_primitive_int::<i8>(Fragment::testing("-128.9")), Ok(-128));
517		}
518
519		#[test]
520		fn test_float_scientific_notation() {
521			assert_eq!(parse_primitive_int::<i8>(Fragment::testing("1e+2")), Ok(100));
522		}
523
524		#[test]
525		fn test_float_scientific_small() {
526			assert_eq!(parse_primitive_int::<i8>(Fragment::testing("1.23e-1")), Ok(0));
527		}
528
529		#[test]
530		fn test_float_overflow_positive() {
531			assert!(parse_primitive_int::<i8>(Fragment::testing("128.0")).is_err());
532		}
533
534		#[test]
535		fn test_float_overflow_negative() {
536			assert!(parse_primitive_int::<i8>(Fragment::testing("-129.0")).is_err());
537		}
538
539		#[test]
540		fn test_float_overflow_scientific() {
541			assert!(parse_primitive_int::<i8>(Fragment::testing("1e3")).is_err());
542		}
543
544		#[test]
545		fn test_invalid_float_format() {
546			assert!(parse_primitive_int::<i8>(Fragment::testing("1.2.3")).is_err());
547		}
548
549		#[test]
550		fn trimming_leading_space() {
551			assert_eq!(parse_primitive_int::<i8>(Fragment::testing(" 42")), Ok(42));
552		}
553
554		#[test]
555		fn trimming_trailing_space() {
556			assert_eq!(parse_primitive_int::<i8>(Fragment::testing("42 ")), Ok(42));
557		}
558
559		#[test]
560		fn trimming_both_spaces() {
561			assert_eq!(parse_primitive_int::<i8>(Fragment::testing(" 42 ")), Ok(42));
562		}
563
564		#[test]
565		fn trimming_negative_leading_space() {
566			assert_eq!(parse_primitive_int::<i8>(Fragment::testing(" -42")), Ok(-42));
567		}
568
569		#[test]
570		fn trimming_negative_trailing_space() {
571			assert_eq!(parse_primitive_int::<i8>(Fragment::testing("-42 ")), Ok(-42));
572		}
573
574		#[test]
575		fn trimming_negative_both_spaces() {
576			assert_eq!(parse_primitive_int::<i8>(Fragment::testing(" -42 ")), Ok(-42));
577		}
578	}
579
580	mod i16 {
581		use crate::{Fragment, parse_primitive_int};
582
583		#[test]
584		fn test_valid_zero() {
585			assert_eq!(parse_primitive_int::<i16>(Fragment::testing("0")), Ok(0));
586		}
587
588		#[test]
589		fn test_valid_positive() {
590			assert_eq!(parse_primitive_int::<i16>(Fragment::testing("1000")), Ok(1000));
591		}
592
593		#[test]
594		fn test_valid_negative() {
595			assert_eq!(parse_primitive_int::<i16>(Fragment::testing("-1000")), Ok(-1000));
596		}
597
598		#[test]
599		fn test_valid_max() {
600			assert_eq!(parse_primitive_int::<i16>(Fragment::testing("32767")), Ok(32767));
601		}
602
603		#[test]
604		fn test_valid_min() {
605			assert_eq!(parse_primitive_int::<i16>(Fragment::testing("-32768")), Ok(-32768));
606		}
607
608		#[test]
609		fn test_overflow_positive() {
610			assert!(parse_primitive_int::<i16>(Fragment::testing("32768")).is_err());
611		}
612
613		#[test]
614		fn test_overflow_negative() {
615			assert!(parse_primitive_int::<i16>(Fragment::testing("-32769")).is_err());
616		}
617
618		#[test]
619		fn test_invalid_text() {
620			assert!(parse_primitive_int::<i16>(Fragment::testing("hello")).is_err());
621		}
622
623		#[test]
624		fn test_invalid_empty() {
625			assert!(parse_primitive_int::<i16>(Fragment::testing("")).is_err());
626		}
627
628		#[test]
629		fn test_float_truncation_positive() {
630			assert_eq!(parse_primitive_int::<i16>(Fragment::testing("1000.7")), Ok(1000));
631		}
632
633		#[test]
634		fn test_float_truncation_negative() {
635			assert_eq!(parse_primitive_int::<i16>(Fragment::testing("-1000.7")), Ok(-1000));
636		}
637
638		#[test]
639		fn test_float_truncation_max() {
640			assert_eq!(parse_primitive_int::<i16>(Fragment::testing("32767.9")), Ok(32767));
641		}
642
643		#[test]
644		fn test_float_truncation_min() {
645			assert_eq!(parse_primitive_int::<i16>(Fragment::testing("-32768.9")), Ok(-32768));
646		}
647
648		#[test]
649		fn test_float_scientific_notation() {
650			assert_eq!(parse_primitive_int::<i16>(Fragment::testing("1.5e3")), Ok(1500));
651		}
652
653		#[test]
654		fn test_float_overflow_positive() {
655			assert!(parse_primitive_int::<i16>(Fragment::testing("32768.0")).is_err());
656		}
657
658		#[test]
659		fn test_float_overflow_negative() {
660			assert!(parse_primitive_int::<i16>(Fragment::testing("-32769.0")).is_err());
661		}
662
663		#[test]
664		fn test_float_overflow_scientific() {
665			assert!(parse_primitive_int::<i16>(Fragment::testing("1e5")).is_err());
666		}
667
668		#[test]
669		fn trimming_leading_space() {
670			assert_eq!(parse_primitive_int::<i16>(Fragment::testing(" 1000")), Ok(1000));
671		}
672
673		#[test]
674		fn trimming_trailing_space() {
675			assert_eq!(parse_primitive_int::<i16>(Fragment::testing("1000 ")), Ok(1000));
676		}
677
678		#[test]
679		fn trimming_both_spaces() {
680			assert_eq!(parse_primitive_int::<i16>(Fragment::testing(" 1000 ")), Ok(1000));
681		}
682
683		#[test]
684		fn trimming_negative_leading_space() {
685			assert_eq!(parse_primitive_int::<i16>(Fragment::testing(" -1000")), Ok(-1000));
686		}
687
688		#[test]
689		fn trimming_negative_trailing_space() {
690			assert_eq!(parse_primitive_int::<i16>(Fragment::testing("-1000 ")), Ok(-1000));
691		}
692
693		#[test]
694		fn trimming_negative_both_spaces() {
695			assert_eq!(parse_primitive_int::<i16>(Fragment::testing(" -1000 ")), Ok(-1000));
696		}
697	}
698
699	mod i32 {
700		use crate::{Fragment, parse_primitive_int};
701
702		#[test]
703		fn test_valid_zero() {
704			assert_eq!(parse_primitive_int::<i32>(Fragment::testing("0")), Ok(0));
705		}
706
707		#[test]
708		fn test_valid_positive() {
709			assert_eq!(parse_primitive_int::<i32>(Fragment::testing("1000000")), Ok(1000000));
710		}
711
712		#[test]
713		fn test_valid_negative() {
714			assert_eq!(parse_primitive_int::<i32>(Fragment::testing("-1000000")), Ok(-1000000));
715		}
716
717		#[test]
718		fn test_valid_max() {
719			assert_eq!(parse_primitive_int::<i32>(Fragment::testing("2147483647")), Ok(2147483647));
720		}
721
722		#[test]
723		fn test_valid_min() {
724			assert_eq!(parse_primitive_int::<i32>(Fragment::testing("-2147483648")), Ok(-2147483648));
725		}
726
727		#[test]
728		fn test_overflow_positive() {
729			assert!(parse_primitive_int::<i32>(Fragment::testing("2147483648")).is_err());
730		}
731
732		#[test]
733		fn test_overflow_negative() {
734			assert!(parse_primitive_int::<i32>(Fragment::testing("-2147483649")).is_err());
735		}
736
737		#[test]
738		fn test_invalid_text() {
739			assert!(parse_primitive_int::<i32>(Fragment::testing("not_a_number")).is_err());
740		}
741
742		#[test]
743		fn test_invalid_empty() {
744			assert!(parse_primitive_int::<i32>(Fragment::testing("")).is_err());
745		}
746
747		#[test]
748		fn test_float_truncation_positive() {
749			assert_eq!(parse_primitive_int::<i32>(Fragment::testing("3.14")), Ok(3));
750		}
751
752		#[test]
753		fn test_float_truncation_negative() {
754			assert_eq!(parse_primitive_int::<i32>(Fragment::testing("-3.14")), Ok(-3));
755		}
756
757		#[test]
758		fn test_float_truncation_zero() {
759			assert_eq!(parse_primitive_int::<i32>(Fragment::testing("0.0")), Ok(0));
760		}
761
762		#[test]
763		fn test_float_truncation_negative_zero() {
764			assert_eq!(parse_primitive_int::<i32>(Fragment::testing("-0.0")), Ok(0));
765		}
766
767		#[test]
768		fn test_float_truncation_large() {
769			assert_eq!(parse_primitive_int::<i32>(Fragment::testing("42.999")), Ok(42));
770		}
771
772		#[test]
773		fn test_float_scientific_notation() {
774			assert_eq!(parse_primitive_int::<i32>(Fragment::testing("1e+2")), Ok(100));
775		}
776
777		#[test]
778		fn test_float_scientific_decimal() {
779			assert_eq!(parse_primitive_int::<i32>(Fragment::testing("2.5e3")), Ok(2500));
780		}
781
782		#[test]
783		fn test_float_scientific_negative() {
784			assert_eq!(parse_primitive_int::<i32>(Fragment::testing("-1.5e2")), Ok(-150));
785		}
786
787		#[test]
788		fn test_float_scientific_small() {
789			assert_eq!(parse_primitive_int::<i32>(Fragment::testing("1.23e-1")), Ok(0));
790		}
791
792		#[test]
793		fn test_float_scientific_very_small() {
794			assert_eq!(parse_primitive_int::<i32>(Fragment::testing("9.9e-1")), Ok(0));
795		}
796
797		#[test]
798		fn test_float_overflow_positive() {
799			assert!(parse_primitive_int::<i32>(Fragment::testing("2147483648.0")).is_err());
800		}
801
802		#[test]
803		fn test_float_overflow_negative() {
804			assert!(parse_primitive_int::<i32>(Fragment::testing("-2147483649.0")).is_err());
805		}
806
807		#[test]
808		fn test_float_overflow_scientific() {
809			assert!(parse_primitive_int::<i32>(Fragment::testing("1e10")).is_err());
810		}
811
812		#[test]
813		fn test_invalid_float_format() {
814			assert!(parse_primitive_int::<i32>(Fragment::testing("1.2.3")).is_err());
815		}
816
817		#[test]
818		fn trimming_leading_space() {
819			assert_eq!(parse_primitive_int::<i32>(Fragment::testing(" 123")), Ok(123));
820		}
821
822		#[test]
823		fn trimming_trailing_space() {
824			assert_eq!(parse_primitive_int::<i32>(Fragment::testing("123 ")), Ok(123));
825		}
826
827		#[test]
828		fn trimming_both_spaces() {
829			assert_eq!(parse_primitive_int::<i32>(Fragment::testing(" 123 ")), Ok(123));
830		}
831
832		#[test]
833		fn trimming_negative_leading_space() {
834			assert_eq!(parse_primitive_int::<i32>(Fragment::testing(" -456")), Ok(-456));
835		}
836
837		#[test]
838		fn trimming_negative_trailing_space() {
839			assert_eq!(parse_primitive_int::<i32>(Fragment::testing("-456 ")), Ok(-456));
840		}
841
842		#[test]
843		fn trimming_negative_both_spaces() {
844			assert_eq!(parse_primitive_int::<i32>(Fragment::testing(" -456 ")), Ok(-456));
845		}
846	}
847
848	mod i64 {
849		use crate::{Fragment, parse_primitive_int};
850
851		#[test]
852		fn test_valid_zero() {
853			assert_eq!(parse_primitive_int::<i64>(Fragment::testing("0")), Ok(0));
854		}
855
856		#[test]
857		fn test_valid_positive() {
858			assert_eq!(parse_primitive_int::<i64>(Fragment::testing("1000000000")), Ok(1000000000));
859		}
860
861		#[test]
862		fn test_valid_negative() {
863			assert_eq!(parse_primitive_int::<i64>(Fragment::testing("-1000000000")), Ok(-1000000000));
864		}
865
866		#[test]
867		fn test_valid_max() {
868			assert_eq!(parse_primitive_int::<i64>(Fragment::testing("9223372036854775807")), Ok(i64::MAX));
869		}
870
871		#[test]
872		fn test_valid_min() {
873			assert_eq!(parse_primitive_int::<i64>(Fragment::testing("-9223372036854775808")), Ok(i64::MIN));
874		}
875
876		#[test]
877		fn test_overflow_positive() {
878			assert!(parse_primitive_int::<i64>(Fragment::testing("9223372036854775808")).is_err());
879		}
880
881		#[test]
882		fn test_overflow_negative() {
883			assert!(parse_primitive_int::<i64>(Fragment::testing("-9223372036854775809")).is_err());
884		}
885
886		#[test]
887		fn test_invalid_text() {
888			assert!(parse_primitive_int::<i64>(Fragment::testing("invalid")).is_err());
889		}
890
891		#[test]
892		fn test_invalid_empty() {
893			assert!(parse_primitive_int::<i64>(Fragment::testing("")).is_err());
894		}
895
896		#[test]
897		fn test_float_truncation_positive() {
898			assert_eq!(parse_primitive_int::<i64>(Fragment::testing("12345.67")), Ok(12345));
899		}
900
901		#[test]
902		fn test_float_truncation_negative() {
903			assert_eq!(parse_primitive_int::<i64>(Fragment::testing("-12345.67")), Ok(-12345));
904		}
905
906		#[test]
907		fn test_float_scientific_notation() {
908			assert_eq!(parse_primitive_int::<i64>(Fragment::testing("1e10")), Ok(10000000000));
909		}
910
911		#[test]
912		fn test_float_scientific_large() {
913			assert_eq!(parse_primitive_int::<i64>(Fragment::testing("9.223e18")), Ok(9223000000000000000));
914		}
915
916		#[test]
917		fn test_float_overflow_positive() {
918			assert!(parse_primitive_int::<i64>(Fragment::testing("1e19")).is_err());
919		}
920
921		#[test]
922		fn test_float_overflow_negative() {
923			assert!(parse_primitive_int::<i64>(Fragment::testing("-1e19")).is_err());
924		}
925
926		#[test]
927		fn trimming_leading_space() {
928			assert_eq!(parse_primitive_int::<i64>(Fragment::testing(" 1000000000")), Ok(1000000000));
929		}
930
931		#[test]
932		fn trimming_trailing_space() {
933			assert_eq!(parse_primitive_int::<i64>(Fragment::testing("1000000000 ")), Ok(1000000000));
934		}
935
936		#[test]
937		fn trimming_both_spaces() {
938			assert_eq!(parse_primitive_int::<i64>(Fragment::testing(" 1000000000 ")), Ok(1000000000));
939		}
940
941		#[test]
942		fn trimming_negative_leading_space() {
943			assert_eq!(parse_primitive_int::<i64>(Fragment::testing(" -1000000000")), Ok(-1000000000));
944		}
945
946		#[test]
947		fn trimming_negative_trailing_space() {
948			assert_eq!(parse_primitive_int::<i64>(Fragment::testing("-1000000000 ")), Ok(-1000000000));
949		}
950
951		#[test]
952		fn trimming_negative_both_spaces() {
953			assert_eq!(parse_primitive_int::<i64>(Fragment::testing(" -1000000000 ")), Ok(-1000000000));
954		}
955	}
956
957	mod i128 {
958		use crate::{Fragment, parse_primitive_int};
959
960		#[test]
961		fn test_valid_zero() {
962			assert_eq!(parse_primitive_int::<i128>(Fragment::testing("0")), Ok(0));
963		}
964
965		#[test]
966		fn test_valid_positive() {
967			assert_eq!(
968				parse_primitive_int::<i128>(Fragment::testing("12345678901234567890")),
969				Ok(12345678901234567890)
970			);
971		}
972
973		#[test]
974		fn test_valid_negative() {
975			assert_eq!(
976				parse_primitive_int::<i128>(Fragment::testing("-12345678901234567890")),
977				Ok(-12345678901234567890)
978			);
979		}
980
981		#[test]
982		fn test_valid_max() {
983			assert_eq!(
984				parse_primitive_int::<i128>(Fragment::testing(&i128::MAX.to_string())),
985				Ok(i128::MAX)
986			);
987		}
988
989		#[test]
990		fn test_valid_min() {
991			assert_eq!(
992				parse_primitive_int::<i128>(Fragment::testing(&i128::MIN.to_string())),
993				Ok(i128::MIN)
994			);
995		}
996
997		#[test]
998		fn test_overflow_positive() {
999			assert!(parse_primitive_int::<i128>(Fragment::testing(
1000				"170141183460469231731687303715884105728"
1001			))
1002			.is_err());
1003		}
1004
1005		#[test]
1006		fn test_overflow_negative() {
1007			assert!(parse_primitive_int::<i128>(Fragment::testing(
1008				"-170141183460469231731687303715884105729"
1009			))
1010			.is_err());
1011		}
1012
1013		#[test]
1014		fn test_invalid_text() {
1015			assert!(parse_primitive_int::<i128>(Fragment::testing("abc")).is_err());
1016		}
1017
1018		#[test]
1019		fn test_invalid_empty() {
1020			assert!(parse_primitive_int::<i128>(Fragment::testing("")).is_err());
1021		}
1022
1023		#[test]
1024		fn test_float_truncation_positive() {
1025			assert_eq!(parse_primitive_int::<i128>(Fragment::testing("123456789.123")), Ok(123456789));
1026		}
1027
1028		#[test]
1029		fn test_float_truncation_negative() {
1030			assert_eq!(parse_primitive_int::<i128>(Fragment::testing("-123456789.123")), Ok(-123456789));
1031		}
1032
1033		#[test]
1034		fn test_float_scientific_notation() {
1035			assert_eq!(parse_primitive_int::<i128>(Fragment::testing("1e20")), Ok(100000000000000000000));
1036		}
1037
1038		#[test]
1039		fn test_float_overflow_positive() {
1040			assert!(parse_primitive_int::<i128>(Fragment::testing("1e40")).is_err());
1041		}
1042
1043		#[test]
1044		fn test_float_overflow_negative() {
1045			assert!(parse_primitive_int::<i128>(Fragment::testing("-1e40")).is_err());
1046		}
1047
1048		#[test]
1049		fn trimming_leading_space() {
1050			assert_eq!(
1051				parse_primitive_int::<i128>(Fragment::testing(" 12345678901234567890")),
1052				Ok(12345678901234567890)
1053			);
1054		}
1055
1056		#[test]
1057		fn trimming_trailing_space() {
1058			assert_eq!(
1059				parse_primitive_int::<i128>(Fragment::testing("12345678901234567890 ")),
1060				Ok(12345678901234567890)
1061			);
1062		}
1063
1064		#[test]
1065		fn trimming_both_spaces() {
1066			assert_eq!(
1067				parse_primitive_int::<i128>(Fragment::testing(" 12345678901234567890 ")),
1068				Ok(12345678901234567890)
1069			);
1070		}
1071
1072		#[test]
1073		fn trimming_negative_leading_space() {
1074			assert_eq!(
1075				parse_primitive_int::<i128>(Fragment::testing(" -12345678901234567890")),
1076				Ok(-12345678901234567890)
1077			);
1078		}
1079
1080		#[test]
1081		fn trimming_negative_trailing_space() {
1082			assert_eq!(
1083				parse_primitive_int::<i128>(Fragment::testing("-12345678901234567890 ")),
1084				Ok(-12345678901234567890)
1085			);
1086		}
1087
1088		#[test]
1089		fn trimming_negative_both_spaces() {
1090			assert_eq!(
1091				parse_primitive_int::<i128>(Fragment::testing(" -12345678901234567890 ")),
1092				Ok(-12345678901234567890)
1093			);
1094		}
1095	}
1096
1097	mod u8 {
1098		use crate::{Fragment, parse_primitive_uint};
1099
1100		#[test]
1101		fn test_valid_zero() {
1102			assert_eq!(parse_primitive_uint::<u8>(Fragment::testing("0")), Ok(0));
1103		}
1104
1105		#[test]
1106		fn test_valid_positive() {
1107			assert_eq!(parse_primitive_uint::<u8>(Fragment::testing("128")), Ok(128));
1108		}
1109
1110		#[test]
1111		fn test_valid_max() {
1112			assert_eq!(parse_primitive_uint::<u8>(Fragment::testing("255")), Ok(255));
1113		}
1114
1115		#[test]
1116		fn test_overflow_positive() {
1117			assert!(parse_primitive_uint::<u8>(Fragment::testing("256")).is_err());
1118		}
1119
1120		#[test]
1121		fn test_overflow_negative() {
1122			assert!(parse_primitive_uint::<u8>(Fragment::testing("-1")).is_err());
1123		}
1124
1125		#[test]
1126		fn test_invalid_text() {
1127			assert!(parse_primitive_uint::<u8>(Fragment::testing("abc")).is_err());
1128		}
1129
1130		#[test]
1131		fn test_invalid_empty() {
1132			assert!(parse_primitive_uint::<u8>(Fragment::testing("")).is_err());
1133		}
1134
1135		#[test]
1136		fn test_float_truncation_positive() {
1137			assert_eq!(parse_primitive_uint::<u8>(Fragment::testing("128.9")), Ok(128));
1138		}
1139
1140		#[test]
1141		fn test_float_truncation_zero() {
1142			assert_eq!(parse_primitive_uint::<u8>(Fragment::testing("0.0")), Ok(0));
1143		}
1144
1145		#[test]
1146		fn test_float_truncation_max() {
1147			assert_eq!(parse_primitive_uint::<u8>(Fragment::testing("255.9")), Ok(255));
1148		}
1149
1150		#[test]
1151		fn test_float_scientific_notation() {
1152			assert_eq!(parse_primitive_uint::<u8>(Fragment::testing("2e2")), Ok(200));
1153		}
1154
1155		#[test]
1156		fn test_float_scientific_small() {
1157			assert_eq!(parse_primitive_uint::<u8>(Fragment::testing("1.23e-1")), Ok(0));
1158		}
1159
1160		#[test]
1161		fn test_float_negative() {
1162			assert!(parse_primitive_uint::<u8>(Fragment::testing("-1.5")).is_err());
1163		}
1164
1165		#[test]
1166		fn test_float_negative_zero() {
1167			assert!(parse_primitive_uint::<u8>(Fragment::testing("-0.1")).is_err());
1168		}
1169
1170		#[test]
1171		fn test_float_overflow_positive() {
1172			assert!(parse_primitive_uint::<u8>(Fragment::testing("256.0")).is_err());
1173		}
1174
1175		#[test]
1176		fn test_float_overflow_scientific() {
1177			assert!(parse_primitive_uint::<u8>(Fragment::testing("1e3")).is_err());
1178		}
1179
1180		#[test]
1181		fn test_invalid_float_format() {
1182			assert!(parse_primitive_uint::<u8>(Fragment::testing("1.2.3")).is_err());
1183		}
1184
1185		#[test]
1186		fn trimming_leading_space() {
1187			assert_eq!(parse_primitive_uint::<u8>(Fragment::testing(" 128")), Ok(128));
1188		}
1189
1190		#[test]
1191		fn trimming_trailing_space() {
1192			assert_eq!(parse_primitive_uint::<u8>(Fragment::testing("128 ")), Ok(128));
1193		}
1194
1195		#[test]
1196		fn trimming_both_spaces() {
1197			assert_eq!(parse_primitive_uint::<u8>(Fragment::testing(" 128 ")), Ok(128));
1198		}
1199	}
1200
1201	mod u16 {
1202		use crate::{Fragment, parse_primitive_uint};
1203
1204		#[test]
1205		fn test_valid_zero() {
1206			assert_eq!(parse_primitive_uint::<u16>(Fragment::testing("0")), Ok(0));
1207		}
1208
1209		#[test]
1210		fn test_valid_positive() {
1211			assert_eq!(parse_primitive_uint::<u16>(Fragment::testing("32768")), Ok(32768));
1212		}
1213
1214		#[test]
1215		fn test_valid_max() {
1216			assert_eq!(parse_primitive_uint::<u16>(Fragment::testing("65535")), Ok(65535));
1217		}
1218
1219		#[test]
1220		fn test_overflow_positive() {
1221			assert!(parse_primitive_uint::<u16>(Fragment::testing("65536")).is_err());
1222		}
1223
1224		#[test]
1225		fn test_overflow_negative() {
1226			assert!(parse_primitive_uint::<u16>(Fragment::testing("-1")).is_err());
1227		}
1228
1229		#[test]
1230		fn test_invalid_text() {
1231			assert!(parse_primitive_uint::<u16>(Fragment::testing("invalid")).is_err());
1232		}
1233
1234		#[test]
1235		fn test_invalid_empty() {
1236			assert!(parse_primitive_uint::<u16>(Fragment::testing("")).is_err());
1237		}
1238
1239		#[test]
1240		fn test_float_truncation_positive() {
1241			assert_eq!(parse_primitive_uint::<u16>(Fragment::testing("32768.7")), Ok(32768));
1242		}
1243
1244		#[test]
1245		fn test_float_truncation_max() {
1246			assert_eq!(parse_primitive_uint::<u16>(Fragment::testing("65535.9")), Ok(65535));
1247		}
1248
1249		#[test]
1250		fn test_float_scientific_notation() {
1251			assert_eq!(parse_primitive_uint::<u16>(Fragment::testing("6.5e4")), Ok(65000));
1252		}
1253
1254		#[test]
1255		fn test_float_negative() {
1256			assert!(parse_primitive_uint::<u16>(Fragment::testing("-100.0")).is_err());
1257		}
1258
1259		#[test]
1260		fn test_float_overflow_positive() {
1261			assert!(parse_primitive_uint::<u16>(Fragment::testing("65536.0")).is_err());
1262		}
1263
1264		#[test]
1265		fn test_float_overflow_scientific() {
1266			assert!(parse_primitive_uint::<u16>(Fragment::testing("1e5")).is_err());
1267		}
1268
1269		#[test]
1270		fn trimming_leading_space() {
1271			assert_eq!(parse_primitive_uint::<u16>(Fragment::testing(" 32768")), Ok(32768));
1272		}
1273
1274		#[test]
1275		fn trimming_trailing_space() {
1276			assert_eq!(parse_primitive_uint::<u16>(Fragment::testing("32768 ")), Ok(32768));
1277		}
1278
1279		#[test]
1280		fn trimming_both_spaces() {
1281			assert_eq!(parse_primitive_uint::<u16>(Fragment::testing(" 32768 ")), Ok(32768));
1282		}
1283	}
1284
1285	mod u32 {
1286		use crate::{Fragment, parse_primitive_uint};
1287
1288		#[test]
1289		fn test_valid_zero() {
1290			assert_eq!(parse_primitive_uint::<u32>(Fragment::testing("0")), Ok(0));
1291		}
1292
1293		#[test]
1294		fn test_valid_positive() {
1295			assert_eq!(parse_primitive_uint::<u32>(Fragment::testing("1000000")), Ok(1000000));
1296		}
1297
1298		#[test]
1299		fn test_valid_max() {
1300			assert_eq!(parse_primitive_uint::<u32>(Fragment::testing("4294967295")), Ok(4294967295));
1301		}
1302
1303		#[test]
1304		fn test_overflow_positive() {
1305			assert!(parse_primitive_uint::<u32>(Fragment::testing("4294967296")).is_err());
1306		}
1307
1308		#[test]
1309		fn test_overflow_negative() {
1310			assert!(parse_primitive_uint::<u32>(Fragment::testing("-1")).is_err());
1311		}
1312
1313		#[test]
1314		fn test_invalid_text() {
1315			assert!(parse_primitive_uint::<u32>(Fragment::testing("text")).is_err());
1316		}
1317
1318		#[test]
1319		fn test_invalid_empty() {
1320			assert!(parse_primitive_uint::<u32>(Fragment::testing("")).is_err());
1321		}
1322
1323		#[test]
1324		fn test_float_truncation_positive() {
1325			assert_eq!(parse_primitive_uint::<u32>(Fragment::testing("3.14")), Ok(3));
1326		}
1327
1328		#[test]
1329		fn test_float_truncation_zero() {
1330			assert_eq!(parse_primitive_uint::<u32>(Fragment::testing("0.0")), Ok(0));
1331		}
1332
1333		#[test]
1334		fn test_float_truncation_large() {
1335			assert_eq!(parse_primitive_uint::<u32>(Fragment::testing("42.999")), Ok(42));
1336		}
1337
1338		#[test]
1339		fn test_float_scientific_notation() {
1340			assert_eq!(parse_primitive_uint::<u32>(Fragment::testing("1e+2")), Ok(100));
1341		}
1342
1343		#[test]
1344		fn test_float_scientific_decimal() {
1345			assert_eq!(parse_primitive_uint::<u32>(Fragment::testing("2.5e3")), Ok(2500));
1346		}
1347
1348		#[test]
1349		fn test_float_scientific_small() {
1350			assert_eq!(parse_primitive_uint::<u32>(Fragment::testing("1.23e-1")), Ok(0));
1351		}
1352
1353		#[test]
1354		fn test_float_negative() {
1355			assert!(parse_primitive_uint::<u32>(Fragment::testing("-3.14")).is_err());
1356		}
1357
1358		#[test]
1359		fn test_float_negative_small() {
1360			assert!(parse_primitive_uint::<u32>(Fragment::testing("-0.1")).is_err());
1361		}
1362
1363		#[test]
1364		fn test_float_negative_scientific() {
1365			assert!(parse_primitive_uint::<u32>(Fragment::testing("-1e2")).is_err());
1366		}
1367
1368		#[test]
1369		fn test_float_overflow_positive() {
1370			assert!(parse_primitive_uint::<u32>(Fragment::testing("4294967296.0")).is_err());
1371		}
1372
1373		#[test]
1374		fn test_float_overflow_scientific() {
1375			assert!(parse_primitive_uint::<u32>(Fragment::testing("1e10")).is_err());
1376		}
1377
1378		#[test]
1379		fn test_invalid_float_format() {
1380			assert!(parse_primitive_uint::<u32>(Fragment::testing("1.2.3")).is_err());
1381		}
1382
1383		#[test]
1384		fn trimming_leading_space() {
1385			assert_eq!(parse_primitive_uint::<u32>(Fragment::testing(" 1000000")), Ok(1000000));
1386		}
1387
1388		#[test]
1389		fn trimming_trailing_space() {
1390			assert_eq!(parse_primitive_uint::<u32>(Fragment::testing("1000000 ")), Ok(1000000));
1391		}
1392
1393		#[test]
1394		fn trimming_both_spaces() {
1395			assert_eq!(parse_primitive_uint::<u32>(Fragment::testing(" 1000000 ")), Ok(1000000));
1396		}
1397	}
1398
1399	mod u64 {
1400		use crate::{Fragment, parse_primitive_uint};
1401
1402		#[test]
1403		fn test_valid_zero() {
1404			assert_eq!(parse_primitive_uint::<u64>(Fragment::testing("0")), Ok(0));
1405		}
1406
1407		#[test]
1408		fn test_valid_positive() {
1409			assert_eq!(parse_primitive_uint::<u64>(Fragment::testing("1000000000000")), Ok(1000000000000));
1410		}
1411
1412		#[test]
1413		fn test_valid_max() {
1414			assert_eq!(
1415				parse_primitive_uint::<u64>(Fragment::testing("18446744073709551615")),
1416				Ok(u64::MAX)
1417			);
1418		}
1419
1420		#[test]
1421		fn test_overflow_positive() {
1422			assert!(parse_primitive_uint::<u64>(Fragment::testing("18446744073709551616")).is_err());
1423		}
1424
1425		#[test]
1426		fn test_overflow_negative() {
1427			assert!(parse_primitive_uint::<u64>(Fragment::testing("-1")).is_err());
1428		}
1429
1430		#[test]
1431		fn test_invalid_text() {
1432			assert!(parse_primitive_uint::<u64>(Fragment::testing("not_valid")).is_err());
1433		}
1434
1435		#[test]
1436		fn test_invalid_empty() {
1437			assert!(parse_primitive_uint::<u64>(Fragment::testing("")).is_err());
1438		}
1439
1440		#[test]
1441		fn test_float_truncation_positive() {
1442			assert_eq!(parse_primitive_uint::<u64>(Fragment::testing("123456789.123")), Ok(123456789));
1443		}
1444
1445		#[test]
1446		fn test_float_scientific_notation() {
1447			assert_eq!(parse_primitive_uint::<u64>(Fragment::testing("1e12")), Ok(1000000000000));
1448		}
1449
1450		#[test]
1451		fn test_float_negative() {
1452			assert!(parse_primitive_uint::<u64>(Fragment::testing("-1.0")).is_err());
1453		}
1454
1455		#[test]
1456		fn test_float_overflow_positive() {
1457			assert!(parse_primitive_uint::<u64>(Fragment::testing("2e19")).is_err());
1458		}
1459
1460		#[test]
1461		fn test_float_overflow_scientific() {
1462			assert!(parse_primitive_uint::<u64>(Fragment::testing("1e20")).is_err());
1463		}
1464
1465		#[test]
1466		fn trimming_leading_space() {
1467			assert_eq!(parse_primitive_uint::<u64>(Fragment::testing(" 1000000000000")), Ok(1000000000000));
1468		}
1469
1470		#[test]
1471		fn trimming_trailing_space() {
1472			assert_eq!(parse_primitive_uint::<u64>(Fragment::testing("1000000000000 ")), Ok(1000000000000));
1473		}
1474
1475		#[test]
1476		fn trimming_both_spaces() {
1477			assert_eq!(
1478				parse_primitive_uint::<u64>(Fragment::testing(" 1000000000000 ")),
1479				Ok(1000000000000)
1480			);
1481		}
1482	}
1483
1484	mod u128 {
1485		use crate::{Fragment, parse_primitive_uint};
1486
1487		#[test]
1488		fn test_valid_zero() {
1489			assert_eq!(parse_primitive_uint::<u128>(Fragment::testing("0")), Ok(0));
1490		}
1491
1492		#[test]
1493		fn test_valid_positive() {
1494			assert_eq!(
1495				parse_primitive_uint::<u128>(Fragment::testing("12345678901234567890")),
1496				Ok(12345678901234567890)
1497			);
1498		}
1499
1500		#[test]
1501		fn test_valid_max() {
1502			assert_eq!(
1503				parse_primitive_uint::<u128>(Fragment::testing(&u128::MAX.to_string())),
1504				Ok(u128::MAX)
1505			);
1506		}
1507
1508		#[test]
1509		fn test_overflow_positive() {
1510			assert!(parse_primitive_uint::<u128>(Fragment::testing(
1511				"340282366920938463463374607431768211456"
1512			))
1513			.is_err());
1514		}
1515
1516		#[test]
1517		fn test_overflow_negative() {
1518			assert!(parse_primitive_uint::<u128>(Fragment::testing("-1")).is_err());
1519		}
1520
1521		#[test]
1522		fn test_invalid_text() {
1523			assert!(parse_primitive_uint::<u128>(Fragment::testing("abc")).is_err());
1524		}
1525
1526		#[test]
1527		fn test_invalid_empty() {
1528			assert!(parse_primitive_uint::<u128>(Fragment::testing("")).is_err());
1529		}
1530
1531		#[test]
1532		fn test_float_truncation_positive() {
1533			assert_eq!(parse_primitive_uint::<u128>(Fragment::testing("123456789.999")), Ok(123456789));
1534		}
1535
1536		#[test]
1537		fn test_float_scientific_notation() {
1538			assert_eq!(parse_primitive_uint::<u128>(Fragment::testing("1e20")), Ok(100000000000000000000));
1539		}
1540
1541		#[test]
1542		fn test_float_negative() {
1543			assert!(parse_primitive_uint::<u128>(Fragment::testing("-1.0")).is_err());
1544		}
1545
1546		#[test]
1547		fn test_float_overflow_positive() {
1548			assert!(parse_primitive_uint::<u128>(Fragment::testing("1e40")).is_err());
1549		}
1550
1551		#[test]
1552		fn test_float_overflow_scientific() {
1553			assert!(parse_primitive_uint::<u128>(Fragment::testing("1e50")).is_err());
1554		}
1555
1556		#[test]
1557		fn trimming_leading_space() {
1558			assert_eq!(
1559				parse_primitive_uint::<u128>(Fragment::testing(" 12345678901234567890")),
1560				Ok(12345678901234567890)
1561			);
1562		}
1563
1564		#[test]
1565		fn trimming_trailing_space() {
1566			assert_eq!(
1567				parse_primitive_uint::<u128>(Fragment::testing("12345678901234567890 ")),
1568				Ok(12345678901234567890)
1569			);
1570		}
1571
1572		#[test]
1573		fn trimming_both_spaces() {
1574			assert_eq!(
1575				parse_primitive_uint::<u128>(Fragment::testing(" 12345678901234567890 ")),
1576				Ok(12345678901234567890)
1577			);
1578		}
1579	}
1580
1581	mod f32 {
1582		use crate::{Fragment, parse_float};
1583
1584		#[test]
1585		fn test_valid_zero() {
1586			assert_eq!(parse_float::<f32>(Fragment::testing("0.0")), Ok(0.0));
1587		}
1588
1589		#[test]
1590		fn test_valid_positive() {
1591			assert_eq!(parse_float::<f32>(Fragment::testing("1.5")), Ok(1.5));
1592		}
1593
1594		#[test]
1595		fn test_valid_negative() {
1596			assert_eq!(parse_float::<f32>(Fragment::testing("-3.14")), Ok(-3.14));
1597		}
1598
1599		#[test]
1600		fn test_valid_integer() {
1601			assert_eq!(parse_float::<f32>(Fragment::testing("42")), Ok(42.0));
1602		}
1603
1604		#[test]
1605		fn test_valid_scientific() {
1606			assert_eq!(parse_float::<f32>(Fragment::testing("1e2")), Ok(100.0));
1607		}
1608
1609		#[test]
1610		fn test_valid_scientific_negative() {
1611			assert_eq!(parse_float::<f32>(Fragment::testing("1e-2")), Ok(0.01));
1612		}
1613
1614		#[test]
1615		fn test_overflow_positive() {
1616			assert!(parse_float::<f32>(Fragment::testing("3.5e38")).is_err());
1617		}
1618
1619		#[test]
1620		fn test_overflow_negative() {
1621			assert!(parse_float::<f32>(Fragment::testing("-3.5e38")).is_err());
1622		}
1623
1624		#[test]
1625		fn test_invalid_text() {
1626			assert!(parse_float::<f32>(Fragment::testing("abc")).is_err());
1627		}
1628
1629		#[test]
1630		fn test_invalid_empty() {
1631			assert!(parse_float::<f32>(Fragment::testing("")).is_err());
1632		}
1633
1634		#[test]
1635		fn test_invalid_whitespace() {
1636			assert!(parse_float::<f32>(Fragment::testing("   ")).is_err());
1637		}
1638
1639		#[test]
1640		fn test_invalid_nan() {
1641			assert!(parse_float::<f32>(Fragment::testing("NaN")).is_err());
1642		}
1643
1644		#[test]
1645		fn test_invalid_nan_lowercase() {
1646			assert!(parse_float::<f32>(Fragment::testing("nan")).is_err());
1647		}
1648
1649		#[test]
1650		fn test_invalid_multiple_dots() {
1651			assert!(parse_float::<f32>(Fragment::testing("1.2.3")).is_err());
1652		}
1653
1654		#[test]
1655		fn trimming_leading_space() {
1656			assert_eq!(parse_float::<f32>(Fragment::testing(" 1.5")), Ok(1.5));
1657		}
1658
1659		#[test]
1660		fn trimming_trailing_space() {
1661			assert_eq!(parse_float::<f32>(Fragment::testing("1.5 ")), Ok(1.5));
1662		}
1663
1664		#[test]
1665		fn trimming_both_spaces() {
1666			assert_eq!(parse_float::<f32>(Fragment::testing(" 1.5 ")), Ok(1.5));
1667		}
1668
1669		#[test]
1670		fn trimming_negative_leading_space() {
1671			assert_eq!(parse_float::<f32>(Fragment::testing(" -3.14")), Ok(-3.14));
1672		}
1673
1674		#[test]
1675		fn trimming_negative_trailing_space() {
1676			assert_eq!(parse_float::<f32>(Fragment::testing("-3.14 ")), Ok(-3.14));
1677		}
1678
1679		#[test]
1680		fn trimming_negative_both_spaces() {
1681			assert_eq!(parse_float::<f32>(Fragment::testing(" -3.14 ")), Ok(-3.14));
1682		}
1683	}
1684
1685	mod f64 {
1686		use crate::{Fragment, parse_float};
1687
1688		#[test]
1689		fn test_valid_zero() {
1690			assert_eq!(parse_float::<f64>(Fragment::testing("0.0")), Ok(0.0));
1691		}
1692
1693		#[test]
1694		fn test_valid_positive() {
1695			assert_eq!(parse_float::<f64>(Fragment::testing("1.23")), Ok(1.23));
1696		}
1697
1698		#[test]
1699		fn test_valid_negative() {
1700			assert_eq!(parse_float::<f64>(Fragment::testing("-0.001")), Ok(-0.001));
1701		}
1702
1703		#[test]
1704		fn test_valid_integer() {
1705			assert_eq!(parse_float::<f64>(Fragment::testing("42")), Ok(42.0));
1706		}
1707
1708		#[test]
1709		fn test_valid_scientific() {
1710			assert_eq!(parse_float::<f64>(Fragment::testing("1e10")), Ok(1e10));
1711		}
1712
1713		#[test]
1714		fn test_valid_scientific_negative() {
1715			assert_eq!(parse_float::<f64>(Fragment::testing("1e-10")), Ok(1e-10));
1716		}
1717
1718		#[test]
1719		fn test_overflow_positive() {
1720			assert!(parse_float::<f64>(Fragment::testing("1e400")).is_err());
1721		}
1722
1723		#[test]
1724		fn test_overflow_negative() {
1725			assert!(parse_float::<f64>(Fragment::testing("-1e400")).is_err());
1726		}
1727
1728		#[test]
1729		fn test_invalid_text() {
1730			assert!(parse_float::<f64>(Fragment::testing("abc")).is_err());
1731		}
1732
1733		#[test]
1734		fn test_invalid_empty() {
1735			assert!(parse_float::<f64>(Fragment::testing("")).is_err());
1736		}
1737
1738		#[test]
1739		fn test_invalid_whitespace() {
1740			assert!(parse_float::<f64>(Fragment::testing("   ")).is_err());
1741		}
1742
1743		#[test]
1744		fn test_invalid_nan() {
1745			assert!(parse_float::<f64>(Fragment::testing("NaN")).is_err());
1746		}
1747
1748		#[test]
1749		fn test_invalid_nan_mixed_case() {
1750			assert!(parse_float::<f64>(Fragment::testing("NaN")).is_err());
1751		}
1752
1753		#[test]
1754		fn test_invalid_multiple_dots() {
1755			assert!(parse_float::<f64>(Fragment::testing("1.2.3")).is_err());
1756		}
1757
1758		#[test]
1759		fn trimming_leading_space() {
1760			assert_eq!(parse_float::<f64>(Fragment::testing(" 1.23")), Ok(1.23));
1761		}
1762
1763		#[test]
1764		fn trimming_trailing_space() {
1765			assert_eq!(parse_float::<f64>(Fragment::testing("1.23 ")), Ok(1.23));
1766		}
1767
1768		#[test]
1769		fn trimming_both_spaces() {
1770			assert_eq!(parse_float::<f64>(Fragment::testing(" 1.23 ")), Ok(1.23));
1771		}
1772
1773		#[test]
1774		fn trimming_negative_leading_space() {
1775			assert_eq!(parse_float::<f64>(Fragment::testing(" -0.001")), Ok(-0.001));
1776		}
1777
1778		#[test]
1779		fn trimming_negative_trailing_space() {
1780			assert_eq!(parse_float::<f64>(Fragment::testing("-0.001 ")), Ok(-0.001));
1781		}
1782
1783		#[test]
1784		fn trimming_negative_both_spaces() {
1785			assert_eq!(parse_float::<f64>(Fragment::testing(" -0.001 ")), Ok(-0.001));
1786		}
1787	}
1788}