1use crate::math::powi_f64;
4use crate::object::macros::object;
5use crate::object::{Object, ObjectLike};
6use crate::reader::Reader;
7use crate::reader::{Readable, ReaderContext, ReaderExt, Skippable};
8use crate::trivia::{is_regular_character, is_white_space_character};
9use core::fmt::{Debug, Display, Formatter};
10
11#[rustfmt::skip]
12static POWERS_OF_10: [f64; 20] = [
13 1.0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9,
14 1e10, 1e11, 1e12, 1e13, 1e14, 1e15, 1e16, 1e17, 1e18, 1e19,
15];
16
17#[derive(Clone, Copy, Debug, PartialEq)]
19pub struct Number(pub(crate) InternalNumber);
20
21impl Number {
22 pub const ZERO: Self = Self::from_i32(0);
24 pub const ONE: Self = Self::from_i32(1);
26
27 pub fn as_f64(&self) -> f64 {
29 match self.0 {
30 InternalNumber::Real(r) => r,
31 InternalNumber::Integer(i) => i as f64,
32 }
33 }
34
35 pub fn as_f32(&self) -> f32 {
37 match self.0 {
38 InternalNumber::Real(r) => r as f32,
39 InternalNumber::Integer(i) => i as f32,
40 }
41 }
42
43 pub fn as_i64(&self) -> i64 {
45 match self.0 {
46 InternalNumber::Real(r) => r as i64,
47 InternalNumber::Integer(i) => i,
48 }
49 }
50
51 pub const fn from_f32(num: f32) -> Self {
53 Self(InternalNumber::Real(num as f64))
54 }
55
56 pub const fn from_i32(num: i32) -> Self {
58 Self(InternalNumber::Integer(num as i64))
59 }
60}
61
62impl Display for Number {
63 fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
64 match self.0 {
65 InternalNumber::Real(value) => write!(f, "{value:?}"),
66 InternalNumber::Integer(value) => write!(f, "{value}"),
67 }
68 }
69}
70
71impl Skippable for Number {
72 fn skip(r: &mut Reader<'_>, _: bool) -> Option<()> {
73 let has_sign = r.forward_if(|b| b == b'+' || b == b'-').is_some();
74
75 match r.peek_byte()? {
77 b'.' => {
78 r.read_byte()?;
79 r.forward_while(is_digit_or_minus);
81 }
82 b'0'..=b'9' | b'-' => {
83 r.forward_while_1(is_digit_or_minus)?;
84 if let Some(()) = r.forward_tag(b".") {
85 r.forward_while(is_digit_or_minus);
86 }
87 }
88 b if has_sign && (is_white_space_character(b) || matches!(b, b'(' | b'<')) => {}
92 _ => return None,
93 }
94
95 if r.peek_byte().is_some_and(is_regular_character) {
97 return None;
98 }
99
100 Some(())
101 }
102}
103
104impl Readable<'_> for Number {
105 #[inline]
106 fn read(r: &mut Reader<'_>, _: &ReaderContext<'_>) -> Option<Self> {
107 let old_offset = r.offset();
108 Self::read_simple(r)
109 .or_else(|| {
110 r.jump(old_offset);
111 read_inner(r)
112 })
113 .or_else(|| {
114 r.jump(old_offset);
115 None
116 })
117 }
118}
119
120impl Number {
121 #[inline(always)]
122 pub(crate) fn read_simple(r: &mut Reader<'_>) -> Option<Self> {
123 let negative = match r.peek_byte() {
124 Some(b'-') => {
125 r.forward();
126 true
127 }
128 Some(b'+') => {
129 r.forward();
130 false
131 }
132 _ => false,
133 };
134
135 let mut mantissa: u64 = 0;
136 let mut read_digits = |r: &mut Reader<'_>| {
137 let start = r.offset();
138 while let Some(d) = r
139 .peek_byte()
140 .map(|b| b.wrapping_sub(b'0'))
141 .filter(|d| *d < 10)
142 {
143 mantissa = mantissa.wrapping_mul(10).wrapping_add(d as u64);
144 r.forward();
145 }
146 r.offset() - start
147 };
148
149 let mut digits = read_digits(r);
150 let mut decimal_shift = None;
151 if r.peek_byte() == Some(b'.') {
152 r.forward();
153 let fraction_digits = read_digits(r);
154 decimal_shift = Some(fraction_digits as u32);
155 digits += fraction_digits;
156 }
157
158 if digits == 0 || digits > 18 || r.peek_byte().is_some_and(is_regular_character) {
159 return None;
160 }
161
162 Some(Self::from_parts(negative, mantissa, decimal_shift))
163 }
164
165 #[inline(always)]
166 fn from_parts(negative: bool, mantissa: u64, decimal_shift: Option<u32>) -> Self {
167 match decimal_shift {
168 None => {
169 let value = mantissa as i64;
170 Self(InternalNumber::Integer(if negative {
171 value.wrapping_neg()
172 } else {
173 value
174 }))
175 }
176 Some(shift) => {
177 let divisor = match POWERS_OF_10.get(shift as usize) {
178 Some(power) => *power,
179 None => powi_f64(10.0, shift),
180 };
181 let value = mantissa as f64 / divisor;
182 Self(InternalNumber::Real(if negative { -value } else { value }))
183 }
184 }
185 }
186}
187
188#[inline(always)]
189fn read_inner(r: &mut Reader<'_>) -> Option<Number> {
190 let start_offset = r.offset();
191 let negative = match r.peek_byte()? {
192 b'-' => {
193 r.forward();
194 true
195 }
196 b'+' => {
197 r.forward();
198 false
199 }
200 _ => false,
201 };
202
203 let mut mantissa: u64 = 0;
204 let mut has_dot = false;
205 let mut decimal_shift: u32 = 0;
206 let mut has_digits = false;
207 let mut overflowed = false;
208 let mut number_end = None;
209
210 loop {
211 match r.peek_byte() {
212 Some(b'0'..=b'9') => {
213 let d = r.read_byte().unwrap();
214 if !overflowed {
215 if let Some(value) = mantissa
216 .checked_mul(10)
217 .and_then(|v| v.checked_add((d - b'0') as u64))
218 {
219 mantissa = value;
220 } else {
221 overflowed = true;
222 }
223 }
224 has_digits = true;
225 if has_dot {
226 decimal_shift += 1;
227 }
228 }
229 Some(b'.') if !has_dot => {
230 r.forward();
231 has_dot = true;
232 }
233 Some(b'-') if has_digits => {
235 number_end = Some(r.offset());
236 r.forward();
237 r.forward_while(is_digit_or_minus);
238 break;
239 }
240 _ => break,
241 }
242 }
243
244 if !has_digits {
245 if negative || has_dot {
246 return Some(Number(InternalNumber::Integer(0)));
248 }
249 return None;
250 }
251
252 if r.peek_byte().is_some_and(is_regular_character) {
255 return None;
256 }
257
258 let integer_overflow = !has_dot && mantissa > i64::MAX as u64;
259
260 if overflowed || integer_overflow {
261 let end_offset = number_end.unwrap_or_else(|| r.offset());
262 let number = core::str::from_utf8(r.range(start_offset..end_offset)?).ok()?;
263
264 if !has_dot && let Ok(value) = number.parse::<i64>() {
265 return Some(Number(InternalNumber::Integer(value)));
266 }
267
268 let value = number.parse::<f64>().ok()?;
269 return Some(Number(InternalNumber::Real(value)));
270 }
271
272 Some(Number::from_parts(
273 negative,
274 mantissa,
275 has_dot.then_some(decimal_shift),
276 ))
277}
278
279object!(Number, Number);
280
281#[derive(Clone, Copy, Debug, PartialEq)]
282pub(crate) enum InternalNumber {
283 Real(f64),
284 Integer(i64),
285}
286
287macro_rules! int_num {
288 ($i:ident) => {
289 impl Skippable for $i {
290 fn skip(r: &mut Reader<'_>, _: bool) -> Option<()> {
291 r.forward_if(|b| b == b'+' || b == b'-');
292 r.forward_while_1(is_digit)?;
293
294 if r.peek_byte() == Some(b'.') {
296 return None;
297 }
298
299 if r.peek_byte().is_some_and(is_regular_character) {
302 return None;
303 }
304
305 Some(())
306 }
307 }
308
309 impl<'a> Readable<'a> for $i {
310 fn read(r: &mut Reader<'a>, ctx: &ReaderContext<'a>) -> Option<$i> {
311 r.read::<Number>(ctx)
312 .map(|n| n.as_i64())
313 .and_then(|n| n.try_into().ok())
314 }
315 }
316
317 impl TryFrom<Object<'_>> for $i {
318 type Error = ();
319
320 fn try_from(value: Object<'_>) -> core::result::Result<Self, Self::Error> {
321 match value {
322 Object::Number(n) => n.as_i64().try_into().ok().ok_or(()),
323 _ => Err(()),
324 }
325 }
326 }
327
328 impl<'a> ObjectLike<'a> for $i {}
329 };
330}
331
332int_num!(i32);
333int_num!(i64);
334int_num!(u32);
335int_num!(u16);
336int_num!(usize);
337int_num!(u8);
338
339impl Skippable for f32 {
340 fn skip(r: &mut Reader<'_>, is_content_stream: bool) -> Option<()> {
341 r.skip::<Number>(is_content_stream).map(|_| {})
342 }
343}
344
345impl Readable<'_> for f32 {
346 fn read(r: &mut Reader<'_>, _: &ReaderContext<'_>) -> Option<Self> {
347 r.read_without_context::<Number>()
348 .map(|n| n.as_f64() as Self)
349 }
350}
351
352impl TryFrom<Object<'_>> for f32 {
353 type Error = ();
354
355 fn try_from(value: Object<'_>) -> Result<Self, Self::Error> {
356 match value {
357 Object::Number(n) => Ok(n.as_f64() as Self),
358 _ => Err(()),
359 }
360 }
361}
362
363impl ObjectLike<'_> for f32 {}
364
365impl Skippable for f64 {
366 fn skip(r: &mut Reader<'_>, is_content_stream: bool) -> Option<()> {
367 r.skip::<Number>(is_content_stream).map(|_| {})
368 }
369}
370
371impl Readable<'_> for f64 {
372 fn read(r: &mut Reader<'_>, _: &ReaderContext<'_>) -> Option<Self> {
373 r.read_without_context::<Number>().map(|n| n.as_f64())
374 }
375}
376
377impl TryFrom<Object<'_>> for f64 {
378 type Error = ();
379
380 fn try_from(value: Object<'_>) -> Result<Self, Self::Error> {
381 match value {
382 Object::Number(n) => Ok(n.as_f64()),
383 _ => Err(()),
384 }
385 }
386}
387
388impl ObjectLike<'_> for f64 {}
389
390pub(crate) fn is_digit(byte: u8) -> bool {
391 byte.is_ascii_digit()
392}
393
394pub(crate) fn is_digit_or_minus(byte: u8) -> bool {
395 is_digit(byte) || byte == b'-'
396}
397
398#[cfg(test)]
399mod tests {
400 use crate::object::Number;
401 use crate::reader::Reader;
402 use crate::reader::ReaderExt;
403
404 #[test]
405 fn display() {
406 assert_eq!(format!("{}", Number::from_i32(10)), "10");
407 assert_eq!(format!("{}", Number::from_f32(10.0)), "10.0");
408 assert_eq!(format!("{}", Number::from_f32(10.5)), "10.5");
409 }
410
411 #[test]
412 fn int_1() {
413 assert_eq!(
414 Reader::new("0".as_bytes())
415 .read_without_context::<i32>()
416 .unwrap(),
417 0
418 );
419 }
420
421 #[test]
422 fn int_3() {
423 assert_eq!(
424 Reader::new("+32".as_bytes())
425 .read_without_context::<i32>()
426 .unwrap(),
427 32
428 );
429 }
430
431 #[test]
432 fn int_4() {
433 assert_eq!(
434 Reader::new("-32".as_bytes())
435 .read_without_context::<i32>()
436 .unwrap(),
437 -32
438 );
439 }
440
441 #[test]
442 fn int_6() {
443 assert_eq!(
444 Reader::new("98349".as_bytes())
445 .read_without_context::<i32>()
446 .unwrap(),
447 98349
448 );
449 }
450
451 #[test]
452 fn int_7() {
453 assert_eq!(
454 Reader::new("003245".as_bytes())
455 .read_without_context::<i32>()
456 .unwrap(),
457 3245
458 );
459 }
460
461 #[test]
462 fn int_min_stays_integer() {
463 let number = Reader::new("-9223372036854775808".as_bytes())
464 .read_without_context::<Number>()
465 .unwrap();
466 assert_eq!(number.0, super::InternalNumber::Integer(i64::MIN));
467 assert_eq!(number.as_i64(), i64::MIN);
468 }
469
470 #[test]
471 fn real_1() {
472 assert_eq!(
473 Reader::new("3".as_bytes())
474 .read_without_context::<f32>()
475 .unwrap(),
476 3.0
477 );
478 }
479
480 #[test]
481 fn real_3() {
482 assert_eq!(
483 Reader::new("+32".as_bytes())
484 .read_without_context::<f32>()
485 .unwrap(),
486 32.0
487 );
488 }
489
490 #[test]
491 fn real_4() {
492 assert_eq!(
493 Reader::new("-32".as_bytes())
494 .read_without_context::<f32>()
495 .unwrap(),
496 -32.0
497 );
498 }
499
500 #[test]
501 fn real_5() {
502 assert_eq!(
503 Reader::new("-32.01".as_bytes())
504 .read_without_context::<f32>()
505 .unwrap(),
506 -32.01
507 );
508 }
509
510 #[test]
511 fn real_6() {
512 assert_eq!(
513 Reader::new("-.345".as_bytes())
514 .read_without_context::<f32>()
515 .unwrap(),
516 -0.345
517 );
518 }
519
520 #[test]
521 fn real_7() {
522 assert_eq!(
523 Reader::new("-.00143".as_bytes())
524 .read_without_context::<f32>()
525 .unwrap(),
526 -0.00143
527 );
528 }
529
530 #[test]
531 fn real_8() {
532 assert_eq!(
533 Reader::new("-12.0013".as_bytes())
534 .read_without_context::<f32>()
535 .unwrap(),
536 -12.0013
537 );
538 }
539
540 #[test]
541 fn real_9() {
542 assert_eq!(
543 Reader::new("98349.432534".as_bytes())
544 .read_without_context::<f32>()
545 .unwrap(),
546 98_349.43
547 );
548 }
549
550 #[test]
551 fn real_10() {
552 assert_eq!(
553 Reader::new("-34534656.34".as_bytes())
554 .read_without_context::<f32>()
555 .unwrap(),
556 -34534656.34
557 );
558 }
559
560 #[test]
561 fn real_failing() {
562 assert!(
563 Reader::new("+abc".as_bytes())
564 .read_without_context::<f32>()
565 .is_none()
566 );
567 }
568
569 #[test]
570 fn number_1() {
571 assert_eq!(
572 Reader::new("+32".as_bytes())
573 .read_without_context::<Number>()
574 .unwrap()
575 .as_f64() as f32,
576 32.0
577 );
578 }
579
580 #[test]
581 fn number_2() {
582 assert_eq!(
583 Reader::new("-32.01".as_bytes())
584 .read_without_context::<Number>()
585 .unwrap()
586 .as_f64() as f32,
587 -32.01
588 );
589 }
590
591 #[test]
592 fn number_3() {
593 assert_eq!(
594 Reader::new("-.345".as_bytes())
595 .read_without_context::<Number>()
596 .unwrap()
597 .as_f64() as f32,
598 -0.345
599 );
600 }
601
602 #[test]
603 fn large_number() {
604 assert_eq!(
605 Reader::new("38359922".as_bytes())
606 .read_without_context::<Number>()
607 .unwrap()
608 .as_i64(),
609 38359922
610 );
611 }
612
613 #[test]
614 fn large_number_2() {
615 assert_eq!(
616 Reader::new("4294966260".as_bytes())
617 .read_without_context::<u32>()
618 .unwrap(),
619 4294966260
620 );
621 }
622
623 #[test]
624 fn twenty_digit_real_does_not_wrap() {
625 let got = Reader::new("190.50000762939453225".as_bytes())
626 .read_without_context::<Number>()
627 .unwrap()
628 .as_f64();
629 assert_eq!(got, 190.500_007_629_394_53);
630 }
631
632 #[test]
633 fn nineteen_digit_real_stays_exact() {
634 let got = Reader::new("190.5000076293945313".as_bytes())
635 .read_without_context::<Number>()
636 .unwrap()
637 .as_f64();
638 assert_eq!(got, 190.500_007_629_394_53);
639 }
640
641 #[test]
642 fn oversized_integer_uses_float_fallback() {
643 let n = Reader::new("9999999999999999999".as_bytes())
644 .read_without_context::<Number>()
645 .unwrap();
646 assert_eq!(n.as_f64(), 9_999_999_999_999_999_999_u64 as f64);
647 assert_eq!(n.as_i64(), i64::MAX);
648 }
649
650 #[test]
651 fn oversized_negative_integer_uses_float_fallback() {
652 let n = Reader::new("-1234567890123456789012345".as_bytes())
653 .read_without_context::<Number>()
654 .unwrap();
655 assert_eq!(n.as_f64(), -1.234_567_890_123_456_8e24);
656 assert_eq!(n.as_i64(), i64::MIN);
657 }
658
659 #[test]
660 fn integer_overflow_then_fraction_uses_float_fallback() {
661 let got = Reader::new("12345678901234567890123.456".as_bytes())
662 .read_without_context::<Number>()
663 .unwrap()
664 .as_f64();
665 assert_eq!(got, 1.234_567_890_123_456_8e22);
666 }
667
668 #[test]
669 fn f32_max_uses_float_fallback() {
670 let got = Reader::new("340282346638528859811704183484516925440".as_bytes())
671 .read_without_context::<f32>()
672 .unwrap();
673 assert_eq!(got, f32::MAX);
674 }
675
676 #[test]
677 fn float_fallback_ignores_trailing_minus() {
678 let input = "1234567890123456789012345-123".as_bytes();
679 let mut reader = Reader::new(input);
680 let got = reader.read_without_context::<Number>().unwrap().as_f64();
681 assert_eq!(got, 1.234_567_890_123_456_8e24);
682 assert_eq!(reader.offset(), input.len());
683 }
684}