silex_css 0.1.0-beta.3

Next Generation High-Performance Rust Web Framework based on fine-grained reactivity and no-virtual-DOM architecture.
Documentation
use crate::types::units::{Deg, Em, Percent, Px, Rad, Rem, Turn, Vh, Vw};
use std::fmt::Display;
use std::marker::PhantomData;

// ==========================================
// 核心标记 Trait 与 量纲 (Marks & Marker Traits)
// ==========================================

#[derive(Clone, Copy, Debug, PartialEq)]
pub struct LengthMark;
#[derive(Clone, Copy, Debug, PartialEq)]
pub struct AngleMark;
#[derive(Clone, Copy, Debug, PartialEq)]
pub struct NumberMark;
#[derive(Clone, Copy, Debug, PartialEq)]
pub struct ColorMark;

pub trait CssLength: Display {}
pub trait CssAngle: Display {}
pub trait CssColor: Display {}
pub trait CssNumber: Display {}
pub trait CssPercentage: Display {}

#[derive(Clone, Debug, PartialEq)]
pub struct CalcValue<Mark>(pub String, pub PhantomData<Mark>);

impl<Mark> CalcValue<Mark> {
    pub fn new(s: String) -> Self {
        Self(s, PhantomData)
    }
    pub fn binary<L: Display, R: Display>(l: L, op: &'static str, r: R) -> Self {
        Self(format!("({} {} {})", l, op, r), PhantomData)
    }
}

impl<Mark> Display for CalcValue<Mark> {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        write!(f, "{}", self.0)
    }
}

impl CssLength for CalcValue<LengthMark> {}
impl CssAngle for CalcValue<AngleMark> {}

impl<Mark> From<CalcValue<Mark>> for String {
    fn from(v: CalcValue<Mark>) -> Self {
        v.0
    }
}

pub fn calc<Mark>(v: CalcValue<Mark>) -> CalcValue<Mark> {
    CalcValue::new(format!("calc({})", v.0))
}

pub fn min<Mark, T, I>(args: I) -> CalcValue<Mark>
where
    I: IntoIterator<Item = T>,
    T: Into<CalcValue<Mark>>,
{
    let mut s = String::from("min(");
    for (i, arg) in args.into_iter().enumerate() {
        if i > 0 {
            s.push_str(", ");
        }
        let v: CalcValue<Mark> = arg.into();
        s.push_str(&v.0);
    }
    s.push(')');
    CalcValue::new(s)
}

pub fn max<Mark, T, I>(args: I) -> CalcValue<Mark>
where
    I: IntoIterator<Item = T>,
    T: Into<CalcValue<Mark>>,
{
    let mut s = String::from("max(");
    for (i, arg) in args.into_iter().enumerate() {
        if i > 0 {
            s.push_str(", ");
        }
        let v: CalcValue<Mark> = arg.into();
        s.push_str(&v.0);
    }
    s.push(')');
    CalcValue::new(s)
}

pub fn clamp<Mark, T>(min_v: T, val: T, max_v: T) -> CalcValue<Mark>
where
    T: Into<CalcValue<Mark>> + Display,
{
    CalcValue::new(format!("clamp({}, {}, {})", min_v, val, max_v))
}

pub trait IntoCalc<Mark> {
    fn into_calc(self) -> CalcValue<Mark>;
}

impl<T: Display> IntoCalc<LengthMark> for T {
    fn into_calc(self) -> CalcValue<LengthMark> {
        CalcValue::new(self.to_string())
    }
}

impl IntoCalc<AngleMark> for Deg {
    fn into_calc(self) -> CalcValue<AngleMark> {
        CalcValue::new(self.to_string())
    }
}
impl IntoCalc<AngleMark> for Rad {
    fn into_calc(self) -> CalcValue<AngleMark> {
        CalcValue::new(self.to_string())
    }
}
impl IntoCalc<AngleMark> for Turn {
    fn into_calc(self) -> CalcValue<AngleMark> {
        CalcValue::new(self.to_string())
    }
}
impl IntoCalc<AngleMark> for CalcValue<AngleMark> {
    fn into_calc(self) -> CalcValue<AngleMark> {
        self
    }
}

impl From<Deg> for CalcValue<AngleMark> {
    fn from(v: Deg) -> Self {
        v.into_calc()
    }
}
impl From<Rad> for CalcValue<AngleMark> {
    fn from(v: Rad) -> Self {
        v.into_calc()
    }
}
impl From<Turn> for CalcValue<AngleMark> {
    fn from(v: Turn) -> Self {
        v.into_calc()
    }
}

impl From<Px> for CalcValue<LengthMark> {
    fn from(v: Px) -> Self {
        v.into_calc()
    }
}
impl From<Percent> for CalcValue<LengthMark> {
    fn from(v: Percent) -> Self {
        v.into_calc()
    }
}
impl From<Rem> for CalcValue<LengthMark> {
    fn from(v: Rem) -> Self {
        v.into_calc()
    }
}
impl From<Em> for CalcValue<LengthMark> {
    fn from(v: Em) -> Self {
        v.into_calc()
    }
}
impl From<Vw> for CalcValue<LengthMark> {
    fn from(v: Vw) -> Self {
        v.into_calc()
    }
}
impl From<Vh> for CalcValue<LengthMark> {
    fn from(v: Vh) -> Self {
        v.into_calc()
    }
}