summaryrefslogtreecommitdiff
path: root/library/src/base/create.rs
diff options
context:
space:
mode:
authorLaurenz <laurmaedje@gmail.com>2022-11-26 16:59:20 +0100
committerLaurenz <laurmaedje@gmail.com>2022-11-26 17:13:31 +0100
commit0579fd4409375aaa9fd8e87a06fd59097b5fcd97 (patch)
tree0ccf1d6218806b11d83998d568ae1fb0570c67b7 /library/src/base/create.rs
parent9db6e533cd8a1d925a7daad92e1b99e6f98ac773 (diff)
Reorganize library base
Diffstat (limited to 'library/src/base/create.rs')
-rw-r--r--library/src/base/create.rs149
1 files changed, 149 insertions, 0 deletions
diff --git a/library/src/base/create.rs b/library/src/base/create.rs
new file mode 100644
index 00000000..be8e822f
--- /dev/null
+++ b/library/src/base/create.rs
@@ -0,0 +1,149 @@
+use std::str::FromStr;
+
+use typst::model::Regex;
+
+use crate::prelude::*;
+
+/// Convert a value to an integer.
+pub fn int(_: &Vm, args: &mut Args) -> SourceResult<Value> {
+ let Spanned { v, span } = args.expect("value")?;
+ Ok(Value::Int(match v {
+ Value::Bool(v) => v as i64,
+ Value::Int(v) => v,
+ Value::Float(v) => v as i64,
+ Value::Str(v) => match v.parse() {
+ Ok(v) => v,
+ Err(_) => bail!(span, "invalid integer"),
+ },
+ v => bail!(span, "cannot convert {} to integer", v.type_name()),
+ }))
+}
+
+/// Convert a value to a float.
+pub fn float(_: &Vm, args: &mut Args) -> SourceResult<Value> {
+ let Spanned { v, span } = args.expect("value")?;
+ Ok(Value::Float(match v {
+ Value::Int(v) => v as f64,
+ Value::Float(v) => v,
+ Value::Str(v) => match v.parse() {
+ Ok(v) => v,
+ Err(_) => bail!(span, "invalid float"),
+ },
+ v => bail!(span, "cannot convert {} to float", v.type_name()),
+ }))
+}
+
+/// Create a grayscale color.
+pub fn luma(_: &Vm, args: &mut Args) -> SourceResult<Value> {
+ let Component(luma) = args.expect("gray component")?;
+ Ok(Value::Color(LumaColor::new(luma).into()))
+}
+
+/// Create an RGB(A) color.
+pub fn rgb(_: &Vm, args: &mut Args) -> SourceResult<Value> {
+ Ok(Value::Color(if let Some(string) = args.find::<Spanned<EcoString>>()? {
+ match RgbaColor::from_str(&string.v) {
+ Ok(color) => color.into(),
+ Err(msg) => bail!(string.span, msg),
+ }
+ } else {
+ let Component(r) = args.expect("red component")?;
+ let Component(g) = args.expect("green component")?;
+ let Component(b) = args.expect("blue component")?;
+ let Component(a) = args.eat()?.unwrap_or(Component(255));
+ RgbaColor::new(r, g, b, a).into()
+ }))
+}
+
+/// Create a CMYK color.
+pub fn cmyk(_: &Vm, args: &mut Args) -> SourceResult<Value> {
+ let RatioComponent(c) = args.expect("cyan component")?;
+ let RatioComponent(m) = args.expect("magenta component")?;
+ let RatioComponent(y) = args.expect("yellow component")?;
+ let RatioComponent(k) = args.expect("key component")?;
+ Ok(Value::Color(CmykColor::new(c, m, y, k).into()))
+}
+
+/// An integer or ratio component.
+struct Component(u8);
+
+castable! {
+ Component,
+ Expected: "integer or ratio",
+ Value::Int(v) => match v {
+ 0 ..= 255 => Self(v as u8),
+ _ => Err("must be between 0 and 255")?,
+ },
+ Value::Ratio(v) => if (0.0 ..= 1.0).contains(&v.get()) {
+ Self((v.get() * 255.0).round() as u8)
+ } else {
+ Err("must be between 0% and 100%")?
+ },
+}
+
+/// A component that must be a ratio.
+struct RatioComponent(u8);
+
+castable! {
+ RatioComponent,
+ Expected: "ratio",
+ Value::Ratio(v) => if (0.0 ..= 1.0).contains(&v.get()) {
+ Self((v.get() * 255.0).round() as u8)
+ } else {
+ Err("must be between 0% and 100%")?
+ },
+}
+
+/// Convert a value to a string.
+pub fn str(_: &Vm, args: &mut Args) -> SourceResult<Value> {
+ let Spanned { v, span } = args.expect("value")?;
+ Ok(Value::Str(match v {
+ Value::Int(v) => format_str!("{}", v),
+ Value::Float(v) => format_str!("{}", v),
+ Value::Label(label) => label.0.into(),
+ Value::Str(v) => v,
+ v => bail!(span, "cannot convert {} to string", v.type_name()),
+ }))
+}
+
+/// Create a blind text string.
+pub fn lorem(_: &Vm, args: &mut Args) -> SourceResult<Value> {
+ let words: usize = args.expect("number of words")?;
+ Ok(Value::Str(lipsum::lipsum(words).into()))
+}
+
+/// Create a label from a string.
+pub fn label(_: &Vm, args: &mut Args) -> SourceResult<Value> {
+ Ok(Value::Label(Label(args.expect("string")?)))
+}
+
+/// Create a regular expression from a string.
+pub fn regex(_: &Vm, args: &mut Args) -> SourceResult<Value> {
+ let Spanned { v, span } = args.expect::<Spanned<EcoString>>("regular expression")?;
+ Ok(Regex::new(&v).at(span)?.into())
+}
+
+/// Create an array consisting of a sequence of numbers.
+pub fn range(_: &Vm, args: &mut Args) -> SourceResult<Value> {
+ let first = args.expect::<i64>("end")?;
+ let (start, end) = match args.eat::<i64>()? {
+ Some(second) => (first, second),
+ None => (0, first),
+ };
+
+ let step: i64 = match args.named("step")? {
+ Some(Spanned { v: 0, span }) => bail!(span, "step must not be zero"),
+ Some(Spanned { v, .. }) => v,
+ None => 1,
+ };
+
+ let mut x = start;
+ let mut seq = vec![];
+
+ while x.cmp(&end) == 0.cmp(&step) {
+ seq.push(Value::Int(x));
+ x += step;
+ }
+
+ Ok(Value::Array(Array::from_vec(seq)))
+}