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