use alloc::string::String;
use crate::path::{FsPath, MaildirPath};
#[derive(Clone, Debug, Default, Eq, PartialEq)]
pub struct MaildirStore {
pub root: FsPath,
pub maildirpp: bool,
}
impl MaildirStore {
pub fn resolve(&self, path: &MaildirPath) -> FsPath {
if path.is_empty() {
return self.root.clone();
}
if self.maildirpp {
let mut segment = String::with_capacity(path.as_str().len() + 1);
segment.push('.');
for (i, component) in path.components().enumerate() {
if i > 0 {
segment.push('.');
}
segment.push_str(component);
}
self.root.join(&segment)
} else {
self.root.join(path.as_str())
}
}
pub fn relative(&self, fs: &FsPath) -> Option<MaildirPath> {
let rel = fs.strip_prefix(&self.root)?;
if rel.is_empty() {
return Some(MaildirPath::default());
}
if self.maildirpp {
let stripped = rel.strip_prefix('.').unwrap_or(rel);
let mut out = String::with_capacity(stripped.len());
for (i, segment) in stripped.split('.').enumerate() {
if i > 0 {
out.push('/');
}
out.push_str(segment);
}
Some(MaildirPath::from(out))
} else {
Some(MaildirPath::from(rel))
}
}
}
#[cfg(test)]
mod tests {
use crate::{
path::{FsPath, MaildirPath},
store::MaildirStore,
};
#[test]
fn resolve_fs_empty_is_root() {
let store = MaildirStore {
root: FsPath::from("/tmp/m"),
maildirpp: false,
};
assert_eq!(store.resolve(&MaildirPath::default()).as_str(), "/tmp/m");
}
#[test]
fn resolve_fs_nested() {
let store = MaildirStore {
root: FsPath::from("/tmp/m"),
maildirpp: false,
};
assert_eq!(
store.resolve(&MaildirPath::from("Foo/Bar")).as_str(),
"/tmp/m/Foo/Bar"
);
}
#[test]
fn resolve_maildirpp_flat_dotted() {
let store = MaildirStore {
root: FsPath::from("/tmp/m"),
maildirpp: true,
};
assert_eq!(
store.resolve(&MaildirPath::from("Foo/Bar")).as_str(),
"/tmp/m/.Foo.Bar"
);
}
#[test]
fn resolve_maildirpp_empty_is_root() {
let store = MaildirStore {
root: FsPath::from("/tmp/m"),
maildirpp: true,
};
assert_eq!(store.resolve(&MaildirPath::default()).as_str(), "/tmp/m");
}
#[test]
fn relative_fs_round_trip() {
let store = MaildirStore {
root: FsPath::from("/tmp/m"),
maildirpp: false,
};
let logical = MaildirPath::from("Foo/Bar");
let fs = store.resolve(&logical);
assert_eq!(store.relative(&fs), Some(logical));
}
#[test]
fn relative_maildirpp_round_trip() {
let store = MaildirStore {
root: FsPath::from("/tmp/m"),
maildirpp: true,
};
let logical = MaildirPath::from("Foo/Bar");
let fs = store.resolve(&logical);
assert_eq!(store.relative(&fs), Some(logical));
}
#[test]
fn relative_outside_store_is_none() {
let store = MaildirStore {
root: FsPath::from("/tmp/m"),
maildirpp: false,
};
assert_eq!(store.relative(&FsPath::from("/other/path")), None);
}
}