radicle_cob/object/
storage.rs

1// Copyright © 2021 The Radicle Link Contributors
2
3use std::{collections::BTreeMap, error::Error};
4
5use git_ext::ref_format::RefString;
6use git_ext::Oid;
7
8use crate::change::EntryId;
9use crate::{ObjectId, TypeName};
10
11/// The [`Reference`]s that refer to the commits that make up a
12/// [`crate::CollaborativeObject`].
13#[derive(Clone, Debug, Default)]
14pub struct Objects(Vec<Reference>);
15
16impl Objects {
17    pub fn new(reference: Reference) -> Self {
18        Self(vec![reference])
19    }
20
21    pub fn push(&mut self, reference: Reference) {
22        self.0.push(reference)
23    }
24
25    /// Return an iterator over the `local` and `remotes` of the given
26    /// [`Objects`].
27    pub fn iter(&self) -> impl Iterator<Item = &Reference> {
28        self.0.iter()
29    }
30}
31
32impl From<Vec<Reference>> for Objects {
33    fn from(refs: Vec<Reference>) -> Self {
34        Objects(refs)
35    }
36}
37
38/// A [`Reference`] that must directly point to the [`Commit`] for a
39/// [`crate::CollaborativeObject`].
40#[derive(Clone, Debug)]
41pub struct Reference {
42    /// The `name` of the reference.
43    pub name: RefString,
44    /// The [`Commit`] that this reference points to.
45    pub target: Commit,
46}
47
48/// A [`Commit`] that holds the data for a given [`crate::CollaborativeObject`].
49#[derive(Clone, Debug)]
50pub struct Commit {
51    /// The content identifier of the commit.
52    pub id: Oid,
53}
54
55pub trait Storage {
56    type ObjectsError: Error + Send + Sync + 'static;
57    type TypesError: Error + Send + Sync + 'static;
58    type UpdateError: Error + Send + Sync + 'static;
59    type RemoveError: Error + Send + Sync + 'static;
60
61    type Namespace;
62
63    /// Get all references which point to a head of the change graph for a
64    /// particular object
65    fn objects(
66        &self,
67        typename: &TypeName,
68        object_id: &ObjectId,
69    ) -> Result<Objects, Self::ObjectsError>;
70
71    /// Get all references to objects of a given type within a particular
72    /// identity
73    fn types(&self, typename: &TypeName) -> Result<BTreeMap<ObjectId, Objects>, Self::TypesError>;
74
75    /// Update a ref to a particular collaborative object
76    fn update(
77        &self,
78        namespace: &Self::Namespace,
79        typename: &TypeName,
80        object_id: &ObjectId,
81        entry: &EntryId,
82    ) -> Result<(), Self::UpdateError>;
83
84    /// Remove a ref to a particular collaborative object
85    fn remove(
86        &self,
87        namespace: &Self::Namespace,
88        typename: &TypeName,
89        object_id: &ObjectId,
90    ) -> Result<(), Self::RemoveError>;
91}
92
93pub mod convert {
94    use std::str;
95
96    use git_ext::ref_format::RefString;
97    use thiserror::Error;
98
99    use super::{Commit, Reference};
100
101    #[derive(Debug, Error)]
102    pub enum Error {
103        #[error("the reference '{name}' does not point to a commit object")]
104        NotCommit {
105            name: RefString,
106            #[source]
107            err: git2::Error,
108        },
109        #[error(transparent)]
110        Ref(#[from] git_ext::ref_format::Error),
111        #[error(transparent)]
112        Utf8(#[from] str::Utf8Error),
113    }
114
115    impl<'a> TryFrom<git2::Reference<'a>> for Reference {
116        type Error = Error;
117
118        fn try_from(value: git2::Reference<'a>) -> Result<Self, Self::Error> {
119            let name = RefString::try_from(str::from_utf8(value.name_bytes())?)?;
120            let target = Commit::from(value.peel_to_commit().map_err(|err| Error::NotCommit {
121                name: name.clone(),
122                err,
123            })?);
124            Ok(Self { name, target })
125        }
126    }
127
128    impl<'a> From<git2::Commit<'a>> for Commit {
129        fn from(commit: git2::Commit<'a>) -> Self {
130            Commit {
131                id: commit.id().into(),
132            }
133        }
134    }
135}