mirror of https://github.com/stelzo/typst.git
101 lines
3.1 KiB
Rust
101 lines
3.1 KiB
Rust
use std::cmp::Ordering;
|
|
|
|
use crate::color::{Color, RgbaColor};
|
|
use crate::pretty::pretty;
|
|
|
|
use super::*;
|
|
|
|
/// `type`: The name of a value's type.
|
|
pub fn type_(ctx: &mut EvalContext, args: &mut FuncArgs) -> Value {
|
|
match args.expect::<Value>(ctx, "value") {
|
|
Some(value) => value.type_name().into(),
|
|
None => Value::Error,
|
|
}
|
|
}
|
|
|
|
/// `repr`: The string representation of a value.
|
|
pub fn repr(ctx: &mut EvalContext, args: &mut FuncArgs) -> Value {
|
|
match args.expect::<Value>(ctx, "value") {
|
|
Some(value) => pretty(&value).into(),
|
|
None => Value::Error,
|
|
}
|
|
}
|
|
|
|
/// `len`: The length of a string, an array or a dictionary.
|
|
pub fn len(ctx: &mut EvalContext, args: &mut FuncArgs) -> Value {
|
|
match args.expect::<Spanned<Value>>(ctx, "collection") {
|
|
Some(Spanned { v: Value::Str(v), .. }) => Value::Int(v.len() as i64),
|
|
Some(Spanned { v: Value::Array(v), .. }) => Value::Int(v.len() as i64),
|
|
Some(Spanned { v: Value::Dict(v), .. }) => Value::Int(v.len() as i64),
|
|
Some(other) if other.v != Value::Error => {
|
|
ctx.diag(error!(other.span, "expected string, array or dictionary"));
|
|
Value::Error
|
|
}
|
|
_ => Value::Error,
|
|
}
|
|
}
|
|
|
|
/// `rgb`: Create an RGB(A) color.
|
|
pub fn rgb(ctx: &mut EvalContext, args: &mut FuncArgs) -> Value {
|
|
let r = args.expect(ctx, "red component");
|
|
let g = args.expect(ctx, "green component");
|
|
let b = args.expect(ctx, "blue component");
|
|
let a = args.eat(ctx);
|
|
|
|
let mut clamp = |component: Option<Spanned<f64>>, default| {
|
|
component.map_or(default, |c| {
|
|
if c.v < 0.0 || c.v > 1.0 {
|
|
ctx.diag(warning!(c.span, "should be between 0.0 and 1.0"));
|
|
}
|
|
(c.v.max(0.0).min(1.0) * 255.0).round() as u8
|
|
})
|
|
};
|
|
|
|
Value::Color(Color::Rgba(RgbaColor::new(
|
|
clamp(r, 0),
|
|
clamp(g, 0),
|
|
clamp(b, 0),
|
|
clamp(a, 255),
|
|
)))
|
|
}
|
|
|
|
/// `min`: The minimum of a sequence of values.
|
|
pub fn min(ctx: &mut EvalContext, args: &mut FuncArgs) -> Value {
|
|
minmax(ctx, args, Ordering::Less)
|
|
}
|
|
|
|
/// `max`: The maximum of a sequence of values.
|
|
pub fn max(ctx: &mut EvalContext, args: &mut FuncArgs) -> Value {
|
|
minmax(ctx, args, Ordering::Greater)
|
|
}
|
|
|
|
/// Find the minimum or maximum of a sequence of values.
|
|
fn minmax(ctx: &mut EvalContext, args: &mut FuncArgs, goal: Ordering) -> Value {
|
|
let mut extremum = None;
|
|
|
|
while let Some(value) = args.eat::<Value>(ctx) {
|
|
if let Some(prev) = &extremum {
|
|
match value.cmp(&prev) {
|
|
Some(ordering) if ordering == goal => extremum = Some(value),
|
|
Some(_) => {}
|
|
None => {
|
|
ctx.diag(error!(
|
|
args.span,
|
|
"cannot compare {} with {}",
|
|
prev.type_name(),
|
|
value.type_name(),
|
|
));
|
|
return Value::Error;
|
|
}
|
|
}
|
|
} else {
|
|
extremum = Some(value);
|
|
}
|
|
}
|
|
|
|
extremum.unwrap_or_else(|| {
|
|
args.expect::<Value>(ctx, "value");
|
|
Value::Error
|
|
})
|
|
}
|