make better use of num traits

This commit is contained in:
ConnorSkees 2020-03-22 22:28:54 -04:00
parent 0e0b01f595
commit 0be8828bf0
12 changed files with 180 additions and 116 deletions

View File

@ -1,5 +1,7 @@
use std::collections::HashMap; use std::collections::HashMap;
use num_traits::One;
use super::Builtin; use super::Builtin;
use crate::color::Color; use crate::color::Color;
use crate::common::QuoteKind; use crate::common::QuoteKind;
@ -46,7 +48,7 @@ pub(crate) fn register(f: &mut HashMap<String, Builtin>) {
hue, hue,
saturation, saturation,
luminance, luminance,
Number::from(1), Number::one(),
))) )))
} else { } else {
let hue = match arg!(args, 0, "hue") { let hue = match arg!(args, 0, "hue") {
@ -64,7 +66,7 @@ pub(crate) fn register(f: &mut HashMap<String, Builtin>) {
let alpha = match arg!( let alpha = match arg!(
args, args,
3, 3,
"alpha" = Value::Dimension(Number::from(1), Unit::None) "alpha" = Value::Dimension(Number::one(), Unit::None)
) { ) {
Value::Dimension(n, Unit::None) => n, Value::Dimension(n, Unit::None) => n,
Value::Dimension(n, Unit::Percent) => n / Number::from(100), Value::Dimension(n, Unit::Percent) => n / Number::from(100),
@ -120,7 +122,7 @@ pub(crate) fn register(f: &mut HashMap<String, Builtin>) {
hue, hue,
saturation, saturation,
luminance, luminance,
Number::from(1), Number::one(),
))) )))
} else { } else {
let hue = match arg!(args, 0, "hue") { let hue = match arg!(args, 0, "hue") {
@ -138,7 +140,7 @@ pub(crate) fn register(f: &mut HashMap<String, Builtin>) {
let alpha = match arg!( let alpha = match arg!(
args, args,
3, 3,
"alpha" = Value::Dimension(Number::from(1), Unit::None) "alpha" = Value::Dimension(Number::one(), Unit::None)
) { ) {
Value::Dimension(n, Unit::None) => n, Value::Dimension(n, Unit::None) => n,
Value::Dimension(n, Unit::Percent) => n / Number::from(100), Value::Dimension(n, Unit::Percent) => n / Number::from(100),
@ -280,7 +282,7 @@ pub(crate) fn register(f: &mut HashMap<String, Builtin>) {
} }
v => return Err(format!("$color: {} is not a color.", v).into()), v => return Err(format!("$color: {} is not a color.", v).into()),
}; };
Ok(Value::Color(color.desaturate(Number::from(1)))) Ok(Value::Color(color.desaturate(Number::one())))
}), }),
); );
f.insert( f.insert(

View File

@ -1,5 +1,7 @@
use std::collections::HashMap; use std::collections::HashMap;
use num_traits::{One, Signed, Zero};
use super::Builtin; use super::Builtin;
use crate::color::Color; use crate::color::Color;
use crate::common::QuoteKind; use crate::common::QuoteKind;
@ -84,10 +86,10 @@ pub(crate) fn register(f: &mut HashMap<String, Builtin>) {
if red.is_some() || green.is_some() || blue.is_some() { if red.is_some() || green.is_some() || blue.is_some() {
return Ok(Value::Color(Color::from_rgba( return Ok(Value::Color(Color::from_rgba(
color.red() + red.unwrap_or(Number::from(0)), color.red() + red.unwrap_or(Number::zero()),
color.green() + green.unwrap_or(Number::from(0)), color.green() + green.unwrap_or(Number::zero()),
color.blue() + blue.unwrap_or(Number::from(0)), color.blue() + blue.unwrap_or(Number::zero()),
color.alpha() + alpha.unwrap_or(Number::from(0)), color.alpha() + alpha.unwrap_or(Number::zero()),
))); )));
} }
@ -104,10 +106,10 @@ pub(crate) fn register(f: &mut HashMap<String, Builtin>) {
// Color::as_hsla() returns more exact values than Color::hue(), etc. // Color::as_hsla() returns more exact values than Color::hue(), etc.
let (this_hue, this_saturation, this_luminance, this_alpha) = color.as_hsla(); let (this_hue, this_saturation, this_luminance, this_alpha) = color.as_hsla();
return Ok(Value::Color(Color::from_hsla( return Ok(Value::Color(Color::from_hsla(
this_hue + hue.unwrap_or(Number::from(0)), this_hue + hue.unwrap_or(Number::zero()),
this_saturation + saturation.unwrap_or(Number::from(0)), this_saturation + saturation.unwrap_or(Number::zero()),
this_luminance + luminance.unwrap_or(Number::from(0)), this_luminance + luminance.unwrap_or(Number::zero()),
this_alpha + alpha.unwrap_or(Number::from(0)), this_alpha + alpha.unwrap_or(Number::zero()),
))); )));
} }
@ -154,23 +156,23 @@ pub(crate) fn register(f: &mut HashMap<String, Builtin>) {
return Ok(Value::Color(Color::from_rgba( return Ok(Value::Color(Color::from_rgba(
scale( scale(
color.red(), color.red(),
red.unwrap_or(Number::from(0)), red.unwrap_or(Number::zero()),
Number::from(255), Number::from(255),
), ),
scale( scale(
color.green(), color.green(),
green.unwrap_or(Number::from(0)), green.unwrap_or(Number::zero()),
Number::from(255), Number::from(255),
), ),
scale( scale(
color.blue(), color.blue(),
blue.unwrap_or(Number::from(0)), blue.unwrap_or(Number::zero()),
Number::from(255), Number::from(255),
), ),
scale( scale(
color.alpha(), color.alpha(),
alpha.unwrap_or(Number::from(0)), alpha.unwrap_or(Number::zero()),
Number::from(1), Number::one(),
), ),
))); )));
} }
@ -182,28 +184,24 @@ pub(crate) fn register(f: &mut HashMap<String, Builtin>) {
// Color::as_hsla() returns more exact values than Color::hue(), etc. // Color::as_hsla() returns more exact values than Color::hue(), etc.
let (this_hue, this_saturation, this_luminance, this_alpha) = color.as_hsla(); let (this_hue, this_saturation, this_luminance, this_alpha) = color.as_hsla();
return Ok(Value::Color(Color::from_hsla( return Ok(Value::Color(Color::from_hsla(
scale(this_hue, Number::from(0), Number::from(360)), scale(this_hue, Number::zero(), Number::from(360)),
scale( scale(
this_saturation, this_saturation,
saturation.unwrap_or(Number::from(0)), saturation.unwrap_or(Number::zero()),
Number::from(1), Number::one(),
), ),
scale( scale(
this_luminance, this_luminance,
luminance.unwrap_or(Number::from(0)), luminance.unwrap_or(Number::zero()),
Number::from(1), Number::one(),
),
scale(
this_alpha,
alpha.unwrap_or(Number::from(0)),
Number::from(1),
), ),
scale(this_alpha, alpha.unwrap_or(Number::zero()), Number::one()),
))); )));
} }
Ok(Value::Color(if let Some(a) = alpha { Ok(Value::Color(if let Some(a) = alpha {
let temp_alpha = color.alpha(); let temp_alpha = color.alpha();
color.with_alpha(scale(temp_alpha, a, Number::from(1))) color.with_alpha(scale(temp_alpha, a, Number::one()))
} else { } else {
color color
})) }))
@ -223,8 +221,8 @@ pub(crate) fn register(f: &mut HashMap<String, Builtin>) {
} }
fn scale(val: Number, by: Number, max: Number) -> Number { fn scale(val: Number, by: Number, max: Number) -> Number {
if by == Number::from(0) { if by.is_zero() {
return val; return val;
} }
val.clone() + (if by > Number::from(0) { max - val } else { val }) * by val.clone() + (if by.is_positive() { max - val } else { val }) * by
} }

