solidrs 0.2.0

Rust library to generate openScad models. Inspired by SolidPython.
Documentation
#[macro_export]
macro_rules! var {
    ($var:ident,$val:literal) => {
        let $var = Var::new(stringify!($var), $crate::Arg::f32(&$val));
        let $var = Val::Var(&$var);
    };
    ($var:ident,$val:literal,$comment:literal) => {
        let $var = Var::commented(stringify!($var), $comment, $crate::Arg::f32(&$val));
        let $var = Val::Var(&$var);
    };
}

pub trait Arg<'a>: Sized {
    fn val(self) -> Val<'a> {
        Val::Val(self.f32())
    }
    fn f32(&self) -> f32;
}
impl<'a> Arg<'a> for &'a Var {
    fn val(self) -> Val<'a> {
        Val::Var(self)
    }
    fn f32(&self) -> f32 {
        self.val
    }
}
impl<'a> Arg<'a> for Val<'a> {
    fn val(self) -> Val<'a> {
        self
    }
    fn f32(&self) -> f32 {
        match self {
            Val::Val(val) => *val,
            Val::Var(var) => var.val,
        }
    }
}
impl<'a> Arg<'a> for f32 {
    fn f32(&self) -> f32 {
        *self
    }
}
impl<'a> Arg<'a> for i32 {
    #[allow(clippy::cast_precision_loss)]
    fn f32(&self) -> f32 {
        *self as f32
    }
}

#[derive(Clone)]
pub struct Var {
    name: &'static str,
    comment: &'static str,
    val: f32,
}
impl Var {
    #[must_use]
    pub fn new(name: &'static str, val: f32) -> Var {
        Self {
            name,
            comment: "",
            val,
        }
    }
    #[must_use]
    pub fn commented(name: &'static str, comment: &'static str, val: f32) -> Var {
        Self { name, comment, val }
    }
    pub(crate) fn get_comment(&self) -> &'static str {
        self.comment
    }
    pub(crate) fn get_name(&self) -> &'static str {
        self.name
    }
    pub(crate) fn get_val(&self) -> f32 {
        self.val
    }
}

impl std::ops::Neg for Val<'_> {
    type Output = Val<'static>;

    fn neg(self) -> Self::Output {
        Val::Val(-self.f32())
    }
}
impl<'a, RHS: Arg<'a>> std::ops::Add<RHS> for Val<'_> {
    type Output = Val<'static>;

    fn add(self, rhs: RHS) -> Self::Output {
        Val::Val(self.f32() + rhs.f32())
    }
}
impl<'a, RHS: Arg<'a>> std::ops::Sub<RHS> for Val<'_> {
    type Output = Val<'static>;

    fn sub(self, rhs: RHS) -> Self::Output {
        Val::Val(self.f32() - rhs.f32())
    }
}
impl<'a, RHS: Arg<'a>> std::ops::Mul<RHS> for Val<'_> {
    type Output = Val<'static>;

    fn mul(self, rhs: RHS) -> Self::Output {
        Val::Val(self.f32() * rhs.f32())
    }
}
impl<'a, RHS: Arg<'a>> std::ops::Div<RHS> for Val<'_> {
    type Output = Val<'static>;

    fn div(self, rhs: RHS) -> Self::Output {
        Val::Val(self.f32() / rhs.f32())
    }
}
#[derive(Copy, Clone)]
pub enum Val<'a> {
    Val(f32),
    Var(&'a Var),
}
impl std::fmt::Display for Val<'_> {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        match self {
            Val::Val(val) => f.write_str(val.to_string().as_str()),
            Val::Var(var) => f.write_str(var.name),
        }
    }
}