Files
orchid/orchid-extension/src/fs.rs
2025-07-12 00:46:10 +02:00

89 lines
2.3 KiB
Rust

use std::borrow::Cow;
use std::num::NonZero;
use futures::FutureExt;
use futures::future::LocalBoxFuture;
use hashbrown::HashMap;
use orchid_base::interner::{Interner, Tok};
use orchid_base::pure_seq::pushed;
use crate::api;
use crate::system::SysCtx;
pub trait VirtFS: Send + Sync + 'static {
fn load<'a>(
&'a self,
path: &'a [Tok<String>],
ctx: SysCtx,
) -> LocalBoxFuture<'a, api::OrcResult<api::Loaded>>;
}
#[derive(Clone)]
pub struct DeclVmod(Cow<'static, [(&'static str, DeclFs)]>);
impl DeclVmod {
pub fn new(items: &'static [(&'static str, DeclFs)]) -> DeclVmod {
DeclVmod(Cow::Borrowed(items))
}
pub fn entry(
key: &'static str,
items: &'static [(&'static str, DeclFs)],
) -> (&'static str, DeclVmod) {
(key, DeclVmod(Cow::Borrowed(items)))
}
pub fn merge(&self, other: &Self) -> Result<Self, Vec<&'static str>> {
let mut items = Vec::new();
for (k, v1) in self.0.iter() {
items.push((*k, match other.0.iter().find(|(k2, _)| k == k2) {
Some((_, v2)) => v1.merge(v2).map_err(|e| pushed::<_, Vec<_>>(e, *k))?,
None => v1.clone(),
}));
}
for (k, v) in other.0.iter() {
if !items.iter().any(|(k2, _)| k2 == k) {
items.push((*k, v.clone()))
}
}
Ok(Self(Cow::Owned(items)))
}
pub async fn to_api_rec(
&self,
vfses: &mut HashMap<api::VfsId, &'static dyn VirtFS>,
i: &Interner,
) -> std::collections::HashMap<api::TStr, api::EagerVfs> {
let mut output = std::collections::HashMap::new();
for (k, v) in self.0.iter() {
output.insert(i.i::<String>(*k).await.to_api(), v.to_api_rec(vfses, i).boxed_local().await);
}
output
}
}
#[derive(Clone)]
pub enum DeclFs {
Lazy(&'static dyn VirtFS),
Mod(DeclVmod),
}
impl DeclFs {
pub fn merge(&self, other: &Self) -> Result<Self, Vec<&'static str>> {
match (self, other) {
(Self::Mod(m1), Self::Mod(m2)) => Ok(Self::Mod(m1.merge(m2)?)),
(..) => Err(Vec::new()),
}
}
pub async fn to_api_rec(
&self,
vfses: &mut HashMap<api::VfsId, &'static dyn VirtFS>,
i: &Interner,
) -> api::EagerVfs {
match self {
DeclFs::Lazy(fs) => {
let vfsc: u16 = vfses.len().try_into().expect("too many vfses (more than u16::MAX)");
let id = api::VfsId(NonZero::new(vfsc + 1).unwrap());
vfses.insert(id, *fs);
api::EagerVfs::Lazy(id)
},
DeclFs::Mod(m) => api::EagerVfs::Eager(m.to_api_rec(vfses, i).await),
}
}
}