Skip to main content

scratch_test_value/conversions/
to_number.rs

1use crate::{ARc, QuirkSink, SNumber, SValue};
2
3/// Generated by [`SValue::q_as_number`]
4pub enum SValueToNumberQ {
5    /// [`true`] will be treated as (integer) 1, [`false`] as (integer) 0
6    BoolNotANumber(bool),
7    /// The text is converted to the (integer) number 0
8    TextNotANumber(ARc<str>),
9}
10
11impl SValue {
12    pub fn q_as_number_permissive_bool_text<Q>(&self, sink: &mut Q) -> SNumber
13    where
14        Q: QuirkSink<SValueToNumberQ>,
15    {
16        match self {
17            Self::Bool(b) => {
18                sink.put(SValueToNumberQ::BoolNotANumber(*b));
19                if *b { SNumber::Int(1) } else { SNumber::Int(0) }
20            }
21            Self::Text(t) => {
22                if t.as_ref() == "true" {
23                    sink.put(SValueToNumberQ::BoolNotANumber(true));
24                    SNumber::Int(1)
25                } else if t.as_ref() == "false" {
26                    sink.put(SValueToNumberQ::BoolNotANumber(false));
27                    SNumber::Int(0)
28                } else if let Ok(i) = t.parse() {
29                    SNumber::Int(i)
30                } else if let Ok(f) = t.parse() {
31                    SNumber::Float(f)
32                } else {
33                    sink.put(SValueToNumberQ::TextNotANumber(t.clone()));
34                    SNumber::Int(0)
35                }
36            }
37            Self::Int(i) => SNumber::Int(*i),
38            Self::Float(f) => SNumber::Float(*f),
39        }
40    }
41    pub fn q_as_number<Q>(&self, sink: &mut Q) -> SNumber
42    where
43        Q: QuirkSink<SValueToNumberQ>,
44    {
45        self.q_as_number_strict_bool_text(sink)
46    }
47
48    /// Converts the [`SValue`] to an [`SNumber`]
49    ///
50    /// - The boolean `true` will become integer 1
51    /// - The boolean `false` will become integer 0
52    /// - Any text (also the strings `"true"`, `"false"`) will become integer 0
53    /// - Integers will stay as they are
54    /// - Floats will stay as they are
55    pub fn q_as_number_strict_bool_text<Q>(&self, sink: &mut Q) -> SNumber
56    where
57        Q: QuirkSink<SValueToNumberQ>,
58    {
59        match self {
60            Self::Bool(b) => {
61                sink.put(SValueToNumberQ::BoolNotANumber(*b));
62                if *b { SNumber::Int(1) } else { SNumber::Int(0) }
63            }
64            Self::Text(t) => {
65                if let Ok(i) = t.parse() {
66                    SNumber::Int(i)
67                } else if let Ok(f) = t.parse() {
68                    SNumber::Float(f)
69                } else {
70                    sink.put(SValueToNumberQ::TextNotANumber(t.clone()));
71                    SNumber::Int(0)
72                }
73            }
74            Self::Int(i) => SNumber::Int(*i),
75            Self::Float(f) => SNumber::Float(*f),
76        }
77    }
78}
79
80impl SNumber {
81    pub fn int_or_border<Q>(&self, sink: &mut Q) -> i64
82    where
83        Q: QuirkSink<NumberTooBigForIntQ>,
84    {
85        match self {
86            Self::Int(i) => *i,
87            Self::Float(f) => {
88                if !((f.is_sign_positive() && *f <= (i64::MAX as f64))
89                    || (f.is_sign_negative() && *f >= (i64::MIN as f64)))
90                {
91                    sink.put(NumberTooBigForIntQ(*f));
92                }
93                *f as i64
94            }
95        }
96    }
97}
98
99#[allow(unused)]
100pub struct NumberTooBigForIntQ(f64);