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}