typst_library/loading/
mod.rs

1//! Data loading.
2
3#[path = "cbor.rs"]
4mod cbor_;
5#[path = "csv.rs"]
6mod csv_;
7#[path = "json.rs"]
8mod json_;
9#[path = "read.rs"]
10mod read_;
11#[path = "toml.rs"]
12mod toml_;
13#[path = "xml.rs"]
14mod xml_;
15#[path = "yaml.rs"]
16mod yaml_;
17
18use comemo::Tracked;
19use ecow::EcoString;
20use typst_syntax::{FileId, Spanned};
21
22pub use self::cbor_::*;
23pub use self::csv_::*;
24pub use self::json_::*;
25pub use self::read_::*;
26pub use self::toml_::*;
27pub use self::xml_::*;
28pub use self::yaml_::*;
29
30use crate::World;
31use crate::diag::{At, SourceResult};
32use crate::foundations::OneOrMultiple;
33use crate::foundations::{Bytes, Scope, Str, cast};
34
35/// Hook up all `data-loading` definitions.
36pub(super) fn define(global: &mut Scope) {
37    global.start_category(crate::Category::DataLoading);
38    global.define_func::<read>();
39    global.define_func::<csv>();
40    global.define_func::<json>();
41    global.define_func::<toml>();
42    global.define_func::<yaml>();
43    global.define_func::<cbor>();
44    global.define_func::<xml>();
45    global.reset_category();
46}
47
48/// Something we can retrieve byte data from.
49#[derive(Debug, Clone, PartialEq, Hash)]
50pub enum DataSource {
51    /// A path to a file.
52    Path(EcoString),
53    /// Raw bytes.
54    Bytes(Bytes),
55}
56
57cast! {
58    DataSource,
59    self => match self {
60        Self::Path(v) => v.into_value(),
61        Self::Bytes(v) => v.into_value(),
62    },
63    v: EcoString => Self::Path(v),
64    v: Bytes => Self::Bytes(v),
65}
66
67/// Loads data from a path or provided bytes.
68pub trait Load {
69    /// Bytes or a list of bytes (if there are multiple sources).
70    type Output;
71
72    /// Load the bytes.
73    fn load(&self, world: Tracked<dyn World + '_>) -> SourceResult<Self::Output>;
74}
75
76impl Load for Spanned<DataSource> {
77    type Output = Loaded;
78
79    fn load(&self, world: Tracked<dyn World + '_>) -> SourceResult<Self::Output> {
80        self.as_ref().load(world)
81    }
82}
83
84impl Load for Spanned<&DataSource> {
85    type Output = Loaded;
86
87    fn load(&self, world: Tracked<dyn World + '_>) -> SourceResult<Self::Output> {
88        match &self.v {
89            DataSource::Path(path) => {
90                let file_id = self.span.resolve_path(path).at(self.span)?;
91                let data = world.file(file_id).at(self.span)?;
92                let source = Spanned::new(LoadSource::Path(file_id), self.span);
93                Ok(Loaded::new(source, data))
94            }
95            DataSource::Bytes(data) => {
96                let source = Spanned::new(LoadSource::Bytes, self.span);
97                Ok(Loaded::new(source, data.clone()))
98            }
99        }
100    }
101}
102
103impl Load for Spanned<OneOrMultiple<DataSource>> {
104    type Output = Vec<Loaded>;
105
106    fn load(&self, world: Tracked<dyn World + '_>) -> SourceResult<Self::Output> {
107        self.as_ref().load(world)
108    }
109}
110
111impl Load for Spanned<&OneOrMultiple<DataSource>> {
112    type Output = Vec<Loaded>;
113
114    fn load(&self, world: Tracked<dyn World + '_>) -> SourceResult<Self::Output> {
115        self.v
116            .0
117            .iter()
118            .map(|source| Spanned::new(source, self.span).load(world))
119            .collect()
120    }
121}
122
123/// Data loaded from a [`DataSource`].
124#[derive(Debug, Clone, Eq, PartialEq, Hash)]
125pub struct Loaded {
126    /// Details about where `data` was loaded from.
127    pub source: Spanned<LoadSource>,
128    /// The loaded data.
129    pub data: Bytes,
130}
131
132impl Loaded {
133    pub fn new(source: Spanned<LoadSource>, bytes: Bytes) -> Self {
134        Self { source, data: bytes }
135    }
136}
137
138/// A loaded [`DataSource`].
139#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
140pub enum LoadSource {
141    Path(FileId),
142    Bytes,
143}
144
145/// A value that can be read from a file.
146#[derive(Debug, Clone, PartialEq, Hash)]
147pub enum Readable {
148    /// A decoded string.
149    Str(Str),
150    /// Raw bytes.
151    Bytes(Bytes),
152}
153
154impl Readable {
155    pub fn into_bytes(self) -> Bytes {
156        match self {
157            Self::Bytes(v) => v,
158            Self::Str(v) => Bytes::from_string(v),
159        }
160    }
161
162    pub fn into_source(self) -> DataSource {
163        DataSource::Bytes(self.into_bytes())
164    }
165}
166
167cast! {
168    Readable,
169    self => match self {
170        Self::Str(v) => v.into_value(),
171        Self::Bytes(v) => v.into_value(),
172    },
173    v: Str => Self::Str(v),
174    v: Bytes => Self::Bytes(v),
175}