json_ld_core/loader/
fs.rs1use super::{Loader, RemoteDocument};
2use crate::{LoadError, LoadingResult};
3use iref::{Iri, IriBuf};
4use json_syntax::Parse;
5use std::fs::File;
6use std::io::{BufReader, Read};
7use std::path::{Path, PathBuf};
8
9#[derive(Debug, thiserror::Error)]
11pub enum Error {
12 #[error("no mount point")]
14 NoMountPoint,
15
16 #[error("IO: {0}")]
18 IO(std::io::Error),
19
20 #[error("parse error: {0}")]
22 Parse(json_syntax::parse::Error),
23}
24
25#[derive(Default)]
33pub struct FsLoader {
34 mount_points: Vec<(PathBuf, IriBuf)>,
35}
36
37impl FsLoader {
38 pub fn new() -> Self {
40 Self::default()
41 }
42
43 #[inline(always)]
48 pub fn mount<P: AsRef<Path>>(&mut self, url: IriBuf, path: P) {
49 self.mount_points.push((path.as_ref().into(), url));
50 }
51
52 pub fn filepath(&self, url: &Iri) -> Option<PathBuf> {
54 for (path, target_url) in &self.mount_points {
55 if let Some((suffix, _, _)) = url.as_iri_ref().suffix(target_url) {
56 let mut filepath = path.clone();
57 for seg in suffix.as_path().segments() {
58 filepath.push(seg.as_str())
59 }
60
61 return Some(filepath);
62 }
63 }
64
65 None
66 }
67}
68
69impl Loader for FsLoader {
70 async fn load(&self, url: &Iri) -> LoadingResult<IriBuf> {
71 match self.filepath(url) {
72 Some(filepath) => {
73 let file = File::open(filepath)
74 .map_err(|e| LoadError::new(url.to_owned(), Error::IO(e)))?;
75 let mut buf_reader = BufReader::new(file);
76 let mut contents = String::new();
77 buf_reader
78 .read_to_string(&mut contents)
79 .map_err(|e| LoadError::new(url.to_owned(), Error::IO(e)))?;
80 let (doc, _) = json_syntax::Value::parse_str(&contents)
81 .map_err(|e| LoadError::new(url.to_owned(), Error::Parse(e)))?;
82 Ok(RemoteDocument::new(
83 Some(url.to_owned()),
84 Some("application/ld+json".parse().unwrap()),
85 doc,
86 ))
87 }
88 None => Err(LoadError::new(url.to_owned(), Error::NoMountPoint)),
89 }
90 }
91}