rune/compile/
source_loader.rs
1use crate::alloc::path::Path;
2#[cfg(feature = "std")]
3use crate::alloc::prelude::*;
4use crate::ast::Spanned;
5use crate::compile;
6#[cfg(feature = "std")]
7use crate::compile::ErrorKind;
8#[cfg(feature = "std")]
9use crate::item::ComponentRef;
10use crate::{Item, Source};
11
12pub trait SourceLoader {
14 fn load(&mut self, root: &Path, item: &Item, span: &dyn Spanned) -> compile::Result<Source>;
16}
17
18#[derive(Default)]
20#[non_exhaustive]
21pub struct NoopSourceLoader;
22
23impl SourceLoader for NoopSourceLoader {
24 fn load(&mut self, _: &Path, _: &Item, span: &dyn Spanned) -> compile::Result<Source> {
25 Err(compile::Error::msg(span, "Source loading is not supported"))
26 }
27}
28
29cfg_std! {
30 #[derive(Default)]
32 #[non_exhaustive]
33 pub struct FileSourceLoader;
34
35 impl FileSourceLoader {
36 pub fn new() -> Self {
38 Self::default()
39 }
40 }
41
42 impl SourceLoader for FileSourceLoader {
43 fn load(&mut self, root: &Path, item: &Item, span: &dyn Spanned) -> compile::Result<Source> {
44 let mut base = root.try_to_owned()?;
45
46 if !base.pop() {
47 return Err(compile::Error::new(
48 span,
49 ErrorKind::UnsupportedModuleRoot {
50 root: root.try_to_owned()?,
51 },
52 ));
53 }
54
55 for c in item {
56 if let ComponentRef::Str(string) = c {
57 base.push(string);
58 } else {
59 return Err(compile::Error::new(
60 span,
61 ErrorKind::UnsupportedModuleItem {
62 item: item.try_to_owned()?,
63 },
64 ));
65 }
66 }
67
68 let candidates = [base.join("mod.rn"), base.with_extension("rn")];
69
70 let mut found = None;
71
72 for path in &candidates[..] {
73 if path.is_file() {
74 found = Some(path);
75 break;
76 }
77 }
78
79 let Some(path) = found else {
80 return Err(compile::Error::new(
81 span,
82 ErrorKind::ModNotFound { path: base },
83 ));
84 };
85
86 match Source::from_path(path) {
87 Ok(source) => Ok(source),
88 Err(error) => Err(compile::Error::new(
89 span,
90 ErrorKind::SourceError {
91 path: path.clone(),
92 error,
93 },
94 )),
95 }
96 }
97 }
98}