typst_library/loading/cbor.rs
1use ecow::eco_format;
2use typst_syntax::Spanned;
3
4use crate::diag::{At, SourceResult};
5use crate::engine::Engine;
6use crate::foundations::{Bytes, Value, func, scope};
7use crate::loading::{DataSource, Load};
8
9/// Reads structured data from a CBOR file.
10///
11/// The file must contain a valid CBOR serialization. The CBOR values will be
12/// converted into corresponding Typst values as listed in the
13/// [table below](#conversion).
14///
15/// The function returns a dictionary, an array or, depending on the CBOR file,
16/// another CBOR data type.
17///
18/// # Conversion details { #conversion }
19///
20/// | CBOR value | Converted into Typst |
21/// | ---------- | ---------------------- |
22/// | integer | [`int`] (or [`float`]) |
23/// | bytes | [`bytes`] |
24/// | float | [`float`] |
25/// | text | [`str`] |
26/// | bool | [`bool`] |
27/// | null | `{none}` |
28/// | array | [`array`] |
29/// | map | [`dictionary`] |
30///
31/// | Typst value | Converted into CBOR |
32/// | ------------------------------------- | ---------------------------- |
33/// | types that can be converted from CBOR | corresponding CBOR value |
34/// | [`symbol`] | text |
35/// | [`content`] | a map describing the content |
36/// | other types ([`length`], etc.) | text via [`repr`] |
37///
38/// ## Notes
39///
40/// - Be aware that CBOR integers larger than 2<sup>63</sup>-1 or smaller than
41/// -2<sup>63</sup> will be converted to floating point numbers, which may
42/// result in an approximative value.
43///
44/// - CBOR tags are not supported, and an error will be thrown.
45///
46/// - The `repr` function is [for debugging purposes only]($repr/#debugging-only),
47/// and its output is not guaranteed to be stable across Typst versions.
48#[func(scope, title = "CBOR")]
49pub fn cbor(
50 engine: &mut Engine,
51 /// A [path]($syntax/#paths) to a CBOR file or raw CBOR bytes.
52 source: Spanned<DataSource>,
53) -> SourceResult<Value> {
54 let loaded = source.load(engine.world)?;
55 ciborium::from_reader(loaded.data.as_slice())
56 .map_err(|err| eco_format!("failed to parse CBOR ({err})"))
57 .at(source.span)
58}
59
60#[scope]
61impl cbor {
62 /// Reads structured data from CBOR bytes.
63 #[func(title = "Decode CBOR")]
64 #[deprecated(
65 message = "`cbor.decode` is deprecated, directly pass bytes to `cbor` instead",
66 until = "0.15.0"
67 )]
68 pub fn decode(
69 engine: &mut Engine,
70 /// CBOR data.
71 data: Spanned<Bytes>,
72 ) -> SourceResult<Value> {
73 cbor(engine, data.map(DataSource::Bytes))
74 }
75
76 /// Encode structured data into CBOR bytes.
77 #[func(title = "Encode CBOR")]
78 pub fn encode(
79 /// Value to be encoded.
80 value: Spanned<Value>,
81 ) -> SourceResult<Bytes> {
82 let Spanned { v: value, span } = value;
83 let mut res = Vec::new();
84 ciborium::into_writer(&value, &mut res)
85 .map(|_| Bytes::new(res))
86 .map_err(|err| eco_format!("failed to encode value as CBOR ({err})"))
87 .at(span)
88 }
89}