//! CSS number values. use super::angle::impl_try_from_angle; use super::calc::Calc; use crate::error::{ParserError, PrinterError}; use crate::printer::Printer; use crate::traits::private::AddInternal; use crate::traits::{Map, Op, Parse, Sign, ToCss, Zero}; use cssparser::*; /// A CSS [``](https://www.w3.org/TR/css-values-4/#numbers) value. /// /// Numbers may be explicit or computed by `calc()`, but are always stored and serialized /// as their computed value. pub type CSSNumber = f32; impl<'i> Parse<'i> for CSSNumber { fn parse<'t>(input: &mut Parser<'i, 't>) -> Result>> { match input.try_parse(Calc::parse) { Ok(Calc::Value(v)) => return Ok(*v), Ok(Calc::Number(n)) => return Ok(n), // Numbers are always compatible, so they will always compute to a value. Ok(_) => return Err(input.new_custom_error(ParserError::InvalidValue)), _ => {} } let number = input.expect_number()?; Ok(number) } } impl ToCss for CSSNumber { fn to_css(&self, dest: &mut Printer) -> Result<(), PrinterError> where W: std::fmt::Write, { let number = *self; if number != 0.0 && number.abs() < 1.0 { let mut s = String::new(); cssparser::ToCss::to_css(self, &mut s)?; if number < 0.0 { dest.write_char('-')?; dest.write_str(s.trim_start_matches("-").trim_start_matches("0")) } else { dest.write_str(s.trim_start_matches('0')) } } else { cssparser::ToCss::to_css(self, dest)?; Ok(()) } } } impl std::convert::Into> for CSSNumber { fn into(self) -> Calc { Calc::Value(Box::new(self)) } } impl std::convert::From> for CSSNumber { fn from(calc: Calc) -> CSSNumber { match calc { Calc::Value(v) => *v, Calc::Number(n) => n, _ => unreachable!(), } } } impl AddInternal for CSSNumber { fn add(self, other: Self) -> Self { self + other } } impl Op for CSSNumber { fn op f32>(&self, to: &Self, op: F) -> Self { op(*self, *to) } fn op_to T>(&self, rhs: &Self, op: F) -> T { op(*self, *rhs) } } impl Map for CSSNumber { fn map f32>(&self, op: F) -> Self { op(*self) } } impl Sign for CSSNumber { fn sign(&self) -> f32 { if *self == 0.0 { return if f32::is_sign_positive(*self) { 0.0 } else { -0.0 }; } self.signum() } } impl Zero for CSSNumber { fn zero() -> Self { 0.0 } fn is_zero(&self) -> bool { *self == 0.0 } } impl_try_from_angle!(CSSNumber); /// A CSS [``](https://www.w3.org/TR/css-values-4/#integers) value. pub type CSSInteger = i32; impl<'i> Parse<'i> for CSSInteger { fn parse<'t>(input: &mut Parser<'i, 't>) -> Result>> { // TODO: calc?? let integer = input.expect_integer()?; Ok(integer) } } impl ToCss for CSSInteger { fn to_css(&self, dest: &mut Printer) -> Result<(), PrinterError> where W: std::fmt::Write, { cssparser::ToCss::to_css(self, dest)?; Ok(()) } } impl Zero for CSSInteger { fn zero() -> Self { 0 } fn is_zero(&self) -> bool { *self == 0 } }