implement builtin function random

This commit is contained in:
ConnorSkees 2020-04-05 13:42:53 -04:00
parent 03ac46d268
commit c8a59ea501
3 changed files with 53 additions and 1 deletions

View File

@ -18,7 +18,7 @@ The large features remaining are
order of operations order of operations
special case certain functions (min, max, calc, element, expression, progid, url) special case certain functions (min, max, calc, element, expression, progid, url)
all builtin selector functions (274 tests) all builtin selector functions (274 tests)
content-exists, unique-id, random, min, min content-exists, unique-id, min, min
@extend (~600 tests) @extend (~600 tests)
indented syntax (27 tests) indented syntax (27 tests)
a special parser for plain css a special parser for plain css

View File

@ -1,5 +1,10 @@
use std::collections::HashMap; use std::collections::HashMap;
#[cfg(feature = "random")]
use num_traits::{One, Signed, ToPrimitive, Zero};
#[cfg(feature = "random")]
use rand::Rng;
use super::Builtin; use super::Builtin;
use crate::unit::Unit; use crate::unit::Unit;
use crate::value::{Number, Value}; use crate::value::{Number, Value};
@ -75,4 +80,50 @@ pub(crate) fn register(f: &mut HashMap<String, Builtin>) {
Ok(Value::bool(unit1.comparable(&unit2))) Ok(Value::bool(unit1.comparable(&unit2)))
}), }),
); );
// TODO: write tests for this. how?
#[cfg(feature = "random")]
f.insert(
"random".to_owned(),
Builtin::new(|mut args, scope, super_selector| {
max_args!(args, 1);
let limit = match arg!(args, scope, super_selector, 0, "limit" = Value::Null) {
Value::Dimension(n, _) => n,
Value::Null => {
let mut rng = rand::thread_rng();
return Ok(Value::Dimension(
Number::from(rng.gen_range(0.0, 1.0)),
Unit::None,
));
}
v => return Err(format!("$limit: {} is not a number.", v).into()),
};
if limit.is_one() {
return Ok(Value::Dimension(Number::one(), Unit::None));
}
if limit.is_decimal() {
return Err(format!("$limit: {} is not an int.", limit).into());
}
if limit.is_zero() || limit.is_negative() {
return Err(format!("$limit: Must be greater than 0, was {}.", limit).into());
}
let limit = match limit.to_integer().to_u32() {
Some(n) => n,
None => {
return Err(
format!("max must be in range 0 < max ≤ 2^32, was {}", limit).into(),
)
}
};
let mut rng = rand::thread_rng();
Ok(Value::Dimension(
Number::from(rng.gen_range(0, limit)),
Unit::None,
))
}),
);
} }

View File

@ -161,6 +161,7 @@ impl From<f64> for Number {
from_integer!(u16); from_integer!(u16);
from_integer!(usize); from_integer!(usize);
from_integer!(i32); from_integer!(i32);
from_integer!(u32);
from_integer!(u8); from_integer!(u8);
impl Display for Number { impl Display for Number {