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;
10use log::debug;
11
12#[rustfmt::skip]
13static POWERS_OF_10: [f64; 20] = [
14 1.0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9,
15 1e10, 1e11, 1e12, 1e13, 1e14, 1e15, 1e16, 1e17, 1e18, 1e19,
16];
17
18#[derive(Clone, Copy, Debug, PartialEq)]
20pub struct Number(pub(crate) InternalNumber);
21
22impl Number {
23 pub const ZERO: Self = Self::from_i32(0);
25 pub const ONE: Self = Self::from_i32(1);
27
28 pub fn as_f64(&self) -> f64 {
30 match self.0 {
31 InternalNumber::Real(r) => r,
32 InternalNumber::Integer(i) => i as f64,
33 }
34 }
35
36 pub fn as_f32(&self) -> f32 {
38 match self.0 {
39 InternalNumber::Real(r) => r as f32,
40 InternalNumber::Integer(i) => i as f32,
41 }
42 }
43
44 pub fn as_i64(&self) -> i64 {
46 match self.0 {
47 InternalNumber::Real(r) => {
48 let res = r as i64;
49
50 if !(trunc_f64(r) == r) {
51 debug!("float {r} was truncated to {res}");
52 }
53
54 res
55 }
56 InternalNumber::Integer(i) => i,
57 }
58 }
59
60 pub const fn from_f32(num: f32) -> Self {
62 Self(InternalNumber::Real(num as f64))
63 }
64
65 pub const fn from_i32(num: i32) -> Self {
67 Self(InternalNumber::Integer(num as i64))
68 }
69
70 pub fn is_real(&self) -> bool {
75 matches!(self.0, InternalNumber::Real(_))
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 mut overflowed = false;
127 let mut number_end = None;
128 let negative = match r.peek_byte()? {
129 b'-' => {
130 r.forward();
131 true
132 }
133 b'+' => {
134 r.forward();
135 false
136 }
137 _ => false,
138 };
139
140 let mut mantissa: u64 = 0;
141 let mut has_dot = false;
142 let mut decimal_shift: u32 = 0;
143 let mut has_digits = false;
144
145 loop {
146 match r.peek_byte() {
147 Some(b'0'..=b'9') => {
148 let d = r.read_byte().expect("peek_byte returned Some");
149 if !overflowed {
155 match mantissa
156 .checked_mul(10)
157 .and_then(|v| v.checked_add(u64::from(d - b'0')))
158 {
159 Some(value) => mantissa = value,
160 None => overflowed = true,
161 }
162 }
163 number_end = Some(r.offset());
164 has_digits = true;
165 if has_dot {
166 decimal_shift += 1;
167 }
168 }
169 Some(b'.') if !has_dot => {
170 r.forward();
171 has_dot = true;
172 }
173 Some(b'-') if has_digits => {
175 r.forward();
176 r.forward_while(is_digit_or_minus);
177 break;
178 }
179 _ => break,
180 }
181 }
182
183 if !has_digits {
184 if negative || has_dot {
185 return Some(Number(InternalNumber::Integer(0)));
187 }
188 return None;
189 }
190
191 if r.peek_byte().is_some_and(is_regular_character) {
194 return None;
195 }
196
197 let integer_overflow = !has_dot && mantissa > i64::MAX as u64;
203 if overflowed || integer_overflow {
204 let end_offset = number_end.unwrap_or_else(|| r.offset());
205 let text = core::str::from_utf8(r.range(start_offset..end_offset)?).ok()?;
206
207 if !has_dot && let Ok(value) = text.parse::<i64>() {
208 return Some(Number(InternalNumber::Integer(value)));
209 }
210 let value = text.parse::<f64>().ok()?;
211 return Some(Number(InternalNumber::Real(value)));
212 }
213
214 if !has_dot {
215 let value = if negative {
216 (mantissa as i64).wrapping_neg()
220 } else {
221 mantissa as i64
222 };
223 Some(Number(InternalNumber::Integer(value)))
224 } else {
225 let mut value = mantissa as f64;
226
227 if decimal_shift > 0 {
228 if decimal_shift < POWERS_OF_10.len() as u32 {
229 value /= POWERS_OF_10[decimal_shift as usize];
230 } else {
231 value /= powi_f64(10.0, decimal_shift);
232 }
233 }
234
235 if negative {
236 value = -value;
237 }
238
239 Some(Number(InternalNumber::Real(value)))
240 }
241}
242
243object!(Number, Number);
244
245#[derive(Clone, Copy, Debug, PartialEq)]
246pub(crate) enum InternalNumber {
247 Real(f64),
248 Integer(i64),
249}
250
251macro_rules! int_num {
252 ($i:ident) => {
253 impl Skippable for $i {
254 fn skip(r: &mut Reader<'_>, _: bool) -> Option<()> {
255 r.forward_if(|b| b == b'+' || b == b'-');
256 r.forward_while_1(is_digit)?;
257
258 if r.peek_byte() == Some(b'.') {
260 return None;
261 }
262
263 if r.peek_byte().is_some_and(is_regular_character) {
269 return None;
270 }
271
272 Some(())
273 }
274 }
275
276 impl<'a> Readable<'a> for $i {
277 fn read(r: &mut Reader<'a>, ctx: &ReaderContext<'a>) -> Option<$i> {
278 r.read::<Number>(ctx)
279 .map(|n| n.as_i64())
280 .and_then(|n| n.try_into().ok())
281 }
282 }
283
284 impl TryFrom<Object<'_>> for $i {
285 type Error = ();
286
287 fn try_from(value: Object<'_>) -> core::result::Result<Self, Self::Error> {
288 match value {
289 Object::Number(n) => n.as_i64().try_into().ok().ok_or(()),
290 _ => Err(()),
291 }
292 }
293 }
294
295 impl<'a> ObjectLike<'a> for $i {}
296 };
297}
298
299int_num!(i32);
300int_num!(i64);
301int_num!(u32);
302int_num!(u16);
303int_num!(usize);
304int_num!(u8);
305
306impl Skippable for f32 {
307 fn skip(r: &mut Reader<'_>, is_content_stream: bool) -> Option<()> {
308 r.skip::<Number>(is_content_stream).map(|_| {})
309 }
310}
311
312impl Readable<'_> for f32 {
313 fn read(r: &mut Reader<'_>, _: &ReaderContext<'_>) -> Option<Self> {
314 r.read_without_context::<Number>()
315 .map(|n| n.as_f64() as Self)
316 }
317}
318
319impl TryFrom<Object<'_>> for f32 {
320 type Error = ();
321
322 fn try_from(value: Object<'_>) -> Result<Self, Self::Error> {
323 match value {
324 Object::Number(n) => Ok(n.as_f64() as Self),
325 _ => Err(()),
326 }
327 }
328}
329
330impl ObjectLike<'_> for f32 {}
331
332impl Skippable for f64 {
333 fn skip(r: &mut Reader<'_>, is_content_stream: bool) -> Option<()> {
334 r.skip::<Number>(is_content_stream).map(|_| {})
335 }
336}
337
338impl Readable<'_> for f64 {
339 fn read(r: &mut Reader<'_>, _: &ReaderContext<'_>) -> Option<Self> {
340 r.read_without_context::<Number>().map(|n| n.as_f64())
341 }
342}
343
344impl TryFrom<Object<'_>> for f64 {
345 type Error = ();
346
347 fn try_from(value: Object<'_>) -> Result<Self, Self::Error> {
348 match value {
349 Object::Number(n) => Ok(n.as_f64()),
350 _ => Err(()),
351 }
352 }
353}
354
355impl ObjectLike<'_> for f64 {}
356
357pub(crate) fn is_digit(byte: u8) -> bool {
358 byte.is_ascii_digit()
359}
360
361pub(crate) fn is_digit_or_minus(byte: u8) -> bool {
362 is_digit(byte) || byte == b'-'
363}
364
365#[cfg(test)]
366mod tests {
367 use crate::object::Number;
368 use crate::reader::Reader;
369 use crate::reader::ReaderExt;
370
371 #[test]
372 fn int_1() {
373 assert_eq!(
374 Reader::new("0".as_bytes())
375 .read_without_context::<i32>()
376 .unwrap(),
377 0
378 );
379 }
380
381 #[test]
382 fn int_3() {
383 assert_eq!(
384 Reader::new("+32".as_bytes())
385 .read_without_context::<i32>()
386 .unwrap(),
387 32
388 );
389 }
390
391 #[test]
392 fn int_4() {
393 assert_eq!(
394 Reader::new("-32".as_bytes())
395 .read_without_context::<i32>()
396 .unwrap(),
397 -32
398 );
399 }
400
401 #[test]
402 fn int_6() {
403 assert_eq!(
404 Reader::new("98349".as_bytes())
405 .read_without_context::<i32>()
406 .unwrap(),
407 98349
408 );
409 }
410
411 #[test]
412 fn int_7() {
413 assert_eq!(
414 Reader::new("003245".as_bytes())
415 .read_without_context::<i32>()
416 .unwrap(),
417 3245
418 );
419 }
420
421 #[test]
426 fn int_min_does_not_panic() {
427 assert_eq!(
428 Reader::new("-9223372036854775808".as_bytes())
429 .read_without_context::<i64>()
430 .unwrap(),
431 i64::MIN
432 );
433 }
434
435 #[test]
436 fn real_1() {
437 assert_eq!(
438 Reader::new("3".as_bytes())
439 .read_without_context::<f32>()
440 .unwrap(),
441 3.0
442 );
443 }
444
445 #[test]
446 fn real_3() {
447 assert_eq!(
448 Reader::new("+32".as_bytes())
449 .read_without_context::<f32>()
450 .unwrap(),
451 32.0
452 );
453 }
454
455 #[test]
456 fn real_4() {
457 assert_eq!(
458 Reader::new("-32".as_bytes())
459 .read_without_context::<f32>()
460 .unwrap(),
461 -32.0
462 );
463 }
464
465 #[test]
466 fn real_5() {
467 assert_eq!(
468 Reader::new("-32.01".as_bytes())
469 .read_without_context::<f32>()
470 .unwrap(),
471 -32.01
472 );
473 }
474
475 #[test]
476 fn real_6() {
477 assert_eq!(
478 Reader::new("-.345".as_bytes())
479 .read_without_context::<f32>()
480 .unwrap(),
481 -0.345
482 );
483 }
484
485 #[test]
486 fn real_7() {
487 assert_eq!(
488 Reader::new("-.00143".as_bytes())
489 .read_without_context::<f32>()
490 .unwrap(),
491 -0.00143
492 );
493 }
494
495 #[test]
496 fn real_8() {
497 assert_eq!(
498 Reader::new("-12.0013".as_bytes())
499 .read_without_context::<f32>()
500 .unwrap(),
501 -12.0013
502 );
503 }
504
505 #[test]
506 fn real_9() {
507 assert_eq!(
508 Reader::new("98349.432534".as_bytes())
509 .read_without_context::<f32>()
510 .unwrap(),
511 98_349.43
512 );
513 }
514
515 #[test]
516 fn real_10() {
517 assert_eq!(
518 Reader::new("-34534656.34".as_bytes())
519 .read_without_context::<f32>()
520 .unwrap(),
521 -34534656.34
522 );
523 }
524
525 #[test]
526 fn real_failing() {
527 assert!(
528 Reader::new("+abc".as_bytes())
529 .read_without_context::<f32>()
530 .is_none()
531 );
532 }
533
534 #[test]
535 fn number_1() {
536 assert_eq!(
537 Reader::new("+32".as_bytes())
538 .read_without_context::<Number>()
539 .unwrap()
540 .as_f64() as f32,
541 32.0
542 );
543 }
544
545 #[test]
546 fn number_2() {
547 assert_eq!(
548 Reader::new("-32.01".as_bytes())
549 .read_without_context::<Number>()
550 .unwrap()
551 .as_f64() as f32,
552 -32.01
553 );
554 }
555
556 #[test]
557 fn number_3() {
558 assert_eq!(
559 Reader::new("-.345".as_bytes())
560 .read_without_context::<Number>()
561 .unwrap()
562 .as_f64() as f32,
563 -0.345
564 );
565 }
566
567 #[test]
568 fn large_number() {
569 assert_eq!(
570 Reader::new("38359922".as_bytes())
571 .read_without_context::<Number>()
572 .unwrap()
573 .as_i64(),
574 38359922
575 );
576 }
577
578 #[test]
579 fn large_number_2() {
580 assert_eq!(
581 Reader::new("4294966260".as_bytes())
582 .read_without_context::<u32>()
583 .unwrap(),
584 4294966260
585 );
586 }
587
588 #[test]
594 fn a_number_past_u64_does_not_wrap_into_a_small_one() {
595 let n = Reader::new(b"10000000000000000000000000")
597 .read_without_context::<Number>()
598 .unwrap();
599 let value = n.as_f64();
600 assert!(
601 value > 9.9e24 && value < 1.01e25,
602 "expected about 1e25, got {value}"
603 );
604 }
605
606 #[test]
610 fn int_min_stays_an_integer() {
611 let n = Reader::new(b"-9223372036854775808")
612 .read_without_context::<Number>()
613 .unwrap();
614 assert_eq!(n.as_i64(), i64::MIN);
615 }
616
617 #[test]
619 fn an_ordinary_integer_is_still_an_integer() {
620 let n = Reader::new(b"12345")
621 .read_without_context::<Number>()
622 .unwrap();
623 assert_eq!(n.as_i64(), 12345);
624 }
625}