1use std::borrow::{Borrow, ToOwned};
23use std::fmt;
24use std::ops::Deref;
25use std::str::FromStr;
26
27#[cfg(feature = "serde")]
29pub mod serde;
30
31#[cfg(feature = "serde_json")]
33pub mod serde_json;
34
35#[cfg(feature = "smallnumberbuf")]
36mod smallnumberbuf {
37 use super::*;
38 use smallvec::SmallVec;
39
40 pub type SmallNumberBuf<const LEN: usize = 8> = NumberBuf<SmallVec<[u8; LEN]>>;
42
43 unsafe impl<A: smallvec::Array<Item = u8>> crate::Buffer for SmallVec<A> {
44 fn from_vec(bytes: Vec<u8>) -> Self {
45 bytes.into()
46 }
47
48 fn from_bytes(bytes: &[u8]) -> Self {
49 bytes.into()
50 }
51 }
52}
53
54#[cfg(feature = "smallnumberbuf")]
55pub use smallnumberbuf::*;
56
57#[derive(Clone, Copy, Debug)]
61pub struct InvalidNumber<T>(pub T);
62
63impl<T: fmt::Display> fmt::Display for InvalidNumber<T> {
64 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
65 write!(f, "invalid JSON number: {}", self.0)
66 }
67}
68
69impl<T: fmt::Display + fmt::Debug> std::error::Error for InvalidNumber<T> {}
70
71#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
73pub enum Sign {
74 Negative,
75 Zero,
76 Positive,
77}
78
79impl Sign {
80 #[inline(always)]
82 pub fn is_zero(&self) -> bool {
83 matches!(self, Self::Zero)
84 }
85
86 #[inline(always)]
88 pub fn is_non_positive(&self) -> bool {
89 matches!(self, Self::Negative | Self::Zero)
90 }
91
92 #[inline(always)]
94 pub fn is_non_negative(&self) -> bool {
95 matches!(self, Self::Positive | Self::Zero)
96 }
97
98 #[inline(always)]
100 pub fn is_positive(&self) -> bool {
101 matches!(self, Self::Positive)
102 }
103
104 #[inline(always)]
106 pub fn is_negative(&self) -> bool {
107 matches!(self, Self::Negative)
108 }
109}
110
111#[derive(PartialEq, Eq, PartialOrd, Ord, Hash)]
117pub struct Number {
118 data: [u8],
119}
120
121impl Number {
122 pub fn new<B: AsRef<[u8]> + ?Sized>(data: &B) -> Result<&Number, InvalidNumber<&B>> {
124 let s = data.as_ref();
125
126 enum State {
127 Init,
128 FirstDigit,
129 Zero,
130 NonZero,
131 FractionalFirst,
132 FractionalRest,
133 ExponentSign,
134 ExponentFirst,
135 ExponentRest,
136 }
137
138 let mut state = State::Init;
139
140 for b in s {
141 match state {
142 State::Init => match *b {
143 b'-' => state = State::FirstDigit,
144 b'0' => state = State::Zero,
145 b'1'..=b'9' => state = State::NonZero,
146 _ => return Err(InvalidNumber(data)),
147 },
148 State::FirstDigit => match *b {
149 b'0' => state = State::Zero,
150 b'1'..=b'9' => state = State::NonZero,
151 _ => return Err(InvalidNumber(data)),
152 },
153 State::Zero => match *b {
154 b'.' => state = State::FractionalFirst,
155 b'e' | b'E' => state = State::ExponentSign,
156 _ => return Err(InvalidNumber(data)),
157 },
158 State::NonZero => match *b {
159 b'0'..=b'9' => state = State::NonZero,
160 b'.' => state = State::FractionalFirst,
161 b'e' | b'E' => state = State::ExponentSign,
162 _ => return Err(InvalidNumber(data)),
163 },
164 State::FractionalFirst => match *b {
165 b'0'..=b'9' => state = State::FractionalRest,
166 _ => return Err(InvalidNumber(data)),
167 },
168 State::FractionalRest => match *b {
169 b'0'..=b'9' => state = State::FractionalRest,
170 b'e' | b'E' => state = State::ExponentSign,
171 _ => return Err(InvalidNumber(data)),
172 },
173 State::ExponentSign => match *b {
174 b'+' | b'-' => state = State::ExponentFirst,
175 b'0'..=b'9' => state = State::ExponentRest,
176 _ => return Err(InvalidNumber(data)),
177 },
178 State::ExponentFirst => match *b {
179 b'0'..=b'9' => state = State::ExponentRest,
180 _ => return Err(InvalidNumber(data)),
181 },
182 State::ExponentRest => match *b {
183 b'0'..=b'9' => state = State::ExponentRest,
184 _ => return Err(InvalidNumber(data)),
185 },
186 }
187 }
188
189 if matches!(
190 state,
191 State::Zero | State::NonZero | State::FractionalRest | State::ExponentRest
192 ) {
193 Ok(unsafe { Self::new_unchecked(s) })
194 } else {
195 Err(InvalidNumber(data))
196 }
197 }
198
199 #[inline(always)]
205 pub unsafe fn new_unchecked<B: AsRef<[u8]> + ?Sized>(data: &B) -> &Number {
206 std::mem::transmute(data.as_ref())
207 }
208
209 #[inline(always)]
210 pub fn as_str(&self) -> &str {
211 unsafe {
212 std::str::from_utf8_unchecked(&self.data)
214 }
215 }
216
217 pub fn trimmed(&self) -> &Self {
218 let mut end = 1;
219 let mut i = 1;
220 let mut fractional_part = false;
221 while i < self.data.len() {
222 match self.data[i] {
223 b'0' if fractional_part => (),
224 b'.' => fractional_part = true,
225 _ => end = i + 1,
226 }
227
228 i += 1
229 }
230
231 unsafe { Self::new_unchecked(&self.data[0..end]) }
232 }
233
234 #[inline(always)]
240 pub fn is_zero(&self) -> bool {
241 for b in &self.data {
242 match b {
243 b'-' | b'0' | b'.' => (),
244 b'e' | b'E' => break,
245 _ => return false,
246 }
247 }
248
249 true
250 }
251
252 pub fn sign(&self) -> Sign {
254 let mut non_negative = true;
255
256 for b in &self.data {
257 match b {
258 b'-' => non_negative = false,
259 b'0' | b'.' => (),
260 b'e' | b'E' => break,
261 _ => {
262 return if non_negative {
263 Sign::Positive
264 } else {
265 Sign::Negative
266 }
267 }
268 }
269 }
270
271 Sign::Zero
272 }
273
274 #[inline(always)]
276 pub fn is_non_positive(&self) -> bool {
277 self.sign().is_non_positive()
278 }
279
280 #[inline(always)]
282 pub fn is_non_negative(&self) -> bool {
283 self.sign().is_non_negative()
284 }
285
286 #[inline(always)]
288 pub fn is_positive(&self) -> bool {
289 self.sign().is_positive()
290 }
291
292 #[inline(always)]
294 pub fn is_negative(&self) -> bool {
295 self.sign().is_negative()
296 }
297
298 #[inline(always)]
300 pub fn has_decimal_point(&self) -> bool {
301 self.data.contains(&b'.')
302 }
303
304 #[inline(always)]
308 pub fn has_fraction(&self) -> bool {
309 self.has_decimal_point()
310 }
311
312 #[inline(always)]
314 pub fn has_exponent(&self) -> bool {
315 for b in &self.data {
316 if matches!(b, b'e' | b'E') {
317 return true;
318 }
319 }
320
321 false
322 }
323
324 #[inline(always)]
325 pub fn is_i32(&self) -> bool {
326 self.as_i32().is_some()
327 }
328
329 #[inline(always)]
330 pub fn is_i64(&self) -> bool {
331 self.as_i64().is_some()
332 }
333
334 #[inline(always)]
335 pub fn is_u32(&self) -> bool {
336 self.as_u32().is_some()
337 }
338
339 #[inline(always)]
340 pub fn is_u64(&self) -> bool {
341 self.as_u64().is_some()
342 }
343
344 #[inline(always)]
345 pub fn as_i32(&self) -> Option<i32> {
346 self.as_str().parse().ok()
347 }
348
349 #[inline(always)]
350 pub fn as_i64(&self) -> Option<i64> {
351 self.as_str().parse().ok()
352 }
353
354 #[inline(always)]
355 pub fn as_u32(&self) -> Option<u32> {
356 self.as_str().parse().ok()
357 }
358
359 #[inline(always)]
360 pub fn as_u64(&self) -> Option<u64> {
361 self.as_str().parse().ok()
362 }
363
364 #[inline(always)]
365 pub fn as_f32_lossy(&self) -> f32 {
366 lexical::parse_with_options::<_, _, { lexical::format::JSON }>(
367 self.as_bytes(),
368 &LOSSY_PARSE_FLOAT,
369 )
370 .unwrap()
371 }
372
373 #[inline(always)]
379 pub fn as_f32_lossless(&self) -> Option<f32> {
380 let f = self.as_f32_lossy();
381 let n: NumberBuf = f.try_into().unwrap();
382 eprintln!("n = {n} = {f}");
383 if n.as_number() == self.trimmed() {
384 Some(f)
385 } else {
386 None
387 }
388 }
389
390 #[inline(always)]
391 pub fn as_f64_lossy(&self) -> f64 {
392 lexical::parse_with_options::<_, _, { lexical::format::JSON }>(
393 self.as_bytes(),
394 &LOSSY_PARSE_FLOAT,
395 )
396 .unwrap()
397 }
398
399 #[inline(always)]
405 pub fn as_f64_lossless(&self) -> Option<f64> {
406 let f = self.as_f64_lossy();
407 let n: NumberBuf = f.try_into().unwrap();
408 if n.as_number() == self {
409 Some(f)
410 } else {
411 None
412 }
413 }
414
415 #[cfg(feature = "canonical")]
418 pub fn canonical_with<'b>(&self, buffer: &'b mut ryu_js::Buffer) -> &'b Number {
419 unsafe { Number::new_unchecked(buffer.format_finite(self.as_f64_lossy())) }
420 }
421
422 #[cfg(feature = "canonical")]
425 pub fn canonical(&self) -> NumberBuf {
426 let mut buffer = ryu_js::Buffer::new();
427 self.canonical_with(&mut buffer).to_owned()
428 }
429}
430
431const LOSSY_PARSE_FLOAT: lexical::ParseFloatOptions = lexical::ParseFloatOptions::builder()
432 .lossy(true)
433 .build_unchecked();
434
435impl Deref for Number {
436 type Target = str;
437
438 #[inline(always)]
439 fn deref(&self) -> &str {
440 self.as_str()
441 }
442}
443
444impl AsRef<str> for Number {
445 #[inline(always)]
446 fn as_ref(&self) -> &str {
447 self.as_str()
448 }
449}
450
451impl Borrow<str> for Number {
452 #[inline(always)]
453 fn borrow(&self) -> &str {
454 self.as_str()
455 }
456}
457
458impl AsRef<[u8]> for Number {
459 #[inline(always)]
460 fn as_ref(&self) -> &[u8] {
461 self.as_bytes()
462 }
463}
464
465impl<'a> TryFrom<&'a str> for &'a Number {
466 type Error = InvalidNumber<&'a str>;
467
468 #[inline(always)]
469 fn try_from(s: &'a str) -> Result<&'a Number, InvalidNumber<&'a str>> {
470 Number::new(s)
471 }
472}
473
474impl ToOwned for Number {
475 type Owned = NumberBuf;
476
477 fn to_owned(&self) -> Self::Owned {
478 unsafe { NumberBuf::new_unchecked(self.as_bytes().to_owned()) }
479 }
480}
481
482impl fmt::Display for Number {
483 #[inline(always)]
484 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
485 self.as_str().fmt(f)
486 }
487}
488
489impl fmt::Debug for Number {
490 #[inline(always)]
491 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
492 self.as_str().fmt(f)
493 }
494}
495
496pub unsafe trait Buffer: AsRef<[u8]> {
503 fn from_bytes(bytes: &[u8]) -> Self;
504
505 fn from_vec(bytes: Vec<u8>) -> Self;
506}
507
508unsafe impl Buffer for Vec<u8> {
509 fn from_bytes(bytes: &[u8]) -> Self {
510 bytes.into()
511 }
512
513 fn from_vec(bytes: Vec<u8>) -> Self {
514 bytes
515 }
516}
517
518#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
520pub struct NumberBuf<B = Vec<u8>> {
521 data: B,
522}
523
524impl<B> NumberBuf<B> {
525 #[inline(always)]
527 pub fn new(data: B) -> Result<Self, InvalidNumber<B>>
528 where
529 B: AsRef<[u8]>,
530 {
531 match Number::new(&data) {
532 Ok(_) => Ok(NumberBuf { data }),
533 Err(_) => Err(InvalidNumber(data)),
534 }
535 }
536
537 #[inline(always)]
543 pub unsafe fn new_unchecked(data: B) -> Self {
544 NumberBuf { data }
545 }
546
547 #[inline(always)]
549 pub fn from_number(n: &Number) -> Self
550 where
551 B: FromIterator<u8>,
552 {
553 unsafe { NumberBuf::new_unchecked(n.bytes().collect()) }
554 }
555
556 #[inline(always)]
557 pub fn buffer(&self) -> &B {
558 &self.data
559 }
560
561 #[inline(always)]
562 pub fn into_buffer(self) -> B {
563 self.data
564 }
565}
566
567impl NumberBuf<String> {
568 #[inline(always)]
569 pub fn into_string(self) -> String {
570 self.data
571 }
572
573 #[inline(always)]
574 pub fn into_bytes(self) -> Vec<u8> {
575 self.data.into_bytes()
576 }
577}
578
579impl<B: Buffer> NumberBuf<B> {
580 #[inline(always)]
581 pub fn as_number(&self) -> &Number {
582 unsafe { Number::new_unchecked(&self.data) }
583 }
584}
585
586impl<B: Buffer> FromStr for NumberBuf<B> {
587 type Err = InvalidNumber<B>;
588
589 #[inline(always)]
590 fn from_str(s: &str) -> Result<Self, Self::Err> {
591 Self::new(B::from_bytes(s.as_bytes()))
592 }
593}
594
595impl<B: Buffer> Deref for NumberBuf<B> {
596 type Target = Number;
597
598 #[inline(always)]
599 fn deref(&self) -> &Number {
600 self.as_number()
601 }
602}
603
604impl<B: Buffer> AsRef<Number> for NumberBuf<B> {
605 #[inline(always)]
606 fn as_ref(&self) -> &Number {
607 self.as_number()
608 }
609}
610
611impl<B: Buffer> Borrow<Number> for NumberBuf<B> {
612 #[inline(always)]
613 fn borrow(&self) -> &Number {
614 self.as_number()
615 }
616}
617
618impl<B: Buffer> AsRef<str> for NumberBuf<B> {
619 #[inline(always)]
620 fn as_ref(&self) -> &str {
621 self.as_str()
622 }
623}
624
625impl<B: Buffer> Borrow<str> for NumberBuf<B> {
626 #[inline(always)]
627 fn borrow(&self) -> &str {
628 self.as_str()
629 }
630}
631
632impl<B: Buffer> AsRef<[u8]> for NumberBuf<B> {
633 #[inline(always)]
634 fn as_ref(&self) -> &[u8] {
635 self.as_bytes()
636 }
637}
638
639impl<B: Buffer> Borrow<[u8]> for NumberBuf<B> {
640 #[inline(always)]
641 fn borrow(&self) -> &[u8] {
642 self.as_bytes()
643 }
644}
645
646impl<B: Buffer> fmt::Display for NumberBuf<B> {
647 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
648 self.as_str().fmt(f)
649 }
650}
651
652impl<B: Buffer> fmt::Debug for NumberBuf<B> {
653 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
654 self.as_str().fmt(f)
655 }
656}
657
658macro_rules! impl_from_int {
659 ($($ty:ty),*) => {
660 $(
661 impl<B: Buffer> From<$ty> for NumberBuf<B> {
662 #[inline(always)]
663 fn from(i: $ty) -> Self {
664 unsafe {
665 Self::new_unchecked(B::from_vec(lexical::to_string(i).into_bytes()))
666 }
667 }
668 }
669 )*
670 };
671}
672
673#[derive(Clone, Copy, Debug)]
675pub enum TryFromFloatError {
676 Nan,
678
679 Infinite,
681}
682
683const WRITE_FLOAT: lexical::WriteFloatOptions = lexical::WriteFloatOptions::builder()
684 .trim_floats(true)
685 .exponent(b'e')
686 .build_unchecked();
687
688macro_rules! impl_try_from_float {
689 ($($ty:ty),*) => {
690 $(
691 impl<B: Buffer> TryFrom<$ty> for NumberBuf<B> {
692 type Error = TryFromFloatError;
693
694 #[inline(always)]
695 fn try_from(f: $ty) -> Result<Self, Self::Error> {
696 if f.is_finite() {
697 Ok(unsafe {
698 Self::new_unchecked(B::from_vec(lexical::to_string_with_options::<_, {lexical::format::JSON}>(f, &WRITE_FLOAT).into_bytes()))
699 })
700 } else if f.is_nan() {
701 Err(TryFromFloatError::Nan)
702 } else {
703 Err(TryFromFloatError::Infinite)
704 }
705 }
706 }
707 )*
708 };
709}
710
711impl_from_int!(u8, i8, u16, i16, u32, i32, u64, i64, usize, isize);
712impl_try_from_float!(f32, f64);
713
714#[cfg(test)]
715mod tests {
716 use super::*;
717
718 fn trimming_test(a: &str, b: &str) {
719 let a = Number::new(a).unwrap();
720 let b = Number::new(b).unwrap();
721 assert_eq!(a.trimmed(), b)
722 }
723
724 #[test]
725 fn trimming() {
726 trimming_test("0", "0");
727 trimming_test("0.0", "0");
728 trimming_test("1.0", "1");
729 trimming_test("1.0", "1");
730 trimming_test("1.1", "1.1");
731 trimming_test("1.10000", "1.1");
732 trimming_test("100.0", "100");
733 trimming_test("100.1000", "100.1");
734 }
735
736 macro_rules! positive_tests {
737 { $($id:ident: $input:literal),* } => {
738 $(
739 #[test]
740 fn $id () {
741 assert!(Number::new($input).is_ok())
742 }
743 )*
744 };
745 }
746
747 macro_rules! negative_tests {
748 { $($id:ident: $input:literal),* } => {
749 $(
750 #[test]
751 fn $id () {
752 assert!(Number::new($input).is_err())
753 }
754 )*
755 };
756 }
757
758 macro_rules! sign_tests {
759 { $($id:ident: $input:literal => $sign:ident),* } => {
760 $(
761 #[test]
762 fn $id () {
763 assert_eq!(Number::new($input).unwrap().sign(), Sign::$sign)
764 }
765 )*
766 };
767 }
768
769 macro_rules! canonical_tests {
770 { $($id:ident: $input:literal => $output:literal),* } => {
771 $(
772 #[cfg(feature="canonical")]
773 #[test]
774 fn $id () {
775 assert_eq!(Number::new($input).unwrap().canonical().as_number(), Number::new($output).unwrap())
776 }
777 )*
778 };
779 }
780
781 positive_tests! {
782 pos_01: "0",
783 pos_02: "-0",
784 pos_03: "123",
785 pos_04: "1.23",
786 pos_05: "-12.34",
787 pos_06: "12.34e+56",
788 pos_07: "12.34E-56",
789 pos_08: "0.0000"
790 }
791
792 negative_tests! {
793 neg_01: "",
794 neg_02: "00",
795 neg_03: "01",
796 neg_04: "-00",
797 neg_05: "-01",
798 neg_06: "0.000e+-1",
799 neg_07: "12.34E-56abc",
800 neg_08: "1.",
801 neg_09: "12.34e",
802 neg_10: "12.34e+",
803 neg_11: "12.34E-"
804 }
805
806 sign_tests! {
807 sign_zero_01: "0" => Zero,
808 sign_zero_02: "-0" => Zero,
809 sign_zero_03: "0.0" => Zero,
810 sign_zero_04: "0.0e12" => Zero,
811 sign_zero_05: "-0.0E-12" => Zero,
812 sign_zero_06: "-0.00000" => Zero
813 }
814
815 sign_tests! {
816 sign_pos_01: "1" => Positive,
817 sign_pos_02: "0.1" => Positive,
818 sign_pos_03: "0.01e23" => Positive,
819 sign_pos_04: "1.0E-23" => Positive,
820 sign_pos_05: "0.00001" => Positive
821 }
822
823 sign_tests! {
824 sign_neg_01: "-1" => Negative,
825 sign_neg_02: "-0.1" => Negative,
826 sign_neg_03: "-0.01e23" => Negative,
827 sign_neg_04: "-1.0E-23" => Negative,
828 sign_neg_05: "-0.00001" => Negative
829 }
830
831 canonical_tests! {
832 canonical_01: "-0.0000" => "0",
833 canonical_02: "0.00000000028" => "2.8e-10"
834 }
835}