diff options
| author | Laurenz <laurmaedje@gmail.com> | 2023-08-04 15:09:01 +0200 |
|---|---|---|
| committer | Laurenz <laurmaedje@gmail.com> | 2023-08-04 15:46:46 +0200 |
| commit | b8b0137504d388efbe2d1ba5082c0dcabcd8bc8a (patch) | |
| tree | 825abab07230c702bca8efee026d9b98ecfa2aae /crates/typst-library/src/compute/construct.rs | |
| parent | 028d2f53085022c39945b1a99c9dc78eb8069d4a (diff) | |
Bytes type
- Moves `Bytes` from `util` to `eval` module
- Accepts bytes in `str` function for bytes -> str conversion
- Adds `bytes` function for str | array -> bytes conversion
- Adds `array` function for bytes -> array conversion
- Adds `len`, `at`, and `slice` methods for bytes
- Adds `encoding` parameter to `read` function
Diffstat (limited to 'crates/typst-library/src/compute/construct.rs')
| -rw-r--r-- | crates/typst-library/src/compute/construct.rs | 141 |
1 files changed, 109 insertions, 32 deletions
diff --git a/crates/typst-library/src/compute/construct.rs b/crates/typst-library/src/compute/construct.rs index 1ce676bb..4329f259 100644 --- a/crates/typst-library/src/compute/construct.rs +++ b/crates/typst-library/src/compute/construct.rs @@ -3,7 +3,7 @@ use std::str::FromStr; use time::{Month, PrimitiveDateTime}; -use typst::eval::{Datetime, Module, Regex}; +use typst::eval::{Bytes, Datetime, Module, Reflect, Regex}; use crate::prelude::*; @@ -37,9 +37,9 @@ pub struct ToInt(i64); cast! { ToInt, v: bool => Self(v as i64), - v: i64 => Self(v), v: f64 => Self(v as i64), v: EcoString => Self(v.parse().map_err(|_| eco_format!("invalid integer: {}", v))?), + v: i64 => Self(v), } /// Converts a value to a float. @@ -77,9 +77,9 @@ cast! { ToFloat, v: bool => Self(v as i64 as f64), v: i64 => Self(v as f64), - v: f64 => Self(v), v: Ratio => Self(v.get()), v: EcoString => Self(v.parse().map_err(|_| eco_format!("invalid float: {}", v))?), + v: f64 => Self(v), } /// Creates a grayscale color. @@ -486,6 +486,7 @@ cast! { /// optional `base` parameter. /// - Floats are formatted in base 10 and never in exponential notation. /// - From labels the name is extracted. +/// - Bytes are decoded as UTF-8. /// /// If you wish to convert from and to Unicode code points, see /// [`str.to-unicode`]($func/str.to-unicode) and @@ -545,6 +546,11 @@ cast! { v: i64 => Self::Int(v), v: f64 => Self::Str(format_str!("{}", v)), v: Label => Self::Str(v.0.into()), + v: Bytes => Self::Str( + std::str::from_utf8(&v) + .map_err(|_| "bytes are not valid utf-8")? + .into() + ), v: Str => Self::Str(v), } @@ -633,35 +639,6 @@ cast! { }, } -/// Creates a label from a string. -/// -/// Inserting a label into content attaches it to the closest previous element -/// that is not a space. Then, the element can be [referenced]($func/ref) and -/// styled through the label. -/// -/// ## Example { #example } -/// ```example -/// #show <a>: set text(blue) -/// #show label("b"): set text(red) -/// -/// = Heading <a> -/// *Strong* #label("b") -/// ``` -/// -/// ## Syntax { #syntax } -/// This function also has dedicated syntax: You can create a label by enclosing -/// its name in angle brackets. This works both in markup and code. -/// -/// Display: Label -/// Category: construct -#[func] -pub fn label( - /// The name of the label. - name: EcoString, -) -> Label { - Label(name) -} - /// Creates a regular expression from a string. /// /// The result can be used as a @@ -701,6 +678,106 @@ pub fn regex( Regex::new(®ex.v).at(regex.span) } +/// Converts a value to bytes. +/// +/// - Strings are encoded in UTF-8. +/// - Arrays of integers between `{0}` and `{255}` are converted directly. The +/// dedicated byte representation is much more efficient than the array +/// representation and thus typically used for large byte buffers (e.g. image +/// data). +/// +/// ```example +/// #bytes("Hello 😃") \ +/// #bytes((123, 160, 22, 0)) +/// ``` +/// +/// Display: Bytes +/// Category: construct +#[func] +pub fn bytes( + /// The value that should be converted to a string. + value: ToBytes, +) -> Bytes { + value.0 +} + +/// A value that can be cast to bytes. +pub struct ToBytes(Bytes); + +cast! { + ToBytes, + v: Str => Self(v.as_bytes().into()), + v: Array => Self(v.iter() + .map(|v| match v { + Value::Int(byte @ 0..=255) => Ok(*byte as u8), + Value::Int(_) => bail!("number must be between 0 and 255"), + value => Err(<u8 as Reflect>::error(value)), + }) + .collect::<Result<Vec<u8>, _>>()? + .into() + ), + v: Bytes => Self(v), +} + +/// Creates a label from a string. +/// +/// Inserting a label into content attaches it to the closest previous element +/// that is not a space. Then, the element can be [referenced]($func/ref) and +/// styled through the label. +/// +/// ## Example { #example } +/// ```example +/// #show <a>: set text(blue) +/// #show label("b"): set text(red) +/// +/// = Heading <a> +/// *Strong* #label("b") +/// ``` +/// +/// ## Syntax { #syntax } +/// This function also has dedicated syntax: You can create a label by enclosing +/// its name in angle brackets. This works both in markup and code. +/// +/// Display: Label +/// Category: construct +#[func] +pub fn label( + /// The name of the label. + name: EcoString, +) -> Label { + Label(name) +} + +/// Converts a value to an array. +/// +/// Note that this function is only intended for conversion of a collection-like +/// value to an array, not for creation of an array from individual items. Use +/// the array syntax `(1, 2, 3)` (or `(1,)` for a single-element array) instead. +/// +/// ```example +/// #let hi = "Hello 😃" +/// #array(bytes(hi)) +/// ``` +/// +/// Display: Array +/// Category: construct +#[func] +pub fn array( + /// The value that should be converted to an array. + value: ToArray, +) -> Array { + value.0 +} + +/// A value that can be cast to bytes. +pub struct ToArray(Array); + +cast! { + ToArray, + v: Bytes => Self(v.iter().map(|&b| Value::Int(b as i64)).collect()), + v: Array => Self(v), +} + /// Creates an array consisting of consecutive integers. /// /// If you pass just one positional parameter, it is interpreted as the `end` of |
