Files
orchid/src/virt_fs/embed.rs
Lawrence Bethlenfalvy c279301583 Massive feature drop
- pattern matching seems to be correct
- dynamic dispatch works with the to_string example
- template strings as a last-minute addition
- interpreter revamp, virtual stack for abort safety
2024-01-29 18:26:56 +00:00

75 lines
2.6 KiB
Rust

use std::sync::Arc;
use intern_all::{ev, i, Tok};
use rust_embed::RustEmbed;
use super::common::CodeNotFound;
use super::{FSResult, Loaded, VirtFS};
use crate::error::ErrorSansLocation;
use crate::location::CodeGenInfo;
use crate::name::PathSlice;
use crate::tree::{ModEntry, ModMember, Module};
/// An in-memory FS tree for libraries managed internally by the interpreter
pub struct EmbeddedFS {
tree: Module<Arc<String>, (), ()>,
suffix: &'static str,
gen: CodeGenInfo,
}
impl EmbeddedFS {
/// Expose a directory embedded in a binary wiht [RustEmbed] to the
/// interpreter
pub fn new<T: RustEmbed>(suffix: &'static str, gen: CodeGenInfo) -> Self {
let mut tree = Module::wrap([]);
for path in T::iter() {
let data_buf = T::get(&path).expect("path from iterator").data.to_vec();
let data = String::from_utf8(data_buf).expect("embed must be utf8");
let mut cur_node = &mut tree;
let path_no_suffix =
path.strip_suffix(suffix).expect("embed filtered for suffix");
let mut segments = path_no_suffix.split('/').map(i);
let mut cur_seg = segments.next().expect("Embed is a directory");
for next_seg in segments {
if !cur_node.entries.contains_key(&cur_seg) {
let ent = ModEntry::wrap(ModMember::Sub(Module::wrap([])));
cur_node.entries.insert(cur_seg.clone(), ent);
}
let ent = cur_node.entries.get_mut(&cur_seg).expect("just constructed");
match &mut ent.member {
ModMember::Sub(submod) => cur_node = submod,
_ => panic!("Aliased file and folder"),
};
cur_seg = next_seg;
}
let data_ent = ModEntry::wrap(ModMember::Item(Arc::new(data)));
let prev = cur_node.entries.insert(cur_seg, data_ent);
debug_assert!(prev.is_none(), "file name unique");
}
// if gen.generator == "std" {
// panic!(
// "{:?}",
// tree.map_data(&|_, s| (), &|_, x| x, &|_, x| x, Substack::Bottom)
// );
// };
Self { gen, suffix, tree }
}
}
impl VirtFS for EmbeddedFS {
fn get(&self, path: &[Tok<String>], full_path: PathSlice) -> FSResult {
if path.is_empty() {
return Ok(Loaded::collection(self.tree.keys(|_| true)));
}
let entry = (self.tree.walk1_ref(&[], path, |_| true))
.map_err(|_| CodeNotFound::new(full_path.to_vpath()).pack())?;
Ok(match &entry.0.member {
ModMember::Item(text) => Loaded::Code(text.clone()),
ModMember::Sub(sub) => Loaded::collection(sub.keys(|_| true)),
})
}
fn display(&self, path: &[Tok<String>]) -> Option<String> {
let Self { gen, suffix, .. } = self;
Some(format!("{}{suffix} in {gen}", ev(path).join("/")))
}
}