Skip to main content

objects/
reference_store.rs

1//! Canonical source-reference objects use the existing blob store.
2pub mod prepare;
3use crate::{
4    error::{HeddleError, Result},
5    object::{
6        Blob, ContentHash, ObjectSource, State, StateId, Tree,
7        source_target_map::SourceTargetMapStore,
8    },
9    store::ObjectStore,
10};
11pub struct Source<'a, S>(pub &'a S);
12impl<S: ObjectStore> ObjectSource for Source<'_, S> {
13    fn get_tree(&self, hash: &ContentHash) -> Result<Option<Tree>> {
14        self.0.get_tree(hash)
15    }
16    fn get_state(&self, id: &StateId) -> Result<Option<State>> {
17        self.0.get_state(id)
18    }
19    fn get_blob(&self, hash: &ContentHash) -> Result<Option<Blob>> {
20        self.0.get_blob(hash)
21    }
22    fn decoded_blob_len(&self, hash: &ContentHash) -> Result<Option<u64>> {
23        self.0.blob_size(hash)
24    }
25}
26pub struct MapStore<'a, S>(pub &'a S);
27impl<S: ObjectStore> SourceTargetMapStore for MapStore<'_, S> {
28    type Error = HeddleError;
29    fn read(&mut self, hash: ContentHash, max: usize) -> Result<Option<Vec<u8>>> {
30        if self.0.blob_size(&hash)?.is_some_and(|len| len > max as u64) {
31            return Err(HeddleError::InvalidObject(
32                "reference node read budget".into(),
33            ));
34        }
35        Ok(self.0.get_blob(&hash)?.map(|blob| blob.into_content()))
36    }
37    fn write(&mut self, hash: ContentHash, bytes: Vec<u8>) -> Result<()> {
38        if ContentHash::compute_typed("blob", &bytes) != hash {
39            return Err(HeddleError::InvalidObject(
40                "reference node hash mismatch".into(),
41            ));
42        }
43        self.0.put_blob(&Blob::new(bytes))?;
44        Ok(())
45    }
46}