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}