Skip to main content

style/typed_om/
numeric_values.rs

1/* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
4
5//! Typed OM Numeric Values.
6
7use crate::derives::*;
8use crate::values::specified::{
9    NoCalcAngle, NoCalcLength, NoCalcNumber, NoCalcPercentage, NoCalcTime,
10};
11use crate::values::CSSFloat;
12use cssparser::match_ignore_ascii_case;
13use style_traits::ParsingMode;
14
15/// A numeric value without a `calc` expression.
16#[derive(Clone, ToTyped)]
17#[repr(u8)]
18pub enum NoCalcNumeric {
19    /// A `<length>` value.
20    ///
21    /// <https://drafts.csswg.org/css-values/#lengths>
22    Length(NoCalcLength),
23
24    /// An `<angle>` value.
25    ///
26    /// https://drafts.csswg.org/css-values/#angles
27    Angle(NoCalcAngle),
28
29    /// A `<time>` value.
30    ///
31    /// <https://drafts.csswg.org/css-values/#time>
32    Time(NoCalcTime),
33
34    /// A `<number>` value.
35    ///
36    /// <https://drafts.csswg.org/css-values/#number-value>
37    Number(NoCalcNumber),
38
39    /// A `<percentage>` value.
40    ///
41    /// <https://drafts.csswg.org/css-values/#percentages>
42    Percentage(NoCalcPercentage),
43    // TODO: Add other values.
44}
45
46impl NoCalcNumeric {
47    /// Return the unitless, raw value.
48    pub fn unitless_value(&self) -> CSSFloat {
49        match *self {
50            Self::Length(v) => v.unitless_value(),
51            Self::Angle(v) => v.unitless_value(),
52            Self::Time(v) => v.unitless_value(),
53            Self::Number(v) => v.get(),
54            Self::Percentage(v) => v.get(),
55        }
56    }
57
58    /// Return the unit, as a string.
59    ///
60    /// TODO: Investigate returning SortKey or adding a new variant for
61    /// returning the unit as SortKey. Tracked in
62    /// <https://bugzilla.mozilla.org/show_bug.cgi?id=2015863>
63    pub fn unit(&self) -> &'static str {
64        match *self {
65            Self::Length(v) => v.unit(),
66            Self::Angle(v) => v.unit(),
67            Self::Time(v) => v.unit(),
68            Self::Number(v) => v.unit(),
69            Self::Percentage(v) => v.unit(),
70        }
71    }
72
73    /// Return the canonical unit for this value, if one exists.
74    ///
75    /// TODO: Investigate returning SortKey. Tracked in
76    /// <https://bugzilla.mozilla.org/show_bug.cgi?id=2015863>
77    pub fn canonical_unit(&self) -> Option<&'static str> {
78        match *self {
79            Self::Length(v) => v.canonical_unit(),
80            Self::Angle(v) => v.canonical_unit(),
81            Self::Time(v) => v.canonical_unit(),
82            Self::Number(v) => v.canonical_unit(),
83            Self::Percentage(v) => v.canonical_unit(),
84        }
85    }
86
87    /// Convert this value to the specified unit, if possible.
88    ///
89    /// TODO: Investigate using SortKey. Tracked in
90    /// <https://bugzilla.mozilla.org/show_bug.cgi?id=2015863>
91    pub fn to(&self, unit: &str) -> Result<Self, ()> {
92        match self {
93            Self::Length(v) => Ok(Self::Length(v.to(unit)?)),
94            Self::Angle(v) => Ok(Self::Angle(v.to(unit)?)),
95            Self::Time(v) => Ok(Self::Time(v.to(unit)?)),
96            Self::Number(v) => Ok(Self::Number(v.to(unit)?)),
97            Self::Percentage(v) => Ok(Self::Percentage(v.to(unit)?)),
98        }
99    }
100
101    /// Parse a given unit value.
102    pub fn parse_unit_value(value: CSSFloat, unit: &str) -> Result<Self, ()> {
103        if let Ok(length) = NoCalcLength::parse_dimension_with_flags(
104            ParsingMode::DEFAULT,
105            /* in_page_rule = */ false,
106            value,
107            unit,
108        ) {
109            return Ok(NoCalcNumeric::Length(length));
110        }
111
112        if let Ok(angle) = NoCalcAngle::parse_dimension(value, unit) {
113            return Ok(NoCalcNumeric::Angle(angle));
114        }
115
116        if let Ok(time) = NoCalcTime::parse_dimension(value, unit) {
117            return Ok(NoCalcNumeric::Time(time));
118        }
119
120        match_ignore_ascii_case! { unit,
121            "number" => Ok(NoCalcNumeric::Number(NoCalcNumber::new(value))),
122            "percent" => Ok(NoCalcNumeric::Percentage(NoCalcPercentage::new(value))),
123            _ => Err(()),
124        }
125
126        // TODO: Add support for other values.
127    }
128}