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