haematite_cli/serve/storage/
branches.rs1use haematite::branch::ForkWrite;
4use serde::{Deserialize, Serialize};
5
6use super::{Captured, Failure, Storage, identifier, reads};
7use crate::serve::protocol::Version;
8
9const PROVENANCE_KEY: &[u8] = b"b\0fork";
10
11#[derive(Debug, Serialize, Deserialize)]
12#[serde(deny_unknown_fields)]
13pub struct ForkProvenance {
14 pub branch: String,
15 pub version: Version,
16}
17
18#[derive(Debug, Serialize, Deserialize)]
22#[serde(deny_unknown_fields)]
23struct Stored {
24 branch: String,
25 version: Version,
26 #[serde(default, skip_serializing_if = "std::ops::Not::not")]
27 line: bool,
28}
29
30pub(super) fn provenance_write(
31 writer: &haematite::db::branches::BranchDatabase,
32 branch: &str,
33 at: Version,
34 line: bool,
35) -> Result<ForkWrite, Failure> {
36 Ok(ForkWrite {
37 shard_id: writer.shard_for(PROVENANCE_KEY),
38 key: PROVENANCE_KEY.to_vec(),
39 value: Some(
40 serde_json::to_vec(&Stored {
41 branch: branch.to_owned(),
42 version: at,
43 line,
44 })
45 .map_err(Failure::storage)?,
46 ),
47 })
48}
49
50pub(in crate::serve) fn decode(bytes: &[u8]) -> Result<(ForkProvenance, bool), Failure> {
55 let stored: Stored = serde_json::from_slice(bytes).map_err(Failure::storage)?;
56 identifier(&stored.branch)?;
57 Ok((
58 ForkProvenance {
59 branch: stored.branch,
60 version: stored.version,
61 },
62 stored.line,
63 ))
64}
65
66pub(super) fn origin(
72 reader: &haematite::db::ReadOnlyDatabase,
73 at: &Captured,
74) -> Result<Option<(ForkProvenance, bool)>, Failure> {
75 reads::get_bytes(reader, at, PROVENANCE_KEY)?
76 .map(|bytes| decode(&bytes))
77 .transpose()
78}
79
80pub(super) fn read_provenance(
81 reader: &haematite::db::ReadOnlyDatabase,
82 at: &Captured,
83) -> Result<ForkProvenance, Failure> {
84 provenance(reader, at)?.ok_or_else(|| {
85 Failure::new(
86 "fork_provenance_missing",
87 "branch has no recorded fork origin",
88 )
89 })
90}
91
92pub(super) fn provenance(
95 reader: &haematite::db::ReadOnlyDatabase,
96 at: &Captured,
97) -> Result<Option<ForkProvenance>, Failure> {
98 Ok(origin(reader, at)?.map(|(provenance, _line)| provenance))
99}
100
101impl Storage {
102 pub fn fork_provenance(&self, at: &Captured) -> Result<ForkProvenance, Failure> {
107 read_provenance(&self.reader, at)
108 }
109}