diff --git a/src/builtin/color/hsl.rs b/src/builtin/color/hsl.rs index d61d3d6..9c8677f 100644 --- a/src/builtin/color/hsl.rs +++ b/src/builtin/color/hsl.rs @@ -10,61 +10,149 @@ pub(crate) fn register(f: &mut HashMap) { f.insert( "hsl".to_owned(), Box::new(|args, _| { - let hue = match arg!(args, 0, "hue") { - Value::Dimension(n, _) => n, - v => return Err(format!("$hue: {} is not a number.", v).into()), - }; - let saturation = match arg!(args, 1, "saturation") { - Value::Dimension(n, _) => n / Number::from(100), - v => return Err(format!("$saturation: {} is not a number.", v).into()), - }; - let luminance = match arg!(args, 2, "luminance") { - Value::Dimension(n, _) => n / Number::from(100), - v => return Err(format!("$luminance: {} is not a number.", v).into()), - }; - let alpha = match arg!( - args, - 3, - "alpha" = Value::Dimension(Number::from(1), Unit::None) - ) { - Value::Dimension(n, Unit::None) => n, - Value::Dimension(n, Unit::Percent) => n / Number::from(100), - v @ Value::Dimension(..) => { - return Err(format!("$alpha: Expected {} to have no units or \"%\".", v).into()) + if args.len() == 1 { + let mut channels = match arg!(args, 0, "channels") { + Value::List(v, _) => v, + _ => return Err("Missing element $green.".into()), + }; + + if channels.len() > 3 { + return Err(format!( + "Only 3 elements allowed, but {} were passed.", + channels.len() + ) + .into()); } - v => return Err(format!("$alpha: {} is not a number.", v).into()), - }; - Ok(Value::Color(Color::from_hsla( - hue, saturation, luminance, alpha, - ))) + + let luminance = match channels.pop() { + Some(Value::Dimension(n, _)) => n / Number::from(100), + Some(v) => return Err(format!("$luminance: {} is not a color", v).into()), + None => return Err("Missing element $luminance.".into()), + }; + + let saturation = match channels.pop() { + Some(Value::Dimension(n, _)) => n / Number::from(100), + Some(v) => return Err(format!("$saturation: {} is not a color", v).into()), + None => return Err("Missing element $saturation.".into()), + }; + + let hue = match channels.pop() { + Some(Value::Dimension(n, _)) => n, + Some(v) => return Err(format!("$hue: {} is not a color", v).into()), + None => return Err("Missing element $hue.".into()), + }; + + Ok(Value::Color(Color::from_hsla( + hue, + saturation, + luminance, + Number::from(1), + ))) + } else { + let hue = match arg!(args, 0, "hue") { + Value::Dimension(n, _) => n, + v => return Err(format!("$hue: {} is not a number.", v).into()), + }; + let saturation = match arg!(args, 1, "saturation") { + Value::Dimension(n, _) => n / Number::from(100), + v => return Err(format!("$saturation: {} is not a number.", v).into()), + }; + let luminance = match arg!(args, 2, "luminance") { + Value::Dimension(n, _) => n / Number::from(100), + v => return Err(format!("$luminance: {} is not a number.", v).into()), + }; + let alpha = match arg!( + args, + 3, + "alpha" = Value::Dimension(Number::from(1), Unit::None) + ) { + Value::Dimension(n, Unit::None) => n, + Value::Dimension(n, Unit::Percent) => n / Number::from(100), + v @ Value::Dimension(..) => { + return Err( + format!("$alpha: Expected {} to have no units or \"%\".", v).into() + ) + } + v => return Err(format!("$alpha: {} is not a number.", v).into()), + }; + Ok(Value::Color(Color::from_hsla( + hue, saturation, luminance, alpha, + ))) + } }), ); f.insert( "hsla".to_owned(), Box::new(|args, _| { - let hue = match arg!(args, 0, "hue") { - Value::Dimension(n, _) => n, - v => return Err(format!("$hue: {} is not a number.", v).into()), - }; - let saturation = match arg!(args, 1, "saturation") { - Value::Dimension(n, _) => n / Number::from(100), - v => return Err(format!("$saturation: {} is not a number.", v).into()), - }; - let luminance = match arg!(args, 2, "luminance") { - Value::Dimension(n, _) => n / Number::from(100), - v => return Err(format!("$luminance: {} is not a number.", v).into()), - }; - let alpha = match arg!(args, 3, "alpha") { - Value::Dimension(n, Unit::None) => n, - Value::Dimension(n, Unit::Percent) => n / Number::from(100), - v @ Value::Dimension(..) => { - return Err(format!("$alpha: Expected {} to have no units or \"%\".", v).into()) + if args.len() == 1 { + let mut channels = match arg!(args, 0, "channels") { + Value::List(v, _) => v, + _ => return Err("Missing element $green.".into()), + }; + + if channels.len() > 3 { + return Err(format!( + "Only 3 elements allowed, but {} were passed.", + channels.len() + ) + .into()); } - v => return Err(format!("$alpha: {} is not a number.", v).into()), - }; - Ok(Value::Color(Color::from_hsla( - hue, saturation, luminance, alpha, - ))) + + let luminance = match channels.pop() { + Some(Value::Dimension(n, _)) => n / Number::from(100), + Some(v) => return Err(format!("$luminance: {} is not a color", v).into()), + None => return Err("Missing element $luminance.".into()), + }; + + let saturation = match channels.pop() { + Some(Value::Dimension(n, _)) => n / Number::from(100), + Some(v) => return Err(format!("$saturation: {} is not a color", v).into()), + None => return Err("Missing element $saturation.".into()), + }; + + let hue = match channels.pop() { + Some(Value::Dimension(n, _)) => n, + Some(v) => return Err(format!("$hue: {} is not a color", v).into()), + None => return Err("Missing element $hue.".into()), + }; + + Ok(Value::Color(Color::from_hsla( + hue, + saturation, + luminance, + Number::from(1), + ))) + } else { + let hue = match arg!(args, 0, "hue") { + Value::Dimension(n, _) => n, + v => return Err(format!("$hue: {} is not a number.", v).into()), + }; + let saturation = match arg!(args, 1, "saturation") { + Value::Dimension(n, _) => n / Number::from(100), + v => return Err(format!("$saturation: {} is not a number.", v).into()), + }; + let luminance = match arg!(args, 2, "luminance") { + Value::Dimension(n, _) => n / Number::from(100), + v => return Err(format!("$luminance: {} is not a number.", v).into()), + }; + let alpha = match arg!( + args, + 3, + "alpha" = Value::Dimension(Number::from(1), Unit::None) + ) { + Value::Dimension(n, Unit::None) => n, + Value::Dimension(n, Unit::Percent) => n / Number::from(100), + v @ Value::Dimension(..) => { + return Err( + format!("$alpha: Expected {} to have no units or \"%\".", v).into() + ) + } + v => return Err(format!("$alpha: {} is not a number.", v).into()), + }; + Ok(Value::Color(Color::from_hsla( + hue, saturation, luminance, alpha, + ))) + } }), ); f.insert( diff --git a/src/builtin/color/rgb.rs b/src/builtin/color/rgb.rs index 5c8b74d..e04156c 100644 --- a/src/builtin/color/rgb.rs +++ b/src/builtin/color/rgb.rs @@ -15,25 +15,37 @@ pub(crate) fn register(f: &mut HashMap) { _ => return Err("Missing element $green.".into()), }; - assert_eq!(channels.len(), 3_usize); + if channels.len() > 3 { + return Err(format!( + "Only 3 elements allowed, but {} were passed.", + channels.len() + ) + .into()); + } let blue = match channels.pop() { Some(Value::Dimension(n, Unit::None)) => n, - Some(Value::Dimension(n, Unit::Percent)) => (n / Number::from(100)) * Number::from(255), + Some(Value::Dimension(n, Unit::Percent)) => { + (n / Number::from(100)) * Number::from(255) + } Some(v) => return Err(format!("$blue: {} is not a color", v).into()), None => return Err("Missing element $blue.".into()), }; let green = match channels.pop() { Some(Value::Dimension(n, Unit::None)) => n, - Some(Value::Dimension(n, Unit::Percent)) => (n / Number::from(100)) * Number::from(255), + Some(Value::Dimension(n, Unit::Percent)) => { + (n / Number::from(100)) * Number::from(255) + } Some(v) => return Err(format!("$green: {} is not a color", v).into()), None => return Err("Missing element $green.".into()), }; let red = match channels.pop() { Some(Value::Dimension(n, Unit::None)) => n, - Some(Value::Dimension(n, Unit::Percent)) => (n / Number::from(100)) * Number::from(255), + Some(Value::Dimension(n, Unit::Percent)) => { + (n / Number::from(100)) * Number::from(255) + } Some(v) => return Err(format!("$red: {} is not a color", v).into()), None => return Err("Missing element $red.".into()), }; @@ -121,25 +133,37 @@ pub(crate) fn register(f: &mut HashMap) { _ => return Err("Missing element $green.".into()), }; - assert_eq!(channels.len(), 3_usize); + if channels.len() > 3 { + return Err(format!( + "Only 3 elements allowed, but {} were passed.", + channels.len() + ) + .into()); + } let blue = match channels.pop() { Some(Value::Dimension(n, Unit::None)) => n, - Some(Value::Dimension(n, Unit::Percent)) => (n / Number::from(100)) * Number::from(255), + Some(Value::Dimension(n, Unit::Percent)) => { + (n / Number::from(100)) * Number::from(255) + } Some(v) => return Err(format!("$blue: {} is not a color", v).into()), None => return Err("Missing element $blue.".into()), }; let green = match channels.pop() { Some(Value::Dimension(n, Unit::None)) => n, - Some(Value::Dimension(n, Unit::Percent)) => (n / Number::from(100)) * Number::from(255), + Some(Value::Dimension(n, Unit::Percent)) => { + (n / Number::from(100)) * Number::from(255) + } Some(v) => return Err(format!("$green: {} is not a color", v).into()), None => return Err("Missing element $green.".into()), }; let red = match channels.pop() { Some(Value::Dimension(n, Unit::None)) => n, - Some(Value::Dimension(n, Unit::Percent)) => (n / Number::from(100)) * Number::from(255), + Some(Value::Dimension(n, Unit::Percent)) => { + (n / Number::from(100)) * Number::from(255) + } Some(v) => return Err(format!("$red: {} is not a color", v).into()), None => return Err("Missing element $red.".into()), }; diff --git a/tests/color.rs b/tests/color.rs index e57f7f3..a98848b 100644 --- a/tests/color.rs +++ b/tests/color.rs @@ -501,3 +501,18 @@ test!( // "a {\n color: ie_hex-str(rgba(0, 255, 0, 0.5));\n}\n", // "a {\n color: #8000FF00;\n}\n" // ); +test!( + rgba_1_arg, + "a {\n color: rgba(74.7% 173 93%);\n}\n", + "a {\n color: #beaded;\n}\n" +); +test!( + hsla_1_arg, + "a {\n color: hsla(60 60% 50%);\n}\n", + "a {\n color: #cccc33;\n}\n" +); +test!( + hsla_1_arg_weird_units, + "a {\n color: hsla(60foo 60foo 50foo);\n}\n", + "a {\n color: #cccc33;\n}\n" +);