diff --git a/src/builtin/modules/math.rs b/src/builtin/modules/math.rs index 643beaa..db97a78 100644 --- a/src/builtin/modules/math.rs +++ b/src/builtin/modules/math.rs @@ -142,7 +142,32 @@ fn sqrt(mut args: CallArgs, parser: &mut Parser<'_>) -> SassResult { fn cos(mut args: CallArgs, parser: &mut Parser<'_>) -> SassResult { args.max_args(1)?; - todo!() + let number = args.get_err(0, "number")?; + + Ok(match number { + Value::Dimension(Some(n), Unit::None, ..) | Value::Dimension(Some(n), Unit::Rad, ..) => { + Value::Dimension(n.cos(), Unit::None, true) + } + Value::Dimension(Some(n), Unit::Deg, ..) => Value::Dimension(n.cos_deg(), Unit::None, true), + v @ Value::Dimension(Some(..), ..) => { + return Err(( + format!( + "$number: Expected {} to be an angle.", + v.inspect(args.span())? + ), + args.span(), + ) + .into()) + } + Value::Dimension(None, ..) => Value::Dimension(None, Unit::None, true), + v => { + return Err(( + format!("$number: {} is not a number.", v.inspect(args.span())?), + args.span(), + ) + .into()) + } + }) } fn sin(mut args: CallArgs, parser: &mut Parser<'_>) -> SassResult { @@ -188,6 +213,7 @@ pub(crate) fn declare(f: &mut Module) { f.insert_builtin("percentage", percentage); f.insert_builtin("clamp", clamp); f.insert_builtin("sqrt", sqrt); + f.insert_builtin("cos", cos); #[cfg(feature = "random")] f.insert_builtin("random", random); diff --git a/src/value/number/mod.rs b/src/value/number/mod.rs index 8e95bf9..3c99f68 100644 --- a/src/value/number/mod.rs +++ b/src/value/number/mod.rs @@ -110,16 +110,30 @@ impl Number { } #[allow(clippy::cast_precision_loss)] - pub fn sqrt(self) -> Option { + fn as_float(self) -> Option { Some(match self { - Number::Small(n) => Number::Big(Box::new(BigRational::from_float( - ((*n.numer() as f64) / (*n.denom() as f64)).sqrt(), - )?)), - Number::Big(n) => Number::Big(Box::new(BigRational::from_float( - ((n.numer().to_f64()?) / (n.denom().to_f64()?)).sqrt(), - )?)), + Number::Small(n) => ((*n.numer() as f64) / (*n.denom() as f64)), + Number::Big(n) => ((n.numer().to_f64()?) / (n.denom().to_f64()?)), }) } + + pub fn cos_deg(self) -> Option { + Some(Number::Big(Box::new(BigRational::from_float( + self.as_float()?.to_radians().cos(), + )?))) + } + + pub fn sqrt(self) -> Option { + Some(Number::Big(Box::new(BigRational::from_float( + self.as_float()?.sqrt(), + )?))) + } + + pub fn cos(self) -> Option { + Some(Number::Big(Box::new(BigRational::from_float( + self.as_float()?.cos(), + )?))) + } } impl Default for Number {