typst_library/loading/
mod.rs1#[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
18pub use self::cbor_::*;
19pub use self::csv_::*;
20pub use self::json_::*;
21pub use self::read_::*;
22pub use self::toml_::*;
23pub use self::xml_::*;
24pub use self::yaml_::*;
25
26use comemo::Tracked;
27use typst_syntax::{FileId, Spanned};
28
29use crate::World;
30use crate::diag::{At, HintedString, SourceResult};
31use crate::foundations::{Bytes, OneOrMultiple, PathOrStr, Scope, Str, cast};
32
33pub(super) fn define(global: &mut Scope) {
35 global.start_category(crate::Category::DataLoading);
36 global.define_func::<read>();
37 global.define_func::<csv>();
38 global.define_func::<json>();
39 global.define_func::<toml>();
40 global.define_func::<yaml>();
41 global.define_func::<cbor>();
42 global.define_func::<xml>();
43 global.reset_category();
44}
45
46#[derive(Debug, Clone, PartialEq, Hash)]
48pub enum DataSource {
49 Path(PathOrStr),
51 Bytes(Bytes),
53}
54
55cast! {
56 DataSource,
57 self => match self {
58 Self::Path(v) => v.into_value(),
59 Self::Bytes(v) => v.into_value(),
60 },
61 v: PathOrStr => Self::Path(v),
62 v: Bytes => Self::Bytes(v),
63}
64
65pub trait Load {
67 type Output;
69
70 fn load(&self, world: Tracked<dyn World + '_>) -> SourceResult<Self::Output>;
72}
73
74impl Load for Spanned<DataSource> {
75 type Output = Loaded;
76
77 fn load(&self, world: Tracked<dyn World + '_>) -> SourceResult<Self::Output> {
78 self.as_ref().load(world)
79 }
80}
81
82impl Load for Spanned<&DataSource> {
83 type Output = Loaded;
84
85 fn load(&self, world: Tracked<dyn World + '_>) -> SourceResult<Self::Output> {
86 match self.v {
87 DataSource::Path(path) => {
88 let resolved =
89 path.resolve_if_some(self.span.id()).at(self.span)?.intern();
90 let data = world
91 .file(resolved)
92 .map_err(|error| {
93 let mut hinted = HintedString::from(error);
94 if let PathOrStr::Str(string) = &path
95 && (string.as_str().starts_with("http://")
96 || string.as_str().starts_with("https://"))
97 {
98 hinted.hint("network access is not supported");
99 }
100 hinted
101 })
102 .at(self.span)?;
103 let source = Spanned::new(LoadSource::Path(resolved), self.span);
104 Ok(Loaded::new(source, data))
105 }
106 DataSource::Bytes(data) => {
107 let source = Spanned::new(LoadSource::Bytes, self.span);
108 Ok(Loaded::new(source, data.clone()))
109 }
110 }
111 }
112}
113
114impl Load for Spanned<OneOrMultiple<DataSource>> {
115 type Output = Vec<Loaded>;
116
117 fn load(&self, world: Tracked<dyn World + '_>) -> SourceResult<Self::Output> {
118 self.as_ref().load(world)
119 }
120}
121
122impl Load for Spanned<&OneOrMultiple<DataSource>> {
123 type Output = Vec<Loaded>;
124
125 fn load(&self, world: Tracked<dyn World + '_>) -> SourceResult<Self::Output> {
126 self.v
127 .0
128 .iter()
129 .map(|source| Spanned::new(source, self.span).load(world))
130 .collect()
131 }
132}
133
134#[derive(Debug, Clone, Eq, PartialEq, Hash)]
136pub struct Loaded {
137 pub source: Spanned<LoadSource>,
139 pub data: Bytes,
141}
142
143impl Loaded {
144 pub fn new(source: Spanned<LoadSource>, bytes: Bytes) -> Self {
145 Self { source, data: bytes }
146 }
147}
148
149#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
151pub enum LoadSource {
152 Path(FileId),
153 Bytes,
154}
155
156#[derive(Debug, Clone, PartialEq, Hash)]
158pub enum Readable {
159 Str(Str),
161 Bytes(Bytes),
163}
164
165impl Readable {
166 pub fn into_bytes(self) -> Bytes {
167 match self {
168 Self::Bytes(v) => v,
169 Self::Str(v) => Bytes::from_string(v),
170 }
171 }
172
173 pub fn into_source(self) -> DataSource {
174 DataSource::Bytes(self.into_bytes())
175 }
176}
177
178cast! {
179 Readable,
180 self => match self {
181 Self::Str(v) => v.into_value(),
182 Self::Bytes(v) => v.into_value(),
183 },
184 v: Str => Self::Str(v),
185 v: Bytes => Self::Bytes(v),
186}