#![deny(missing_docs)]
mod sha256;
use std::fs;
use std::io;
use std::path::{Path, PathBuf};
#[derive(Debug, Clone)]
pub struct Cas {
root: PathBuf,
}
impl Cas {
pub fn new(root: impl AsRef<Path>) -> io::Result<Self> {
let root = root.as_ref().to_path_buf();
fs::create_dir_all(&root)?;
Ok(Self { root })
}
pub fn put(&self, bytes: &[u8]) -> io::Result<String> {
let hash = sha256::hex(bytes);
let p = self.path_for(&hash);
if !p.exists() {
if let Some(parent) = p.parent() {
fs::create_dir_all(parent)?;
}
let tmp = p.with_extension("tmp");
fs::write(&tmp, bytes)?;
fs::rename(&tmp, &p)?;
}
Ok(hash)
}
pub fn get(&self, hash: &str) -> io::Result<Option<Vec<u8>>> {
let p = self.path_for(hash);
match fs::read(&p) {
Ok(b) => Ok(Some(b)),
Err(e) if e.kind() == io::ErrorKind::NotFound => Ok(None),
Err(e) => Err(e),
}
}
pub fn contains(&self, hash: &str) -> bool {
self.path_for(hash).exists()
}
pub fn remove(&self, hash: &str) -> io::Result<bool> {
let p = self.path_for(hash);
match fs::remove_file(&p) {
Ok(()) => Ok(true),
Err(e) if e.kind() == io::ErrorKind::NotFound => Ok(false),
Err(e) => Err(e),
}
}
pub fn path_for(&self, hash: &str) -> PathBuf {
let (prefix, rest) = hash.split_at(2);
self.root.join(prefix).join(rest)
}
}