pub mod memory;
#[cfg(feature = "remote")]
pub mod remote;
#[cfg(feature = "sqlite")]
pub mod sqlite;
#[cfg(any(test, feature = "compliance"))]
#[allow(clippy::missing_panics_doc, clippy::must_use_candidate)]
pub mod prop_strategies;
#[cfg(any(test, feature = "compliance"))]
#[allow(clippy::missing_panics_doc)]
pub mod prop_tests;
#[cfg(any(test, feature = "compliance"))]
#[allow(clippy::missing_panics_doc)]
pub mod tests;
use std::collections::HashSet;
use async_trait::async_trait;
use async_stream::try_stream;
use clayers_xml::ContentHash;
use futures_core::stream::BoxStream;
use crate::error::{Error, Result};
use crate::object::Object;
#[async_trait]
pub trait ObjectStore: Send + Sync {
async fn get(&self, hash: &ContentHash) -> Result<Option<Object>>;
async fn contains(&self, hash: &ContentHash) -> Result<bool>;
async fn transaction(&self) -> Result<Box<dyn Transaction>>;
async fn get_by_inclusive_hash(
&self,
inclusive_hash: &ContentHash,
) -> Result<Option<(ContentHash, Object)>>;
fn subtree<'a>(
&'a self,
root: &ContentHash,
) -> BoxStream<'a, Result<(ContentHash, Object)>>;
}
pub(crate) fn subtree_walk<'a>(
store: &'a (dyn ObjectStore + 'a),
root: &ContentHash,
) -> BoxStream<'a, Result<(ContentHash, Object)>> {
let root = *root;
Box::pin(try_stream! {
let mut visited = HashSet::new();
let mut stack = vec![root];
while let Some(hash) = stack.pop() {
if !visited.insert(hash) { continue; }
let obj = store.get(&hash).await?.ok_or(Error::NotFound(hash))?;
match &obj {
Object::Commit(c) => {
stack.push(c.tree);
stack.extend(&c.parents);
}
Object::Tag(t) => { stack.push(t.target); }
Object::Tree(t) => {
for entry in &t.entries {
stack.push(entry.document);
}
}
Object::Document(d) => {
stack.push(d.root);
stack.extend(&d.prologue);
}
Object::Element(e) => { stack.extend(&e.children); }
Object::Text(_) | Object::Comment(_) | Object::PI(_) => {}
}
yield (hash, obj);
}
})
}
#[async_trait]
pub trait RefStore: Send + Sync {
async fn get_ref(&self, name: &str) -> Result<Option<ContentHash>>;
async fn set_ref(&self, name: &str, hash: ContentHash) -> Result<()>;
async fn delete_ref(&self, name: &str) -> Result<()>;
async fn list_refs(&self, prefix: &str) -> Result<Vec<(String, ContentHash)>>;
async fn cas_ref(
&self,
name: &str,
expected: Option<ContentHash>,
new: ContentHash,
) -> Result<bool>;
}
#[async_trait]
pub trait Transaction: Send {
async fn put(&mut self, hash: ContentHash, object: Object) -> Result<()>;
async fn commit(&mut self) -> Result<()>;
async fn rollback(&mut self) -> Result<()>;
}