use haematite::branch::ForkWrite;
use serde::{Deserialize, Serialize};
use super::{Captured, Failure, Storage, identifier, reads};
use crate::serve::protocol::Version;
const PROVENANCE_KEY: &[u8] = b"b\0fork";
#[derive(Debug, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct ForkProvenance {
pub branch: String,
pub version: Version,
}
#[derive(Debug, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
struct Stored {
branch: String,
version: Version,
#[serde(default, skip_serializing_if = "std::ops::Not::not")]
line: bool,
}
pub(super) fn provenance_write(
writer: &haematite::db::branches::BranchDatabase,
branch: &str,
at: Version,
line: bool,
) -> Result<ForkWrite, Failure> {
Ok(ForkWrite {
shard_id: writer.shard_for(PROVENANCE_KEY),
key: PROVENANCE_KEY.to_vec(),
value: Some(
serde_json::to_vec(&Stored {
branch: branch.to_owned(),
version: at,
line,
})
.map_err(Failure::storage)?,
),
})
}
pub(in crate::serve) fn decode(bytes: &[u8]) -> Result<(ForkProvenance, bool), Failure> {
let stored: Stored = serde_json::from_slice(bytes).map_err(Failure::storage)?;
identifier(&stored.branch)?;
Ok((
ForkProvenance {
branch: stored.branch,
version: stored.version,
},
stored.line,
))
}
pub(super) fn origin(
reader: &haematite::db::ReadOnlyDatabase,
at: &Captured,
) -> Result<Option<(ForkProvenance, bool)>, Failure> {
reads::get_bytes(reader, at, PROVENANCE_KEY)?
.map(|bytes| decode(&bytes))
.transpose()
}
pub(super) fn read_provenance(
reader: &haematite::db::ReadOnlyDatabase,
at: &Captured,
) -> Result<ForkProvenance, Failure> {
provenance(reader, at)?.ok_or_else(|| {
Failure::new(
"fork_provenance_missing",
"branch has no recorded fork origin",
)
})
}
pub(super) fn provenance(
reader: &haematite::db::ReadOnlyDatabase,
at: &Captured,
) -> Result<Option<ForkProvenance>, Failure> {
Ok(origin(reader, at)?.map(|(provenance, _line)| provenance))
}
impl Storage {
pub fn fork_provenance(&self, at: &Captured) -> Result<ForkProvenance, Failure> {
read_provenance(&self.reader, at)
}
}