lewp_css/domain/numbers/
css_unsigned_integer.rs

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