use std::{collections::BTreeMap, error::Error};
use git_ext::ref_format::RefString;
use git_ext::Oid;
use radicle_crypto::PublicKey;
use crate::change::EntryId;
use crate::{ObjectId, TypeName};
#[derive(Clone, Debug, Default)]
pub struct Objects(Vec<Reference>);
impl Objects {
pub fn new(reference: Reference) -> Self {
Self(vec![reference])
}
pub fn push(&mut self, reference: Reference) {
self.0.push(reference)
}
pub fn iter(&self) -> impl Iterator<Item = &Reference> {
self.0.iter()
}
}
impl From<Vec<Reference>> for Objects {
fn from(refs: Vec<Reference>) -> Self {
Objects(refs)
}
}
#[derive(Clone, Debug)]
pub struct Reference {
pub name: RefString,
pub target: Commit,
}
#[derive(Clone, Debug)]
pub struct Commit {
pub id: Oid,
}
pub trait Storage {
type ObjectsError: Error + Send + Sync + 'static;
type TypesError: Error + Send + Sync + 'static;
type UpdateError: Error + Send + Sync + 'static;
type RemoveError: Error + Send + Sync + 'static;
fn objects(
&self,
typename: &TypeName,
object_id: &ObjectId,
) -> Result<Objects, Self::ObjectsError>;
fn types(&self, typename: &TypeName) -> Result<BTreeMap<ObjectId, Objects>, Self::TypesError>;
fn update(
&self,
identifier: &PublicKey,
typename: &TypeName,
object_id: &ObjectId,
entry: &EntryId,
) -> Result<(), Self::UpdateError>;
fn remove(
&self,
identifier: &PublicKey,
typename: &TypeName,
object_id: &ObjectId,
) -> Result<(), Self::RemoveError>;
}
pub mod convert {
use std::str;
use git_ext::ref_format::RefString;
use thiserror::Error;
use super::{Commit, Reference};
#[derive(Debug, Error)]
pub enum Error {
#[error("the reference '{name}' does not point to a commit object")]
NotCommit {
name: RefString,
#[source]
err: git2::Error,
},
#[error(transparent)]
Ref(#[from] git_ext::ref_format::Error),
#[error(transparent)]
Utf8(#[from] str::Utf8Error),
}
impl<'a> TryFrom<git2::Reference<'a>> for Reference {
type Error = Error;
fn try_from(value: git2::Reference<'a>) -> Result<Self, Self::Error> {
let name = RefString::try_from(str::from_utf8(value.name_bytes())?)?;
let target = Commit::from(value.peel_to_commit().map_err(|err| Error::NotCommit {
name: name.clone(),
err,
})?);
Ok(Self { name, target })
}
}
impl<'a> From<git2::Commit<'a>> for Commit {
fn from(commit: git2::Commit<'a>) -> Self {
Commit {
id: commit.id().into(),
}
}
}
}