use super::prelude::*;
use crate::{Exact, Flex, Percentage};
macro_rules! apply_lengths {
($ident: ident) => {
$ident! {
Em,
Rem,
Ex,
Rex,
Cap,
Rcap,
Ch,
Rch,
Ic,
Ric,
Lh,
Rlh,
Vw,
Svw,
Lvw,
Dvw,
Vh,
Svh,
Lvh,
Dvh,
Vi,
Svi,
Lvi,
Dvi,
Vb,
Svb,
Lvb,
Dvb,
Vmin,
Svmin,
Lvmin,
Dvmin,
Vmax,
Svmax,
Lvmax,
Dvmax,
Cm,
Mm,
Q,
In,
Pc,
Pt,
Px,
Cqw,
Cqh,
Cqi,
Cqb,
Cqmin,
Cqmax,
}
};
}
macro_rules! define_length {
( $($name: ident),+ $(,)* ) => {
#[derive(Parse, Peek, IntoCursor, ToCursors, Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
#[cfg_attr(feature = "visitable", derive(csskit_derives::Visitable), visit(self))]
#[derive(csskit_derives::NodeWithMetadata)]
#[metadata(node_kinds = Dimension)]
pub enum Length {
Zero(Exact<T![Number], 0>),
$(
#[atom(CssAtomSet::$name)]
$name(T![Dimension]),
)+
}
}
}
apply_lengths!(define_length);
impl Length {
const PX_CM: f32 = Self::PX_IN / 2.54;
const PX_MM: f32 = Self::PX_IN / 25.4;
const PX_Q: f32 = Self::PX_MM / 4.0;
const PX_IN: f32 = 96.0;
const PX_PC: f32 = Self::PX_IN / 6.0;
const PX_PT: f32 = Self::PX_IN / 72.0;
pub fn to_px(&self) -> Option<f32> {
match self {
Self::Zero(_) => Some(0.0),
Self::Cm(d) => Some(Into::<f32>::into(*d) * Self::PX_CM),
Self::Mm(d) => Some(Into::<f32>::into(*d) * Self::PX_MM),
Self::Q(d) => Some(Into::<f32>::into(*d) * Self::PX_Q),
Self::In(d) => Some(Into::<f32>::into(*d) * Self::PX_IN),
Self::Pc(d) => Some(Into::<f32>::into(*d) * Self::PX_PC),
Self::Pt(d) => Some(Into::<f32>::into(*d) * Self::PX_PT),
_ => None,
}
}
}
impl From<Length> for f32 {
fn from(val: Length) -> Self {
macro_rules! match_length {
( $($name: ident),+ $(,)* ) => {
match val {
Length::Zero(_) => 0.0,
$(Length::$name(f) => f.into()),+
}
}
}
apply_lengths!(match_length)
}
}
impl PartialEq<f32> for Length {
fn eq(&self, other: &f32) -> bool {
let f: f32 = (*self).into();
f == *other
}
}
impl ToNumberValue for Length {
fn to_number_value(&self) -> Option<f32> {
Some((*self).into())
}
}
#[derive(Parse, Peek, IntoCursor, ToCursors, Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
#[cfg_attr(feature = "visitable", derive(csskit_derives::Visitable), visit)]
#[derive(csskit_derives::NodeWithMetadata)]
pub enum LengthPercentage {
#[cfg_attr(feature = "visitable", visit(skip))]
Zero(Exact<T![Number], 0>),
Length(Length),
#[cfg_attr(feature = "visitable", visit(skip))]
Percent(Percentage),
}
impl From<LengthPercentage> for f32 {
fn from(val: LengthPercentage) -> Self {
match val {
LengthPercentage::Zero(_) => 0.0,
LengthPercentage::Percent(f) => f.into(),
LengthPercentage::Length(f) => f.into(),
}
}
}
impl ToNumberValue for LengthPercentage {
fn to_number_value(&self) -> Option<f32> {
Some((*self).into())
}
}
#[derive(Parse, Peek, IntoCursor, ToCursors, Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
#[cfg_attr(feature = "visitable", derive(csskit_derives::Visitable), visit)]
#[derive(csskit_derives::NodeWithMetadata)]
pub enum LengthPercentageNumber {
Length(Length),
#[cfg_attr(feature = "visitable", visit(skip))]
Percent(Percentage),
#[cfg_attr(feature = "visitable", visit(skip))]
Number(T![Number]),
}
impl From<LengthPercentageNumber> for f32 {
fn from(val: LengthPercentageNumber) -> Self {
match val {
LengthPercentageNumber::Length(f) => f.into(),
LengthPercentageNumber::Percent(f) => f.into(),
LengthPercentageNumber::Number(f) => f.into(),
}
}
}
impl ToNumberValue for LengthPercentageNumber {
fn to_number_value(&self) -> Option<f32> {
Some((*self).into())
}
}
#[derive(Parse, Peek, IntoCursor, ToCursors, Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
#[cfg_attr(feature = "visitable", derive(csskit_derives::Visitable), visit(children))]
#[derive(csskit_derives::NodeWithMetadata)]
pub enum LengthPercentageOrFlex {
Flex(Flex),
LengthPercentage(LengthPercentage),
}
impl From<LengthPercentageOrFlex> for f32 {
fn from(val: LengthPercentageOrFlex) -> Self {
match val {
LengthPercentageOrFlex::Flex(f) => f.into(),
LengthPercentageOrFlex::LengthPercentage(l) => l.into(),
}
}
}
impl ToNumberValue for LengthPercentageOrFlex {
fn to_number_value(&self) -> Option<f32> {
Some((*self).into())
}
}
#[derive(Parse, Peek, ToCursors, IntoCursor, Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
#[cfg_attr(feature = "visitable", derive(csskit_derives::Visitable), visit)]
#[derive(csskit_derives::NodeWithMetadata)]
pub enum NumberLength {
#[cfg_attr(feature = "visitable", visit(skip))]
Number(T![Number]),
Length(Length),
}
impl From<NumberLength> for f32 {
fn from(val: NumberLength) -> Self {
match val {
NumberLength::Number(n) => n.into(),
NumberLength::Length(n) => n.into(),
}
}
}
impl ToNumberValue for NumberLength {
fn to_number_value(&self) -> Option<f32> {
Some((*self).into())
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::CssAtomSet;
use css_parse::assert_parse;
#[test]
fn size_test() {
assert_eq!(std::mem::size_of::<Length>(), 16);
assert_eq!(std::mem::size_of::<LengthPercentage>(), 16);
assert_eq!(std::mem::size_of::<NumberLength>(), 16);
}
#[test]
fn test_writes() {
assert_parse!(CssAtomSet::ATOMS, Length, "10px");
assert_parse!(CssAtomSet::ATOMS, Length, "1.2345679px");
assert_parse!(CssAtomSet::ATOMS, Length, "-1px");
assert_parse!(CssAtomSet::ATOMS, LengthPercentage, "1%");
}
}