//! Data loading. #[path = "cbor.rs"] mod cbor_; #[path = "csv.rs"] mod csv_; #[path = "html.rs"] mod html_; #[path = "json.rs"] mod json_; #[path = "read.rs"] mod read_; #[path = "toml.rs"] mod toml_; #[path = "xml.rs"] mod xml_; #[path = "yaml.rs"] mod yaml_; use comemo::Tracked; use ecow::EcoString; use typst_syntax::{FileId, Spanned}; pub use self::cbor_::*; pub use self::csv_::*; pub use self::html_::*; pub use self::json_::*; pub use self::read_::*; pub use self::toml_::*; pub use self::xml_::*; pub use self::yaml_::*; use crate::World; use crate::diag::{At, SourceResult}; use crate::foundations::OneOrMultiple; use crate::foundations::{Bytes, Scope, Str, cast}; /// Hook up all `data-loading` definitions. pub(super) fn define(global: &mut Scope) { global.start_category(crate::Category::DataLoading); global.define_func::(); global.define_func::(); global.define_func::(); global.define_func::(); global.define_func::(); global.define_func::(); global.define_func::(); global.define_func::(); global.reset_category(); } /// Something we can retrieve byte data from. #[derive(Debug, Clone, PartialEq, Hash)] pub enum DataSource { /// A path to a file. Path(EcoString), /// Raw bytes. Bytes(Bytes), } cast! { DataSource, self => match self { Self::Path(v) => v.into_value(), Self::Bytes(v) => v.into_value(), }, v: EcoString => Self::Path(v), v: Bytes => Self::Bytes(v), } /// Loads data from a path or provided bytes. pub trait Load { /// Bytes or a list of bytes (if there are multiple sources). type Output; /// Load the bytes. fn load(&self, world: Tracked) -> SourceResult; } impl Load for Spanned { type Output = Loaded; fn load(&self, world: Tracked) -> SourceResult { self.as_ref().load(world) } } impl Load for Spanned<&DataSource> { type Output = Loaded; fn load(&self, world: Tracked) -> SourceResult { match &self.v { DataSource::Path(path) => { let file_id = self.span.resolve_path(path).at(self.span)?; let data = world.file(file_id).at(self.span)?; let source = Spanned::new(LoadSource::Path(file_id), self.span); Ok(Loaded::new(source, data)) } DataSource::Bytes(data) => { let source = Spanned::new(LoadSource::Bytes, self.span); Ok(Loaded::new(source, data.clone())) } } } } impl Load for Spanned> { type Output = Vec; fn load(&self, world: Tracked) -> SourceResult { self.as_ref().load(world) } } impl Load for Spanned<&OneOrMultiple> { type Output = Vec; fn load(&self, world: Tracked) -> SourceResult { self.v .0 .iter() .map(|source| Spanned::new(source, self.span).load(world)) .collect() } } /// Data loaded from a [`DataSource`]. #[derive(Clone, Debug, PartialEq, Eq, Hash)] pub struct Loaded { /// Details about where `data` was loaded from. pub source: Spanned, /// The loaded data. pub data: Bytes, } impl Loaded { pub fn new(source: Spanned, bytes: Bytes) -> Self { Self { source, data: bytes } } } /// A loaded [`DataSource`]. #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] pub enum LoadSource { Path(FileId), Bytes, } /// A value that can be read from a file. #[derive(Debug, Clone, PartialEq, Hash)] pub enum Readable { /// A decoded string. Str(Str), /// Raw bytes. Bytes(Bytes), } impl Readable { pub fn into_bytes(self) -> Bytes { match self { Self::Bytes(v) => v, Self::Str(v) => Bytes::from_string(v), } } pub fn into_source(self) -> DataSource { DataSource::Bytes(self.into_bytes()) } } cast! { Readable, self => match self { Self::Str(v) => v.into_value(), Self::Bytes(v) => v.into_value(), }, v: Str => Self::Str(v), v: Bytes => Self::Bytes(v), }