use crate::types::attrs::Attrs;
use crate::types::ipr::IPR;
use serde::{Deserialize, Serialize};
use std::rc::Rc;
#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
pub struct Ark<C>(
pub(crate) Rc<Vec<IPR>>,
pub(crate) Rc<Vec<Attrs>>,
pub(crate) Rc<Vec<C>>,
);
impl<C> Ark<C> {
pub fn paths(&self) -> &Vec<IPR> {
&self.0
}
pub fn attrs(&self) -> &Vec<Attrs> {
&self.1
}
pub fn contents(&self) -> &Vec<C> {
&self.2
}
pub fn len(&self) -> usize {
self.0.len()
}
pub fn files<'a>(&'a self) -> FileIterator<'a, C> {
FileIterator {
inner: &self,
pos: 0,
}
}
pub fn dirs<'a>(&'a self) -> DirIterator<'a, C> {
DirIterator {
inner: &self,
pos: self.0.len(),
}
}
pub fn compose(paths: Rc<Vec<IPR>>, attrs: Rc<Vec<Attrs>>, contents: Rc<Vec<C>>) -> Self {
assert!(paths.len() == attrs.len());
assert!(paths.len() >= contents.len());
Self(paths, attrs, contents)
}
pub fn decompose(self) -> (Rc<Vec<IPR>>, Rc<Vec<Attrs>>, Rc<Vec<C>>) {
(self.0, self.1, self.2)
}
pub fn empty() -> Self {
Self::compose(Rc::new(vec![]), Rc::new(vec![]), Rc::new(vec![]))
}
}
pub struct FileIterator<'a, C> {
inner: &'a Ark<C>,
pos: usize,
}
impl<'a, C> Iterator for FileIterator<'a, C> {
type Item = (&'a IPR, &'a Attrs, &'a C);
fn next(&mut self) -> Option<Self::Item> {
if self.pos >= self.inner.2.len() {
None
} else {
let pos = self.pos;
self.pos = pos + 1;
Some((&self.inner.0[pos], &self.inner.1[pos], &self.inner.2[pos]))
}
}
}
pub struct DirIterator<'a, C> {
inner: &'a Ark<C>,
pos: usize,
}
impl<'a, C> Iterator for DirIterator<'a, C> {
type Item = (&'a IPR, &'a Attrs);
fn next(&mut self) -> Option<Self::Item> {
if self.pos == 0 {
None
} else {
self.pos = self.pos - 1;
Some((&self.inner.0[self.pos], &self.inner.1[self.pos]))
}
}
}
#[cfg(test)]
mod test {
use super::*;
use crate::types::ipr::ToIPR;
#[test]
fn test_files() {
let ark = Ark::scan("fixture").expect("Scanned fixture");
let mut files = ark.files();
assert_eq!(
files.next(),
Some((
&"dir1/dir2/nested.txt".to_ipr(),
&Attrs::new().append("UNIX_MODE", "33204"),
&std::path::PathBuf::from("fixture/dir1/dir2/nested.txt"),
))
);
assert_eq!(
files.next(),
Some((
&"file_at_root.txt".to_ipr(),
&Attrs::new().append("UNIX_MODE", "33204"),
&std::path::PathBuf::from("fixture/file_at_root.txt"),
))
);
}
#[test]
fn test_dirs() {
let ark = Ark::scan("fixture").expect("Scanned fixture");
let mut dirs = ark.dirs();
assert_eq!(
dirs.next(),
Some((
&"dir1/dir2".to_ipr(),
&Attrs::new().append("UNIX_MODE", "16893"),
))
);
assert_eq!(
dirs.next(),
Some((&"dir1".to_ipr(), &Attrs::new().append("UNIX_MODE", "16893"),))
);
}
}