byr/crates/byr-core/src/lib.rs
2022-10-15 13:48:32 +02:00

99 lines
2.7 KiB
Rust

use cap_std::fs::Dir;
use std::io::{Read, Result as IoResult, Write};
mod traits;
pub use traits::{Event, FlowData};
mod lock;
use lock::RepoLock;
mod changelist;
pub use changelist::ChangeList;
mod thin_snapshot;
pub use thin_snapshot::ThinSnapshot;
pub struct Repository(pub Dir);
impl Repository {
fn subdir(&self, sd: &str) -> IoResult<Dir> {
let _ = self.0.create_dir(sd);
self.0.open_dir(sd)
}
pub fn changes(&self) -> IoResult<Changes> {
self.subdir("changes").map(Changes)
}
pub fn snapshots(&self) -> IoResult<Snapshots> {
self.subdir("snapshots").map(Snapshots)
}
}
pub type ChangeHash = [u8; 32];
pub struct Changes(Dir);
fn yzb64_file_name(h: &ChangeHash) -> [u8; 43] {
let mut buf = [0u8; 43];
assert_eq!(
yzb64::base64::encode_engine_slice(h, &mut buf, &*yzb64::B64_ENGINE),
43
);
buf
}
impl Changes {
pub fn insert(&self, h: &ChangeHash, contents: &[u8]) -> IoResult<bool> {
let buf = yzb64_file_name(h);
let buf = std::str::from_utf8(&buf).unwrap();
let _l = RepoLock::lock_write(&self.0, ".lock");
if self.0.exists(buf) {
return Ok(false);
}
let mut ecd = zstd::stream::write::Encoder::new(self.0.create(buf)?, 5)?;
ecd.write_all(contents)?;
ecd.finish()?;
Ok(true)
}
pub fn remove(&self, h: &ChangeHash) -> IoResult<()> {
let buf = yzb64_file_name(h);
let buf = std::str::from_utf8(&buf).unwrap();
let _l = RepoLock::lock_write(&self.0, ".lock");
self.0.remove_file(buf)
}
pub fn get(&self, h: &ChangeHash) -> IoResult<Vec<u8>> {
let buf = yzb64_file_name(h);
let buf = std::str::from_utf8(&buf).unwrap();
let _l = RepoLock::lock_read(&self.0, ".lock");
let mut dcd = zstd::stream::read::Decoder::new(self.0.open(buf)?)?;
let mut buf2 = Vec::new();
dcd.read_to_end(&mut buf2)?;
Ok(buf2)
}
}
pub struct Snapshots(Dir);
impl Snapshots {
pub fn insert_thin(&self, name: &str, contents: &ThinSnapshot) -> IoResult<bool> {
let _l = RepoLock::lock_write(&self.0, ".lock");
if self.0.exists(name) {
return Ok(false);
}
let f = self.0.create(name)?;
contents.write_to_stream(f)?;
Ok(true)
}
pub fn remove(&self, name: &str) -> IoResult<()> {
let _l = RepoLock::lock_write(&self.0, ".lock");
self.0.remove_file(name)
}
pub fn get_thin(&self, name: &str) -> IoResult<ThinSnapshot> {
let _l = RepoLock::lock_read(&self.0, ".lock");
let f = self.0.open(name)?;
ThinSnapshot::read_from_stream(f)
}
}