1use {
5    super::{CssNumber, CssNumberNewType},
6    crate::{
7        domain,
8        domain::{
9            expressions::{
10                CalcExpression,
11                CalculablePropertyValue::{self, *},
12                FunctionParser,
13            },
14            units::{
15                conversions::*,
16                AppUnitsPer,
17                PercentageUnit,
18                Unit,
19                UnitFromStrError,
20            },
21        },
22        parsers::ParserContext,
23        CustomParseError,
24    },
25    cssparser::{ParseError, Parser, ParserInput, ToCss, Token},
26    either::{Either, Left},
27    std::{
28        cmp::Ordering,
29        fmt::{self, Display, Formatter, LowerExp, UpperExp},
30        hash::{Hash, Hasher},
31        ops::{Deref, *},
32        str::FromStr,
33    },
34};
35
36#[derive(Debug, Copy, Clone)]
38pub struct CssUnsignedNumber(f32);
39
40impl Eq for CssUnsignedNumber {}
41
42impl PartialEq for CssUnsignedNumber {
43    #[inline(always)]
44    fn eq(&self, other: &Self) -> bool {
45        self.to_f32().eq(&other.0)
46    }
47}
48
49impl PartialOrd for CssUnsignedNumber {
50    #[inline(always)]
51    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
52        self.to_f32().partial_cmp(&other.0)
53    }
54}
55
56impl Ord for CssUnsignedNumber {
57    #[inline(always)]
58    fn cmp(&self, other: &Self) -> Ordering {
59        self.partial_cmp(other).unwrap_or(Ordering::Equal)
60    }
61}
62
63impl Hash for CssUnsignedNumber {
64    #[inline(always)]
65    fn hash<H: Hasher>(&self, state: &mut H) {
66        self.to_bits().hash(state)
67    }
68}
69
70impl ToCss for CssUnsignedNumber {
71    #[inline(always)]
72    fn to_css<W: fmt::Write>(&self, dest: &mut W) -> fmt::Result {
73        self.to_f32().to_css(dest)
74    }
75}
76
77impl Display for CssUnsignedNumber {
78    #[inline(always)]
79    fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
80        <f32 as Display>::fmt(&self.to_f32(), fmt)
81    }
82}
83
84impl LowerExp for CssUnsignedNumber {
85    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
86        <f32 as LowerExp>::fmt(&self.to_f32(), f)
87    }
88}
89
90impl UpperExp for CssUnsignedNumber {
91    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
92        <f32 as UpperExp>::fmt(&self.to_f32(), f)
93    }
94}
95
96impl Default for CssUnsignedNumber {
97    #[inline(always)]
98    fn default() -> Self {
99        Self::Zero
100    }
101}
102
103impl Add<CssUnsignedNumber> for CssUnsignedNumber {
104    type Output = Self;
105
106    #[inline(always)]
107    fn add(self, rhs: CssUnsignedNumber) -> Self::Output {
108        <Self as domain::numbers::CssNumber>::clamp(self.to_f32() + rhs.0)
109    }
110}
111
112impl AddAssign<CssUnsignedNumber> for CssUnsignedNumber {
113    #[inline(always)]
114    fn add_assign(&mut self, rhs: CssUnsignedNumber) {
115        *self = self.add(rhs)
116    }
117}
118
119impl Sub<CssUnsignedNumber> for CssUnsignedNumber {
120    type Output = Self;
121
122    #[inline(always)]
123    fn sub(self, rhs: CssUnsignedNumber) -> Self::Output {
124        <Self as domain::numbers::CssNumber>::clamp(self.to_f32() - rhs.0)
125    }
126}
127
128impl SubAssign<CssUnsignedNumber> for CssUnsignedNumber {
129    #[inline(always)]
130    fn sub_assign(&mut self, rhs: CssUnsignedNumber) {
131        *self = self.sub(rhs)
132    }
133}
134
135impl Mul<CssUnsignedNumber> for CssUnsignedNumber {
136    type Output = Self;
137
138    #[inline(always)]
139    fn mul(self, rhs: CssUnsignedNumber) -> Self::Output {
140        <Self as domain::numbers::CssNumber>::clamp(self.to_f32() * rhs.0)
141    }
142}
143
144impl MulAssign<CssUnsignedNumber> for CssUnsignedNumber {
145    #[inline(always)]
146    fn mul_assign(&mut self, rhs: CssUnsignedNumber) {
147        *self = self.mul(rhs)
148    }
149}
150
151impl Div<CssUnsignedNumber> for CssUnsignedNumber {
152    type Output = Self;
153
154    #[inline(always)]
155    fn div(self, rhs: CssUnsignedNumber) -> Self::Output {
156        if rhs.0.is_nan() {
157            let value = if (self.to_f32() / rhs.0).is_sign_positive() {
158                ::std::f32::MAX
159            } else {
160                ::std::f32::MIN
161            };
162            CssUnsignedNumber(value)
163        } else {
164            <Self as domain::numbers::CssNumber>::clamp(self.to_f32() / rhs.0)
165        }
166    }
167}
168
169impl DivAssign<CssUnsignedNumber> for CssUnsignedNumber {
170    #[inline(always)]
171    fn div_assign(&mut self, rhs: CssUnsignedNumber) {
172        *self = self.div(rhs)
173    }
174}
175
176impl Rem<CssUnsignedNumber> for CssUnsignedNumber {
177    type Output = Self;
178
179    #[inline(always)]
180    fn rem(self, rhs: CssUnsignedNumber) -> Self::Output {
181        if rhs.0.is_nan() {
182            let value = if (self.to_f32() % rhs.0).is_sign_positive() {
183                ::std::f32::MAX
184            } else {
185                ::std::f32::MIN
186            };
187            CssUnsignedNumber(value)
188        } else {
189            <Self as domain::numbers::CssNumber>::clamp(self.to_f32() % rhs.0)
190        }
191    }
192}
193
194impl RemAssign<CssUnsignedNumber> for CssUnsignedNumber {
195    #[inline(always)]
196    fn rem_assign(&mut self, rhs: CssUnsignedNumber) {
197        *self = self.rem(rhs)
198    }
199}
200
201impl Neg for CssUnsignedNumber {
202    type Output = Self;
203
204    #[inline(always)]
205    fn neg(self) -> Self::Output {
206        if self.is_zero() {
207            self
208        } else {
209            CssUnsignedNumber(-self.to_f32())
210        }
211    }
212}
213
214impl CssNumberNewType<Self> for CssUnsignedNumber {
215    #[inline(always)]
216    fn to_f32(&self) -> f32 {
217        self.0
218    }
219
220    #[inline(always)]
221    fn as_CssNumber(&self) -> &CssUnsignedNumber {
222        self
223    }
224}
225
226impl Deref for CssUnsignedNumber {
227    type Target = f32;
228
229    #[inline(always)]
230    fn deref(&self) -> &Self::Target {
231        &self.0
232    }
233}
234
235impl From<u16> for CssUnsignedNumber {
236    #[inline(always)]
237    fn from(small: u16) -> CssUnsignedNumber {
238        CssUnsignedNumber(small as f32)
239    }
240}
241
242impl From<i16> for CssUnsignedNumber {
243    #[inline(always)]
244    fn from(small: i16) -> CssUnsignedNumber {
245        CssUnsignedNumber(small as f32)
246    }
247}
248
249impl From<u8> for CssUnsignedNumber {
250    #[inline(always)]
251    fn from(small: u8) -> CssUnsignedNumber {
252        CssUnsignedNumber(small as f32)
253    }
254}
255
256impl From<i8> for CssUnsignedNumber {
257    #[inline(always)]
258    fn from(small: i8) -> CssUnsignedNumber {
259        CssUnsignedNumber(small as f32)
260    }
261}
262
263impl FromStr for CssUnsignedNumber {
264    type Err = UnitFromStrError;
265
266    fn from_str(s: &str) -> Result<Self, Self::Err> {
267        let value = f32::from_str(s)?;
268        Ok(CssUnsignedNumber::new(value)?)
269    }
270}
271
272impl CssNumber for CssUnsignedNumber {
273    const Zero: Self = CssUnsignedNumber(0.0);
274
275    const One: Self = CssUnsignedNumber(1.0);
276
277    const Maximum: Self = CssUnsignedNumber(::std::f32::MAX);
278
279    const Minimum: Self = CssUnsignedNumber(::std::f32::MIN);
280
281    const DotsPerInch: Self = CssUnsignedNumber(96.0);
282
283    const CentimetresPerInch: Self = CssUnsignedNumber(2.54);
284
285    #[inline(always)]
286    fn as_f32(&self) -> f32 {
287        self.0
288    }
289
290    #[inline(always)]
291    fn as_u32(&self) -> u32 {
292        self.0 as u32
293    }
294
295    #[inline(always)]
296    fn abs(self) -> Self {
297        self
298    }
299
300    #[doc(hidden)]
301    #[inline(always)]
302    fn _construct(value: f32) -> Self {
303        CssUnsignedNumber(value)
304    }
305
306    #[inline(always)]
307    fn parseNumber<'i>(
308        value: f32,
309        _int_value: Option<i32>,
310    ) -> Result<Self, ParseError<'i, CustomParseError<'i>>> {
311        CssUnsignedNumber::new(value).map_err(|cssNumberConversionError| {
312            ParseError::from(CustomParseError::CouldNotParseCssSignedNumber(
313                cssNumberConversionError,
314                value,
315            ))
316        })
317    }
318}
319
320impl AppUnitsPer for CssUnsignedNumber {
321    const AppUnitsPerPX: Self = CssUnsignedNumber(f32::AppUnitsPerPX);
323
324    const AppUnitsPerIN: Self = CssUnsignedNumber(f32::AppUnitsPerIN);
326
327    const AppUnitsPerCM: Self = CssUnsignedNumber(f32::AppUnitsPerCM);
329
330    const AppUnitsPerMM: Self = CssUnsignedNumber(f32::AppUnitsPerMM);
332
333    const AppUnitsPerQ: Self = CssUnsignedNumber(f32::AppUnitsPerQ);
335
336    const AppUnitsPerPT: Self = CssUnsignedNumber(f32::AppUnitsPerPT);
338
339    const AppUnitsPerPC: Self = CssUnsignedNumber(f32::AppUnitsPerPC);
341}
342
343impl Unit for CssUnsignedNumber {
344    type Number = Self;
345
346    const HasDimension: bool = false;
347
348    #[inline(always)]
349    fn parse_one_outside_calc_function<'i, 't>(
350        context: &ParserContext,
351        input: &mut Parser<'i, 't>,
352    ) -> Result<
353        CalculablePropertyValue<Self>,
354        ParseError<'i, CustomParseError<'i>>,
355    > {
356        let functionParser = match *input.next()? {
357            Token::Number {
358                value, int_value, ..
359            } => return Self::parseNumber(value, int_value).map(Constant),
360
361            Token::Function(ref name) => FunctionParser::parser(name)?,
362
363            ref unexpectedToken => {
364                return CustomParseError::unexpectedToken(unexpectedToken)
365            }
366        };
367        functionParser.parse_one_outside_calc_function(context, input)
368    }
369
370    #[inline(always)]
371    fn parse_one_inside_calc_function<'i, 't>(
372        context: &ParserContext,
373        input: &mut Parser<'i, 't>,
374    ) -> Result<
375        Either<CalculablePropertyValue<Self>, CalcExpression<Self>>,
376        ParseError<'i, CustomParseError<'i>>,
377    > {
378        let functionParser = match *input.next()? {
379            Token::Number {
380                value, int_value, ..
381            } => {
382                return Self::parseNumber(value, int_value)
383                    .map(|value| Left(Constant(value)))
384            }
385
386            Token::Percentage { unit_value, .. } => {
387                return PercentageUnit::parse_percentage(unit_value)
388                    .map(|value| Left(Percentage(value)))
389            }
390
391            Token::ParenthesisBlock => FunctionParser::parentheses,
392
393            Token::Function(ref name) => FunctionParser::parser(name)?,
394
395            ref unexpectedToken => {
396                return CustomParseError::unexpectedToken(unexpectedToken)
397            }
398        };
399        functionParser.parse_one_inside_calc_function(context, input)
400    }
401
402    #[inline(always)]
403    fn to_canonical_dimension_value<
404        Conversion: FontRelativeLengthConversion<Self::Number>
405            + ViewportPercentageLengthConversion<Self::Number>
406            + PercentageConversion<Self::Number>,
407    >(
408        &self,
409        _conversion: &Conversion,
410    ) -> Self::Number {
411        self.to_CssNumber()
412    }
413
414    #[inline(always)]
415    fn from_raw_css_for_var_expression_evaluation(
416        value: &str,
417        _is_not_in_page_rule: bool,
418    ) -> Option<Self> {
419        fn from_raw_css_for_var_expression_evaluation_internal<'i: 't, 't>(
420            input: &mut Parser<'i, 't>,
421        ) -> Result<CssUnsignedNumber, ParseError<'i, CustomParseError<'i>>>
422        {
423            let value = match *input.next()? {
424                Token::Number {
425                    value, int_value, ..
426                } => CssUnsignedNumber::parseNumber(value, int_value),
427
428                ref unexpectedToken => {
429                    CustomParseError::unexpectedToken(unexpectedToken)
430                }
431            };
432
433            input.skip_whitespace();
434
435            input.expect_exhausted()?;
436
437            value
438        }
439
440        const LineNumberingIsZeroBased: u32 = 0;
441
442        let mut parserInput = ParserInput::new_with_line_number_offset(
443            value,
444            LineNumberingIsZeroBased,
445        );
446        let mut input = Parser::new(&mut parserInput);
447
448        from_raw_css_for_var_expression_evaluation_internal(&mut input).ok()
449    }
450}