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