89 lines
2.0 KiB
Rust
89 lines
2.0 KiB
Rust
use pile_config::Label;
|
|
use std::{
|
|
collections::HashMap,
|
|
path::Component,
|
|
sync::{Arc, OnceLock},
|
|
};
|
|
|
|
use crate::{
|
|
extract::traits::ObjectExtractor,
|
|
value::{Item, PileValue},
|
|
};
|
|
|
|
pub struct FsExtractor {
|
|
item: Item,
|
|
output: OnceLock<HashMap<Label, PileValue>>,
|
|
}
|
|
|
|
impl FsExtractor {
|
|
pub fn new(item: &Item) -> Self {
|
|
Self {
|
|
item: item.clone(),
|
|
output: OnceLock::new(),
|
|
}
|
|
}
|
|
|
|
fn get_inner(&self) -> Result<&HashMap<Label, PileValue>, std::io::Error> {
|
|
if let Some(x) = self.output.get() {
|
|
return Ok(x);
|
|
}
|
|
|
|
let Item::File { path, .. } = &self.item else {
|
|
return Ok(self.output.get_or_init(HashMap::new));
|
|
};
|
|
|
|
#[expect(clippy::unwrap_used)]
|
|
let output = HashMap::from([
|
|
(
|
|
Label::new("extension").unwrap(),
|
|
path.extension()
|
|
.and_then(|x| x.to_str())
|
|
.map(|x| PileValue::String(Arc::new(x.into())))
|
|
.unwrap_or(PileValue::Null),
|
|
),
|
|
(
|
|
Label::new("path").unwrap(),
|
|
path.to_str()
|
|
.map(|x| PileValue::String(Arc::new(x.into())))
|
|
.unwrap_or(PileValue::Null),
|
|
),
|
|
(
|
|
Label::new("segments").unwrap(),
|
|
path.components()
|
|
.map(|x| match x {
|
|
Component::CurDir => Some(".".to_owned()),
|
|
Component::Normal(x) => x.to_str().map(|x| x.to_owned()),
|
|
Component::ParentDir => Some("..".to_owned()),
|
|
Component::RootDir => Some("/".to_owned()),
|
|
Component::Prefix(x) => x.as_os_str().to_str().map(|x| x.to_owned()),
|
|
})
|
|
.map(|x| x.map(|x| PileValue::String(Arc::new(x.into()))))
|
|
.collect::<Option<Vec<_>>>()
|
|
.map(|v| PileValue::Array(Arc::new(v)))
|
|
.unwrap_or(PileValue::Null),
|
|
),
|
|
]);
|
|
|
|
return Ok(self.output.get_or_init(|| output));
|
|
}
|
|
}
|
|
|
|
#[async_trait::async_trait]
|
|
impl ObjectExtractor for FsExtractor {
|
|
async fn field(
|
|
&self,
|
|
name: &Label,
|
|
args: Option<&str>,
|
|
) -> Result<Option<PileValue>, std::io::Error> {
|
|
if args.is_some() {
|
|
return Ok(None);
|
|
}
|
|
|
|
Ok(self.get_inner()?.get(name).cloned())
|
|
}
|
|
|
|
async fn fields(&self) -> Result<Vec<Label>, std::io::Error> {
|
|
Ok(self.get_inner()?.keys().cloned().collect())
|
|
}
|
|
}
|