View File

@ -1,5 +1,7 @@
use std::collections::HashMap; use std::collections::HashMap;
use num_traits::One;
use super::Builtin; use super::Builtin;
use crate::color::Color; use crate::color::Color;
use crate::unit::Unit; use crate::unit::Unit;
@ -50,7 +52,7 @@ pub(crate) fn register(f: &mut HashMap<String, Builtin>) {
None => return Err("Missing element $red.".into()), None => return Err("Missing element $red.".into()),
}; };
let color = Color::from_rgba(red, green, blue, Number::from(1)); let color = Color::from_rgba(red, green, blue, Number::one());
Ok(Value::Color(color)) Ok(Value::Color(color))
} else if args.len() == 2 { } else if args.len() == 2 {
@ -109,7 +111,7 @@ pub(crate) fn register(f: &mut HashMap<String, Builtin>) {
let alpha = match arg!( let alpha = match arg!(
args, args,
3, 3,
"alpha" = Value::Dimension(Number::from(1), Unit::None) "alpha" = Value::Dimension(Number::one(), Unit::None)
) { ) {
Value::Dimension(n, Unit::None) => n, Value::Dimension(n, Unit::None) => n,
Value::Dimension(n, Unit::Percent) => n / Number::from(100), Value::Dimension(n, Unit::Percent) => n / Number::from(100),
@ -168,7 +170,7 @@ pub(crate) fn register(f: &mut HashMap<String, Builtin>) {
None => return Err("Missing element $red.".into()), None => return Err("Missing element $red.".into()),
}; };
let color = Color::from_rgba(red, green, blue, Number::from(1)); let color = Color::from_rgba(red, green, blue, Number::one());
Ok(Value::Color(color)) Ok(Value::Color(color))
} else if args.len() == 2 { } else if args.len() == 2 {
@ -227,7 +229,7 @@ pub(crate) fn register(f: &mut HashMap<String, Builtin>) {
let alpha = match arg!( let alpha = match arg!(
args, args,
3, 3,
"alpha" = Value::Dimension(Number::from(1), Unit::None) "alpha" = Value::Dimension(Number::one(), Unit::None)
) { ) {
Value::Dimension(n, Unit::None) => n, Value::Dimension(n, Unit::None) => n,
Value::Dimension(n, Unit::Percent) => n / Number::from(100), Value::Dimension(n, Unit::Percent) => n / Number::from(100),

View File

@ -1,6 +1,6 @@
use std::collections::HashMap; use std::collections::HashMap;
use num_traits::cast::ToPrimitive; use num_traits::{One, Signed, ToPrimitive, Zero};
use super::Builtin; use super::Builtin;
use crate::common::{ListSeparator, QuoteKind}; use crate::common::{ListSeparator, QuoteKind};
@ -14,7 +14,7 @@ pub(crate) fn register(f: &mut HashMap<String, Builtin>) {
max_args!(args, 1); max_args!(args, 1);
let len = match arg!(args, 0, "list") { let len = match arg!(args, 0, "list") {
Value::List(v, _) => Number::from(v.len()), Value::List(v, _) => Number::from(v.len()),
_ => Number::from(1), _ => Number::one(),
}; };
Ok(Value::Dimension(len, Unit::None)) Ok(Value::Dimension(len, Unit::None))
}), }),
@ -32,7 +32,7 @@ pub(crate) fn register(f: &mut HashMap<String, Builtin>) {
v => return Err(format!("$n: {} is not a number.", v).into()), v => return Err(format!("$n: {} is not a number.", v).into()),
}; };
if n == Number::from(0) { if n.is_zero() {
return Err("$n: List index may not be 0.".into()); return Err("$n: List index may not be 0.".into());
} }
@ -49,7 +49,7 @@ pub(crate) fn register(f: &mut HashMap<String, Builtin>) {
return Err(format!("$n: {} is not an int.", n).into()); return Err(format!("$n: {} is not an int.", n).into());
} }
if n > Number::from(0) { if n.is_positive() {
Ok(list[n.to_integer().to_usize().unwrap() - 1].clone()) Ok(list[n.to_integer().to_usize().unwrap() - 1].clone())
} else { } else {
Ok(list[list.len() - n.abs().to_integer().to_usize().unwrap()].clone()) Ok(list[list.len() - n.abs().to_integer().to_usize().unwrap()].clone())
@ -83,7 +83,7 @@ pub(crate) fn register(f: &mut HashMap<String, Builtin>) {
v => return Err(format!("$n: {} is not a number.", v).into()), v => return Err(format!("$n: {} is not a number.", v).into()),
}; };
if n == Number::from(0) { if n.is_zero() {
return Err("$n: List index may not be 0.".into()); return Err("$n: List index may not be 0.".into());
} }
@ -101,7 +101,7 @@ pub(crate) fn register(f: &mut HashMap<String, Builtin>) {
let val = arg!(args, 2, "value"); let val = arg!(args, 2, "value");
if n > Number::from(0) { if n.is_positive() {
list[n.to_integer().to_usize().unwrap() - 1] = val; list[n.to_integer().to_usize().unwrap() - 1] = val;
} else { } else {
list[len - n.abs().to_integer().to_usize().unwrap()] = val; list[len - n.abs().to_integer().to_usize().unwrap()] = val;

View File

@ -1,8 +1,7 @@
use std::collections::HashMap; use std::collections::HashMap;
use num_bigint::BigInt; use num_bigint::BigInt;
use num_traits::cast::ToPrimitive; use num_traits::{Signed, ToPrimitive, Zero};
use num_traits::sign::Signed;
use super::Builtin; use super::Builtin;
use crate::common::QuoteKind; use crate::common::QuoteKind;
@ -35,7 +34,10 @@ pub(crate) fn register(f: &mut HashMap<String, Builtin>) {
Box::new(|args, _| { Box::new(|args, _| {
max_args!(args, 1); max_args!(args, 1);
match arg!(args, 0, "string") { match arg!(args, 0, "string") {
Value::Ident(i, _) => Ok(Value::Dimension(Number::from(i.chars().count()), Unit::None)), Value::Ident(i, _) => Ok(Value::Dimension(
Number::from(i.chars().count()),
Unit::None,
)),
v => Err(format!("$string: {} is not a string.", v).into()), v => Err(format!("$string: {} is not a string.", v).into()),
} }
}), }),
@ -73,10 +75,10 @@ pub(crate) fn register(f: &mut HashMap<String, Builtin>) {
Value::Dimension(n, Unit::None) if n.is_decimal() => { Value::Dimension(n, Unit::None) if n.is_decimal() => {
return Err(format!("{} is not an int.", n).into()) return Err(format!("{} is not an int.", n).into())
} }
Value::Dimension(n, Unit::None) if n.to_integer().is_positive() => { Value::Dimension(n, Unit::None) if n.is_positive() => {
n.to_integer().to_usize().unwrap() n.to_integer().to_usize().unwrap()
} }
Value::Dimension(n, Unit::None) if n == Number::from(0) => 1_usize, Value::Dimension(n, Unit::None) if n.is_zero() => 1_usize,
Value::Dimension(n, Unit::None) if n < -Number::from(str_len) => 1_usize, Value::Dimension(n, Unit::None) if n < -Number::from(str_len) => 1_usize,
Value::Dimension(n, Unit::None) => (BigInt::from(str_len + 1) + n.to_integer()) Value::Dimension(n, Unit::None) => (BigInt::from(str_len + 1) + n.to_integer())
.to_usize() .to_usize()
@ -90,10 +92,10 @@ pub(crate) fn register(f: &mut HashMap<String, Builtin>) {
Value::Dimension(n, Unit::None) if n.is_decimal() => { Value::Dimension(n, Unit::None) if n.is_decimal() => {
return Err(format!("{} is not an int.", n).into()) return Err(format!("{} is not an int.", n).into())
} }
Value::Dimension(n, Unit::None) if n.to_integer().is_positive() => { Value::Dimension(n, Unit::None) if n.is_positive() => {
n.to_integer().to_usize().unwrap() n.to_integer().to_usize().unwrap()
} }
Value::Dimension(n, Unit::None) if n == Number::from(0) => 0_usize, Value::Dimension(n, Unit::None) if n.is_zero() => 0_usize,
Value::Dimension(n, Unit::None) if n < -Number::from(str_len) => 0_usize, Value::Dimension(n, Unit::None) if n < -Number::from(str_len) => 0_usize,
Value::Dimension(n, Unit::None) => (BigInt::from(str_len + 1) + n.to_integer()) Value::Dimension(n, Unit::None) => (BigInt::from(str_len + 1) + n.to_integer())
.to_usize() .to_usize()
@ -197,13 +199,13 @@ pub(crate) fn register(f: &mut HashMap<String, Builtin>) {
.collect::<String>() .collect::<String>()
}; };
let string = if index > Number::from(0) { let string = if index.is_positive() {
insert( insert(
index.to_integer().to_usize().unwrap().min(len + 1) - 1, index.to_integer().to_usize().unwrap().min(len + 1) - 1,
s1, s1,
&substr, &substr,
) )
} else if index == Number::from(0) { } else if index.is_zero() {
insert(0, s1, &substr) insert(0, s1, &substr)
} else { } else {
let idx = index.abs().to_integer().to_usize().unwrap(); let idx = index.abs().to_integer().to_usize().unwrap();

View File

@ -20,7 +20,7 @@ use std::fmt::{self, Display};
use crate::value::Number; use crate::value::Number;
pub(crate) use name::ColorName; pub(crate) use name::ColorName;
use num_traits::cast::ToPrimitive; use num_traits::{One, Signed, ToPrimitive, Zero};
mod name; mod name;
@ -149,8 +149,8 @@ impl Color {
($channel:ident) => { ($channel:ident) => {
let $channel = if $channel > Number::from(255) { let $channel = if $channel > Number::from(255) {
Number::from(255) Number::from(255)
} else if $channel < Number::from(0) { } else if $channel.is_negative() {
Number::from(0) Number::zero()
} else { } else {
$channel $channel
}; };
@ -161,10 +161,10 @@ impl Color {
clamp!(green); clamp!(green);
clamp!(blue); clamp!(blue);
let alpha = if alpha > Number::from(1) { let alpha = if alpha > Number::one() {
Number::from(1) Number::one()
} else if alpha < Number::from(0) { } else if alpha.is_negative() {
Number::from(0) Number::zero()
} else { } else {
alpha alpha
}; };
@ -190,7 +190,7 @@ impl Color {
/// <https://github.com/sass/dart-sass/blob/0d0270cb12a9ac5cce73a4d0785fecb00735feee/lib/src/functions/color.dart#L718> /// <https://github.com/sass/dart-sass/blob/0d0270cb12a9ac5cce73a4d0785fecb00735feee/lib/src/functions/color.dart#L718>
pub fn mix(self, other: &Color, weight: Number) -> Self { pub fn mix(self, other: &Color, weight: Number) -> Self {
let weight = clamp!(weight, 0, 100); let weight = clamp!(weight, 0, 100);
let normalized_weight = weight.clone() * Number::from(2) - Number::from(1); let normalized_weight = weight.clone() * Number::from(2) - Number::one();
let alpha_distance = self.alpha() - other.alpha(); let alpha_distance = self.alpha() - other.alpha();
let combined_weight1 = let combined_weight1 =
@ -198,16 +198,16 @@ impl Color {
normalized_weight normalized_weight
} else { } else {
(normalized_weight.clone() + alpha_distance.clone()) (normalized_weight.clone() + alpha_distance.clone())
/ (Number::from(1) + normalized_weight * alpha_distance) / (Number::one() + normalized_weight * alpha_distance)
}; };
let weight1 = (combined_weight1 + Number::from(1)) / Number::from(2); let weight1 = (combined_weight1 + Number::one()) / Number::from(2);
let weight2 = Number::from(1) - weight1.clone(); let weight2 = Number::one() - weight1.clone();
Color::from_rgba( Color::from_rgba(
self.red() * weight1.clone() + other.red() * weight2.clone(), self.red() * weight1.clone() + other.red() * weight2.clone(),
self.green() * weight1.clone() + other.green() * weight2.clone(), self.green() * weight1.clone() + other.green() * weight2.clone(),
self.blue() * weight1 + other.blue() * weight2, self.blue() * weight1 + other.blue() * weight2,
self.alpha() * weight.clone() + other.alpha() * (Number::from(1) - weight), self.alpha() * weight.clone() + other.alpha() * (Number::one() - weight),
) )
} }
} }
@ -227,7 +227,7 @@ impl Color {
let min = red.clone().min(green.clone().min(blue.clone())); let min = red.clone().min(green.clone().min(blue.clone()));
let max = red.clone().max(green.clone().max(blue.clone())); let max = red.clone().max(green.clone().max(blue.clone()));
if min == max { if min == max {
return Number::from(0); return Number::zero();
} }
let mut hue = if blue == max { let mut hue = if blue == max {
@ -238,7 +238,7 @@ impl Color {
(green - blue) / (max - min) (green - blue) / (max - min)
}; };
if hue < Number::from(0) { if hue.is_negative() {
hue += Number::from(360); hue += Number::from(360);
} }
@ -259,12 +259,12 @@ impl Color {
let max = red.max(green.max(blue)); let max = red.max(green.max(blue));
if min == max { if min == max {
return Number::from(0); return Number::zero();
} }
let d = max.clone() - min.clone(); let d = max.clone() - min.clone();
let mm = max + min; let mm = max + min;
let s = d / if mm > Number::from(1) { let s = d / if mm > Number::one() {
Number::from(2) - mm Number::from(2) - mm
} else { } else {
mm mm
@ -300,11 +300,11 @@ impl Color {
let lightness = (min.clone() + max.clone()) / Number::from(2); let lightness = (min.clone() + max.clone()) / Number::from(2);
let saturation = if min == max { let saturation = if min == max {
Number::from(0) Number::zero()
} else { } else {
let d = max.clone() - min.clone(); let d = max.clone() - min.clone();
let mm = max.clone() + min.clone(); let mm = max.clone() + min.clone();
d / if mm > Number::from(1) { d / if mm > Number::one() {
Number::from(2) - mm Number::from(2) - mm
} else { } else {
mm mm
@ -312,7 +312,7 @@ impl Color {
}; };
let mut hue = if min == max { let mut hue = if min == max {
Number::from(0) Number::zero()
} else if blue == max { } else if blue == max {
Number::from(4) + (red - green) / (max - min) Number::from(4) + (red - green) / (max - min)
} else if green == max { } else if green == max {
@ -321,7 +321,7 @@ impl Color {
(green - blue) / (max - min) (green - blue) / (max - min)
}; };
if hue < Number::from(0) { if hue.is_negative() {
hue += Number::from(360); hue += Number::from(360);
} }
@ -361,7 +361,7 @@ impl Color {
hue % Number::from(360) hue % Number::from(360)
} else if hue < Number::from(-360) { } else if hue < Number::from(-360) {
Number::from(360) + hue % Number::from(360) Number::from(360) + hue % Number::from(360)
} else if hue < Number::from(0) { } else if hue.is_negative() {
Number::from(360) + clamp!(hue, -360, 360) Number::from(360) + clamp!(hue, -360, 360)
} else { } else {
hue hue
@ -378,7 +378,7 @@ impl Color {
alpha.clone(), alpha.clone(),
); );
if saturation.clone() == Number::from(0) { if saturation.is_zero() {
let luminance = if luminance > Number::from(100) { let luminance = if luminance > Number::from(100) {
Number::from(100) Number::from(100)
} else { } else {
@ -388,8 +388,8 @@ impl Color {
let repr = repr(&val, &val, &val, &alpha); let repr = repr(&val, &val, &val, &alpha);
return Color::new_hsla(val.clone(), val.clone(), val, alpha, hsla, repr); return Color::new_hsla(val.clone(), val.clone(), val, alpha, hsla, repr);
} }
let temporary_1 = if luminance.clone() < Number::ratio(1, 2) { let temporary_1 = if luminance < Number::ratio(1, 2) {
luminance.clone() * (Number::from(1) + saturation) luminance.clone() * (Number::one() + saturation)
} else { } else {
luminance.clone() + saturation.clone() - luminance.clone() * saturation luminance.clone() + saturation.clone() - luminance.clone() * saturation
}; };
@ -401,10 +401,10 @@ impl Color {
macro_rules! clamp_temp { macro_rules! clamp_temp {
($temp:ident) => { ($temp:ident) => {
if $temp > Number::from(1) { if $temp > Number::one() {
$temp -= Number::from(1); $temp -= Number::one();
} else if $temp < Number::from(0) { } else if $temp.is_negative() {
$temp += Number::from(1); $temp += Number::one();
} }
}; };
} }
@ -415,10 +415,10 @@ impl Color {
macro_rules! channel { macro_rules! channel {
($name:ident, $temp:ident, $temp1:ident, $temp2:ident) => { ($name:ident, $temp:ident, $temp1:ident, $temp2:ident) => {
let $name = if Number::from(6) * $temp.clone() < Number::from(1) { let $name = if Number::from(6) * $temp.clone() < Number::one() {
$temp2.clone() $temp2.clone()
+ ($temp1.clone() - $temp2.clone()) * Number::from(6) * $temp.clone() + ($temp1.clone() - $temp2.clone()) * Number::from(6) * $temp.clone()
} else if Number::from(2) * $temp.clone() < Number::from(1) { } else if Number::from(2) * $temp.clone() < Number::one() {
$temp1.clone() $temp1.clone()
} else if Number::from(3) * $temp.clone() < Number::from(2) { } else if Number::from(3) * $temp.clone() < Number::from(2) {
$temp2.clone() $temp2.clone()
@ -440,7 +440,7 @@ impl Color {
} }
pub fn invert(&self, weight: Number) -> Self { pub fn invert(&self, weight: Number) -> Self {
if weight == Number::from(0) { if weight.is_zero() {
return self.clone(); return self.clone();
} }
let red = Number::from(u8::max_value()) - self.red(); let red = Number::from(u8::max_value()) - self.red();
@ -466,7 +466,7 @@ impl Color {
impl Color { impl Color {
pub fn alpha(&self) -> Number { pub fn alpha(&self) -> Number {
let a = self.rgba.alpha(); let a = self.rgba.alpha();
if a > Number::from(1) { if a > Number::one() {
a / Number::from(255) a / Number::from(255)
} else { } else {
a a
@ -512,7 +512,7 @@ fn repr(red: &Number, green: &Number, blue: &Number, alpha: &Number) -> String {
($channel:ident) => { ($channel:ident) => {
let $channel = if $channel > &Number::from(255) { let $channel = if $channel > &Number::from(255) {
255_u8 255_u8
} else if $channel < &Number::from(0) { } else if $channel.is_negative() {
0_u8 0_u8
} else { } else {
$channel.clone().round().to_integer().to_u8().unwrap() $channel.clone().round().to_integer().to_u8().unwrap()
@ -524,7 +524,7 @@ fn repr(red: &Number, green: &Number, blue: &Number, alpha: &Number) -> String {
into_u8!(green); into_u8!(green);
into_u8!(blue); into_u8!(blue);
if alpha < &Number::from(1) { if alpha < &Number::one() {
format!("rgba({}, {}, {}, {})", red, green, blue, alpha) format!("rgba({}, {}, {}, {})", red, green, blue, alpha)
} else if let Ok(c) = ColorName::try_from([red, green, blue]) { } else if let Ok(c) = ColorName::try_from([red, green, blue]) {
format!("{}", c) format!("{}", c)

View File

@ -208,10 +208,10 @@ impl<'a> Lexer<'a> {
self.buf.next(); self.buf.next();
self.pos.next_char(); self.pos.next_char();
if let TokenKind::Ident(s) = self.lex_ident() { if let TokenKind::Ident(s) = self.lex_ident() {
if !s.is_empty() { if s.is_empty() {
TokenKind::AtRule(AtRuleKind::from(s.as_ref()))
} else {
TokenKind::Error("Expected identifier.".into()) TokenKind::Error("Expected identifier.".into())
} else {
TokenKind::AtRule(AtRuleKind::from(s.as_ref()))
} }
} else { } else {
TokenKind::Error("Expected identifier.".into()) TokenKind::Error("Expected identifier.".into())

View File

@ -416,7 +416,7 @@ impl<'a> StyleSheetParser<'a> {
AtRule::If(cond, yes, no) => { AtRule::If(cond, yes, no) => {
if Value::from_tokens( if Value::from_tokens(
&mut cond.into_iter().peekable(), &mut cond.into_iter().peekable(),
&mut GLOBAL_SCOPE.with(|s| s.borrow().clone()), &GLOBAL_SCOPE.with(|s| s.borrow().clone()),
&Selector::new(), &Selector::new(),
)?.is_true()? { )?.is_true()? {
rules.extend(yes); rules.extend(yes);
@ -453,7 +453,7 @@ impl<'a> StyleSheetParser<'a> {
AtRule::If(cond, yes, no) => { AtRule::If(cond, yes, no) => {
if Value::from_tokens( if Value::from_tokens(
&mut cond.into_iter().peekable(), &mut cond.into_iter().peekable(),
&mut GLOBAL_SCOPE.with(|s| s.borrow().clone()), &GLOBAL_SCOPE.with(|s| s.borrow().clone()),
&Selector::new(), &Selector::new(),
)? )?
.is_true()? .is_true()?

View File

@ -6,6 +6,7 @@ use std::collections::HashMap;
use std::f64::consts::PI; use std::f64::consts::PI;
use std::string::ToString; use std::string::ToString;
use num_traits::One;
use once_cell::sync::Lazy; use once_cell::sync::Lazy;
use crate::value::Number; use crate::value::Number;
@ -13,17 +14,17 @@ use crate::value::Number;
pub(crate) static UNIT_CONVERSION_TABLE: Lazy<HashMap<String, HashMap<String, Number>>> = pub(crate) static UNIT_CONVERSION_TABLE: Lazy<HashMap<String, HashMap<String, Number>>> =
Lazy::new(|| { Lazy::new(|| {
let mut from_in = HashMap::new(); let mut from_in = HashMap::new();
from_in.insert("in".to_string(), Number::from(1)); from_in.insert("in".to_string(), Number::one());
from_in.insert("cm".to_string(), Number::from(1) / Number::from(2.54)); from_in.insert("cm".to_string(), Number::one() / Number::from(2.54));
from_in.insert("pc".to_string(), Number::ratio(1, 6)); from_in.insert("pc".to_string(), Number::ratio(1, 6));
from_in.insert("mm".to_string(), Number::from(1) / Number::from(25.4)); from_in.insert("mm".to_string(), Number::one() / Number::from(25.4));
from_in.insert("q".to_string(), Number::from(1) / Number::from(101.6)); from_in.insert("q".to_string(), Number::one() / Number::from(101.6));
from_in.insert("pt".to_string(), Number::ratio(1, 72)); from_in.insert("pt".to_string(), Number::ratio(1, 72));
from_in.insert("px".to_string(), Number::ratio(1, 96)); from_in.insert("px".to_string(), Number::ratio(1, 96));
let mut from_cm = HashMap::new(); let mut from_cm = HashMap::new();
from_cm.insert("in".to_string(), Number::from(2.54)); from_cm.insert("in".to_string(), Number::from(2.54));
from_cm.insert("cm".to_string(), Number::from(1)); from_cm.insert("cm".to_string(), Number::one());
from_cm.insert("pc".to_string(), Number::from(2.54) / Number::from(6)); from_cm.insert("pc".to_string(), Number::from(2.54) / Number::from(6));
from_cm.insert("mm".to_string(), Number::ratio(1, 10)); from_cm.insert("mm".to_string(), Number::ratio(1, 10));
from_cm.insert("q".to_string(), Number::ratio(1, 40)); from_cm.insert("q".to_string(), Number::ratio(1, 40));
@ -33,7 +34,7 @@ pub(crate) static UNIT_CONVERSION_TABLE: Lazy<HashMap<String, HashMap<String, Nu
let mut from_pc = HashMap::new(); let mut from_pc = HashMap::new();
from_pc.insert("in".to_string(), Number::from(6)); from_pc.insert("in".to_string(), Number::from(6));
from_pc.insert("cm".to_string(), Number::from(6) / Number::from(2.54)); from_pc.insert("cm".to_string(), Number::from(6) / Number::from(2.54));
from_pc.insert("pc".to_string(), Number::from(1)); from_pc.insert("pc".to_string(), Number::one());
from_pc.insert("mm".to_string(), Number::from(6) / Number::from(25.4)); from_pc.insert("mm".to_string(), Number::from(6) / Number::from(25.4));
from_pc.insert("q".to_string(), Number::from(6) / Number::from(101.6)); from_pc.insert("q".to_string(), Number::from(6) / Number::from(101.6));
from_pc.insert("pt".to_string(), Number::ratio(1, 12)); from_pc.insert("pt".to_string(), Number::ratio(1, 12));
@ -43,7 +44,7 @@ pub(crate) static UNIT_CONVERSION_TABLE: Lazy<HashMap<String, HashMap<String, Nu
from_mm.insert("in".to_string(), Number::from(25.4)); from_mm.insert("in".to_string(), Number::from(25.4));
from_mm.insert("cm".to_string(), Number::from(10)); from_mm.insert("cm".to_string(), Number::from(10));
from_mm.insert("pc".to_string(), Number::from(25.4) / Number::from(6)); from_mm.insert("pc".to_string(), Number::from(25.4) / Number::from(6));
from_mm.insert("mm".to_string(), Number::from(1)); from_mm.insert("mm".to_string(), Number::one());
from_mm.insert("q".to_string(), Number::ratio(1, 4)); from_mm.insert("q".to_string(), Number::ratio(1, 4));
from_mm.insert("pt".to_string(), Number::from(25.4) / Number::from(72)); from_mm.insert("pt".to_string(), Number::from(25.4) / Number::from(72));
from_mm.insert("px".to_string(), Number::from(25.4) / Number::from(96)); from_mm.insert("px".to_string(), Number::from(25.4) / Number::from(96));
@ -53,7 +54,7 @@ pub(crate) static UNIT_CONVERSION_TABLE: Lazy<HashMap<String, HashMap<String, Nu
from_q.insert("cm".to_string(), Number::from(40)); from_q.insert("cm".to_string(), Number::from(40));
from_q.insert("pc".to_string(), Number::from(101.6) / Number::from(6)); from_q.insert("pc".to_string(), Number::from(101.6) / Number::from(6));
from_q.insert("mm".to_string(), Number::from(4)); from_q.insert("mm".to_string(), Number::from(4));
from_q.insert("q".to_string(), Number::from(1)); from_q.insert("q".to_string(), Number::one());
from_q.insert("pt".to_string(), Number::from(101.6) / Number::from(72)); from_q.insert("pt".to_string(), Number::from(101.6) / Number::from(72));
from_q.insert("px".to_string(), Number::from(101.6) / Number::from(96)); from_q.insert("px".to_string(), Number::from(101.6) / Number::from(96));
@ -63,7 +64,7 @@ pub(crate) static UNIT_CONVERSION_TABLE: Lazy<HashMap<String, HashMap<String, Nu
from_pt.insert("pc".to_string(), Number::from(12)); from_pt.insert("pc".to_string(), Number::from(12));
from_pt.insert("mm".to_string(), Number::from(72) / Number::from(25.4)); from_pt.insert("mm".to_string(), Number::from(72) / Number::from(25.4));
from_pt.insert("q".to_string(), Number::from(72) / Number::from(101.6)); from_pt.insert("q".to_string(), Number::from(72) / Number::from(101.6));
from_pt.insert("pt".to_string(), Number::from(1)); from_pt.insert("pt".to_string(), Number::one());
from_pt.insert("px".to_string(), Number::ratio(3, 4)); from_pt.insert("px".to_string(), Number::ratio(3, 4));
let mut from_px = HashMap::new(); let mut from_px = HashMap::new();
@ -73,62 +74,62 @@ pub(crate) static UNIT_CONVERSION_TABLE: Lazy<HashMap<String, HashMap<String, Nu
from_px.insert("mm".to_string(), Number::from(96) / Number::from(25.4)); from_px.insert("mm".to_string(), Number::from(96) / Number::from(25.4));
from_px.insert("q".to_string(), Number::from(96) / Number::from(101.6)); from_px.insert("q".to_string(), Number::from(96) / Number::from(101.6));
from_px.insert("pt".to_string(), Number::ratio(4, 3)); from_px.insert("pt".to_string(), Number::ratio(4, 3));
from_px.insert("px".to_string(), Number::from(1)); from_px.insert("px".to_string(), Number::one());
let mut from_deg = HashMap::new(); let mut from_deg = HashMap::new();
from_deg.insert("deg".to_string(), Number::from(1)); from_deg.insert("deg".to_string(), Number::one());
from_deg.insert("grad".to_string(), Number::ratio(9, 10)); from_deg.insert("grad".to_string(), Number::ratio(9, 10));
from_deg.insert("rad".to_string(), Number::from(180) / Number::from(PI)); from_deg.insert("rad".to_string(), Number::from(180) / Number::from(PI));
from_deg.insert("turn".to_string(), Number::from(360)); from_deg.insert("turn".to_string(), Number::from(360));
let mut from_grad = HashMap::new(); let mut from_grad = HashMap::new();
from_grad.insert("deg".to_string(), Number::ratio(10, 9)); from_grad.insert("deg".to_string(), Number::ratio(10, 9));
from_grad.insert("grad".to_string(), Number::from(1)); from_grad.insert("grad".to_string(), Number::one());
from_grad.insert("rad".to_string(), Number::from(200) / Number::from(PI)); from_grad.insert("rad".to_string(), Number::from(200) / Number::from(PI));
from_grad.insert("turn".to_string(), Number::from(400)); from_grad.insert("turn".to_string(), Number::from(400));
let mut from_rad = HashMap::new(); let mut from_rad = HashMap::new();
from_rad.insert("deg".to_string(), Number::from(PI) / Number::from(180)); from_rad.insert("deg".to_string(), Number::from(PI) / Number::from(180));
from_rad.insert("grad".to_string(), Number::from(PI) / Number::from(200)); from_rad.insert("grad".to_string(), Number::from(PI) / Number::from(200));
from_rad.insert("rad".to_string(), Number::from(1)); from_rad.insert("rad".to_string(), Number::one());
from_rad.insert("turn".to_string(), Number::from(2.0 * PI)); from_rad.insert("turn".to_string(), Number::from(2.0 * PI));
let mut from_turn = HashMap::new(); let mut from_turn = HashMap::new();
from_turn.insert("deg".to_string(), Number::ratio(1, 360)); from_turn.insert("deg".to_string(), Number::ratio(1, 360));
from_turn.insert("grad".to_string(), Number::ratio(1, 400)); from_turn.insert("grad".to_string(), Number::ratio(1, 400));
from_turn.insert("rad".to_string(), Number::from(1) / Number::from(2.0 * PI)); from_turn.insert("rad".to_string(), Number::one() / Number::from(2.0 * PI));
from_turn.insert("turn".to_string(), Number::from(1)); from_turn.insert("turn".to_string(), Number::one());
let mut from_s = HashMap::new(); let mut from_s = HashMap::new();
from_s.insert("s".to_string(), Number::from(1)); from_s.insert("s".to_string(), Number::one());
from_s.insert("ms".to_string(), Number::ratio(1, 1000)); from_s.insert("ms".to_string(), Number::ratio(1, 1000));
let mut from_ms = HashMap::new(); let mut from_ms = HashMap::new();
from_ms.insert("s".to_string(), Number::from(1000)); from_ms.insert("s".to_string(), Number::from(1000));
from_ms.insert("ms".to_string(), Number::from(1)); from_ms.insert("ms".to_string(), Number::one());
let mut from_hz = HashMap::new(); let mut from_hz = HashMap::new();
from_hz.insert("Hz".to_string(), Number::from(1)); from_hz.insert("Hz".to_string(), Number::one());
from_hz.insert("kHz".to_string(), Number::from(1000)); from_hz.insert("kHz".to_string(), Number::from(1000));
let mut from_khz = HashMap::new(); let mut from_khz = HashMap::new();
from_khz.insert("Hz".to_string(), Number::ratio(1, 1000)); from_khz.insert("Hz".to_string(), Number::ratio(1, 1000));
from_khz.insert("kHz".to_string(), Number::from(1)); from_khz.insert("kHz".to_string(), Number::one());
let mut from_dpi = HashMap::new(); let mut from_dpi = HashMap::new();
from_dpi.insert("dpi".to_string(), Number::from(1)); from_dpi.insert("dpi".to_string(), Number::one());
from_dpi.insert("dpcm".to_string(), Number::from(2.54)); from_dpi.insert("dpcm".to_string(), Number::from(2.54));
from_dpi.insert("dppx".to_string(), Number::from(96)); from_dpi.insert("dppx".to_string(), Number::from(96));
let mut from_dpcm = HashMap::new(); let mut from_dpcm = HashMap::new();
from_dpcm.insert("dpi".to_string(), Number::from(1) / Number::from(2.54)); from_dpcm.insert("dpi".to_string(), Number::one() / Number::from(2.54));
from_dpcm.insert("dpcm".to_string(), Number::from(1)); from_dpcm.insert("dpcm".to_string(), Number::one());
from_dpcm.insert("dppx".to_string(), Number::from(96) / Number::from(2.54)); from_dpcm.insert("dppx".to_string(), Number::from(96) / Number::from(2.54));
let mut from_dppx = HashMap::new(); let mut from_dppx = HashMap::new();
from_dppx.insert("dpi".to_string(), Number::ratio(1, 96)); from_dppx.insert("dpi".to_string(), Number::ratio(1, 96));
from_dppx.insert("dpcm".to_string(), Number::from(2.54) / Number::from(96)); from_dppx.insert("dpcm".to_string(), Number::from(2.54) / Number::from(96));
from_dppx.insert("dppx".to_string(), Number::from(1)); from_dppx.insert("dppx".to_string(), Number::one());
let mut m = HashMap::new(); let mut m = HashMap::new();
m.insert("in".to_string(), from_in); m.insert("in".to_string(), from_in);

View File

@ -102,7 +102,7 @@ impl Value {
match self { match self {
&Value::Null => true, &Value::Null => true,
Value::Ident(i, QuoteKind::None) if i.is_empty() => true, Value::Ident(i, QuoteKind::None) if i.is_empty() => true,
_ => false _ => false,
} }
} }

View File

@ -6,7 +6,9 @@ use std::ops::{
use num_bigint::BigInt; use num_bigint::BigInt;
use num_rational::BigRational; use num_rational::BigRational;
use num_traits::sign::Signed; use num_traits::{Num, One, Signed, Zero};
use crate::error::SassError;
const PRECISION: usize = 10; const PRECISION: usize = 10;
@ -57,6 +59,63 @@ impl Number {
} }
} }
impl Zero for Number {
fn zero() -> Self {
Number::from(0)
}
fn is_zero(&self) -> bool {
self.val.is_zero()
}
}
impl One for Number {
fn one() -> Self {
Number::from(1)
}
fn is_one(&self) -> bool {
self.val.is_one()
}
}
impl Num for Number {
type FromStrRadixErr = SassError;
fn from_str_radix(_str: &str, _radix: u32) -> Result<Self, Self::FromStrRadixErr> {
todo!()
}
}
impl Signed for Number {
fn abs(&self) -> Self {
self.abs()
}
fn abs_sub(&self, other: &Self) -> Self {
Number {
val: self.val.abs_sub(&other.val),
}
}
fn signum(&self) -> Self {
if self.is_zero() {
Self::zero()
} else if self.is_positive() {
Self::one()
} else {
-Self::one()
}
}
fn is_positive(&self) -> bool {
self.val.is_positive()
}
fn is_negative(&self) -> bool {
self.val.is_negative()
}
}
impl fmt::LowerHex for Number { impl fmt::LowerHex for Number {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{:0>2x}", self.val.to_integer()) write!(f, "{:0>2x}", self.val.to_integer())

View File

@ -293,7 +293,7 @@ impl Value {
TokenKind::Keyword(Keyword::Through(s)) => Ok(Value::Ident(s, QuoteKind::None)), TokenKind::Keyword(Keyword::Through(s)) => Ok(Value::Ident(s, QuoteKind::None)),
TokenKind::Keyword(Keyword::To(s)) => Ok(Value::Ident(s, QuoteKind::None)), TokenKind::Keyword(Keyword::To(s)) => Ok(Value::Ident(s, QuoteKind::None)),
TokenKind::AtRule(_) => Err("expected \";\".".into()), TokenKind::AtRule(_) => Err("expected \";\".".into()),
TokenKind::Error(e) => return Err(e), TokenKind::Error(e) => Err(e),
TokenKind::Symbol(Symbol::BackSlash) => { TokenKind::Symbol(Symbol::BackSlash) => {
if let Some(tok) = toks.next() { if let Some(tok) = toks.next() {
match tok.kind { match tok.kind {