From d3ca2ff4ec32cb96b5f742ac48a4d09321ab5966 Mon Sep 17 00:00:00 2001 From: Beiri22 Date: Wed, 30 Aug 2023 17:11:21 +0200 Subject: [PATCH] Support CBOR binary serialization / deserialization (#2000) --- Cargo.lock | 36 ++++++++++++- crates/typst-library/Cargo.toml | 1 + crates/typst-library/src/compute/data.rs | 66 ++++++++++++++++++++++++ crates/typst-library/src/compute/mod.rs | 1 + 4 files changed, 103 insertions(+), 1 deletion(-) diff --git a/Cargo.lock b/Cargo.lock index 00bf3e41f..62cf2e33e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -298,6 +298,33 @@ dependencies = [ "winapi", ] +[[package]] +name = "ciborium" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "effd91f6c78e5a4ace8a5d3c0b6bfaec9e2baaef55f3efc00e45fb2e477ee926" +dependencies = [ + "ciborium-io", + "ciborium-ll", + "serde", +] + +[[package]] +name = "ciborium-io" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cdf919175532b369853f5d5e20b26b43112613fd6fe7aee757e35f7a44642656" + +[[package]] +name = "ciborium-ll" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "defaa24ecc093c77630e6c15e17c51f5e187bf35ee514f4e2d67baaa96dae22b" +dependencies = [ + "ciborium-io", + "half 1.8.2", +] + [[package]] name = "cipher" version = "0.4.4" @@ -668,7 +695,7 @@ checksum = "d1e481eb11a482815d3e9d618db8c42a93207134662873809335a92327440c18" dependencies = [ "bit_field", "flume", - "half", + "half 2.2.1", "lebe", "miniz_oxide", "rayon-core", @@ -847,6 +874,12 @@ dependencies = [ "weezl", ] +[[package]] +name = "half" +version = "1.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eabb4a44450da02c90444cf74558da904edde8fb4e9035a9a6a4e15445af0bd7" + [[package]] name = "half" version = "2.2.1" @@ -2927,6 +2960,7 @@ version = "0.7.0" dependencies = [ "az", "chinese-number", + "ciborium", "comemo", "csv", "ecow", diff --git a/crates/typst-library/Cargo.toml b/crates/typst-library/Cargo.toml index aa1de0202..f4c5b1edd 100644 --- a/crates/typst-library/Cargo.toml +++ b/crates/typst-library/Cargo.toml @@ -34,6 +34,7 @@ kurbo = "0.9" lipsum = "0.9" log = "0.4" once_cell = "1" +ciborium = "0.2.1" roxmltree = "0.18" rustybuzz = "0.7" serde_json = "1" diff --git a/crates/typst-library/src/compute/data.rs b/crates/typst-library/src/compute/data.rs index cd28d61e0..f20623ae3 100644 --- a/crates/typst-library/src/compute/data.rs +++ b/crates/typst-library/src/compute/data.rs @@ -505,6 +505,72 @@ fn format_yaml_error(error: serde_yaml::Error) -> EcoString { eco_format!("failed to parse yaml file: {}", error.to_string().trim()) } +/// Reads structured data from a CBOR file. +/// +/// The file must contain a valid cbor serialization. Mappings will be +/// converted into Typst dictionaries, and sequences will be converted into +/// Typst arrays. Strings and booleans will be converted into the Typst +/// equivalents, null-values (`null`, `~` or empty ``) will be converted into +/// `{none}`, and numbers will be converted to floats or integers depending on +/// whether they are whole numbers. +/// +/// The function returns a dictionary or value or an array, depending on +/// the input. +/// +/// Display: CBOR +/// Category: data-loading +#[func] +#[scope( + scope.define("decode", cbor_decode_func()); + scope.define("encode", cbor_encode_func()); + scope +)] +pub fn cbor( + /// Path to a CBOR file. + path: Spanned, + /// The virtual machine. + vm: &mut Vm, +) -> SourceResult { + let Spanned { v: path, span } = path; + let id = vm.resolve_path(&path).at(span)?; + let data = vm.world().file(id).at(span)?; + cbor_decode(Spanned::new(data, span)) +} + +/// Reads structured data from CBOR bytes. +/// +/// Display: CBOR +/// Category: data-loading +#[func] +pub fn cbor_decode( + /// cbor data. + data: Spanned, +) -> SourceResult { + let Spanned { v: data, span } = data; + let value: Value = ciborium::from_reader(data.as_slice()) + .map_err(|e| eco_format!("failed to parse cbor: {e}")) + .at(span)?; + Ok(value) +} + +/// Encode structured data into CBOR bytes. +/// +/// Display: CBOR +/// Category: data-loading +#[func] +pub fn cbor_encode( + /// Value to be encoded. + value: Spanned, +) -> SourceResult { + let Spanned { v: value, span } = value; + + let mut res = Vec::new(); + ciborium::into_writer(&value, &mut res) + .map(|_| res.into()) + .map_err(|e| eco_format!("failed to encode value as cbor: {e}")) + .at(span) +} + /// Reads structured data from an XML file. /// /// The XML file is parsed into an array of dictionaries and strings. XML nodes diff --git a/crates/typst-library/src/compute/mod.rs b/crates/typst-library/src/compute/mod.rs index 599ac72fb..ca95f7b72 100644 --- a/crates/typst-library/src/compute/mod.rs +++ b/crates/typst-library/src/compute/mod.rs @@ -38,6 +38,7 @@ pub(super) fn define(global: &mut Scope) { global.define("json", json_func()); global.define("toml", toml_func()); global.define("yaml", yaml_func()); + global.define("cbor", cbor_func()); global.define("xml", xml_func()); global.define("calc", calc::module()); global.define("plugin", plugin_func());