Skip to main content

whisker_css/data_type/
angle.rs

1//! `<angle>` — a rotational quantity.
2//!
3//! Lynx reference: <https://lynxjs.org/api/css/data-type/angle.html>
4//!
5//! Lynx supports three of the four CSS angle units:
6//!
7//! | Variant | CSS | Notes |
8//! |---|---|---|
9//! | [`Angle::Deg`]  | `deg`  | 360 degrees per full turn |
10//! | [`Angle::Rad`]  | `rad`  | 2π radians per full turn |
11//! | [`Angle::Turn`] | `turn` | One full revolution |
12//!
13//! **`grad` is not supported by Lynx** and is intentionally absent.
14
15use core::fmt;
16
17use crate::to_css::{write_number, ToCss};
18
19/// A CSS `<angle>` value.
20#[derive(Copy, Clone, Debug, PartialEq)]
21pub enum Angle {
22    /// Degrees (`deg`). 360 per full turn.
23    Deg(f32),
24    /// Radians (`rad`). 2π per full turn.
25    Rad(f32),
26    /// Turns (`turn`). One full revolution.
27    Turn(f32),
28}
29
30impl Angle {
31    /// Convenience zero-degree constant.
32    pub const ZERO: Self = Self::Deg(0.0);
33}
34
35impl ToCss for Angle {
36    fn to_css(&self, dest: &mut dyn fmt::Write) -> fmt::Result {
37        let (v, unit) = match *self {
38            Angle::Deg(v) => (v, "deg"),
39            Angle::Rad(v) => (v, "rad"),
40            Angle::Turn(v) => (v, "turn"),
41        };
42        write_number(dest, v)?;
43        dest.write_str(unit)
44    }
45}
46
47#[cfg(test)]
48mod tests {
49    use super::*;
50
51    #[test]
52    fn each_unit_serializes() {
53        assert_eq!(Angle::Deg(45.0).to_css_string(), "45deg");
54        // Hand-picked value (not a π approximation) so the string
55        // assertion stays away from `clippy::approx_constant`.
56        assert_eq!(Angle::Rad(1.25).to_css_string(), "1.25rad");
57        assert_eq!(Angle::Turn(0.25).to_css_string(), "0.25turn");
58    }
59
60    #[test]
61    fn zero_constant() {
62        assert_eq!(Angle::ZERO.to_css_string(), "0deg");
63    }
64
65    #[test]
66    fn negative_angles() {
67        assert_eq!(Angle::Deg(-90.0).to_css_string(), "-90deg");
68    }
69}