byr/crates/byr-core/src/lib.rs
2022-10-18 00:07:54 +02:00

162 lines
4.5 KiB
Rust

use cap_std::fs::Dir;
use std::io::{Error as IoError, ErrorKind as IoEk, Read, Result as IoResult, Write};
mod changelist;
pub use changelist::ChangeList;
mod lock;
use lock::RepoLock;
mod patience;
pub use patience::{patience_diff, DiffBlock};
mod thin_snapshot;
pub use thin_snapshot::ThinSnapshot;
mod traits;
pub use traits::{Event, FlowData};
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
}
#[allow(dead_code)]
pub struct MassChangesGet {
cd: Dir,
l: RepoLock,
}
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 fn massget(&self) -> IoResult<MassChangesGet> {
let l = RepoLock::lock_read(&self.0, ".lock")?;
Ok(MassChangesGet {
cd: self.0.try_clone()?,
l,
})
}
}
impl MassChangesGet {
pub fn get(&self, h: &ChangeHash) -> IoResult<Vec<u8>> {
let buf = yzb64_file_name(h);
let buf = std::str::from_utf8(&buf).unwrap();
let mut dcd = zstd::stream::read::Decoder::new(self.cd.open(buf)?)?;
let mut buf2 = Vec::new();
dcd.read_to_end(&mut buf2)?;
Ok(buf2)
}
pub fn try_clone(&self) -> IoResult<Self> {
let l = RepoLock::lock_read(&self.cd, ".lock")?;
Ok(MassChangesGet {
cd: self.cd.try_clone()?,
l,
})
}
}
pub struct Snapshots(pub 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 update_thin<R>(
&self,
name: &str,
mut tf: impl FnMut(&mut ThinSnapshot) -> IoResult<R>,
) -> IoResult<R> {
let _l = RepoLock::lock_write(&self.0, ".lock");
let mut snap = ThinSnapshot::read_from_stream(self.0.open(name)?)?;
let res = tf(&mut snap)?;
let mut tmpf = cap_tempfile::TempFile::new(&self.0)?;
snap.write_to_stream(&mut tmpf)?;
tmpf.replace(name)?;
Ok(res)
}
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)
}
pub fn fork(&self, old: &str, new: &str) -> IoResult<()> {
let _l = RepoLock::lock_write(&self.0, ".lock");
if self.0.exists(new) {
return Err(IoError::new(
IoEk::AlreadyExists,
"fork target already exists",
));
}
let mut src = self.0.open(old)?.into_std();
let mut trg = self.0.create(new)?.into_std();
std::io::copy(&mut src, &mut trg)?;
Ok(())
}
}