1use {
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#[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 const AppUnitsPerPX: Self = CssUnsignedInteger(f32::AppUnitsPerPX as u32);
309
310 const AppUnitsPerIN: Self = CssUnsignedInteger(f32::AppUnitsPerIN as u32);
312
313 const AppUnitsPerCM: Self = CssUnsignedInteger(f32::AppUnitsPerCM as u32);
315
316 const AppUnitsPerMM: Self = CssUnsignedInteger(f32::AppUnitsPerMM as u32);
318
319 const AppUnitsPerQ: Self = CssUnsignedInteger(f32::AppUnitsPerQ as u32);
321
322 const AppUnitsPerPT: Self = CssUnsignedInteger(f32::AppUnitsPerPT as u32);
324
325 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}