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