radicle/crefs: Use `GetPayload` to load

Using `GetPayload`, `GetRawCanonicalRefs` can be implemented
generically.
This commit is contained in:
Lorenz Leutgeb 2025-09-18 22:06:53 +02:00 committed by Fintan Halpenny
parent 5167367918
commit a2de55cbb9
3 changed files with 26 additions and 40 deletions

View File

@ -4,19 +4,6 @@ use crate::git::canonical::rules::{RawRules, Rules, ValidationError};
use super::doc::{Delegates, Payload}; use super::doc::{Delegates, Payload};
/// Implemented by any data type or store that can return [`CanonicalRefs`] and
/// [`RawCanonicalRefs`].
pub trait GetRawCanonicalRefs {
type Error: std::error::Error + Send + Sync + 'static;
/// Retrieve the [`RawCanonicalRefs`], returning `Some` if they are
/// present, and `None` if they are absent.
///
/// [`Self::Error`] is used to return any domain-specific error by the
/// implementing type.
fn raw_canonical_refs(&self) -> Result<Option<RawCanonicalRefs>, Self::Error>;
}
/// Configuration for canonical references and their rules. /// Configuration for canonical references and their rules.
/// ///
/// `RawCanonicalRefs` are verified into [`CanonicalRefs`]. /// `RawCanonicalRefs` are verified into [`CanonicalRefs`].

View File

@ -30,7 +30,7 @@ pub use crypto::PublicKey;
pub use radicle_core::repo::*; pub use radicle_core::repo::*;
use super::CanonicalRefs; use super::CanonicalRefs;
use super::crefs::{self, RawCanonicalRefs}; use super::crefs::RawCanonicalRefs;
/// Path to the identity document in the identity branch. /// Path to the identity document in the identity branch.
pub static PATH: LazyLock<&Path> = LazyLock::new(|| Path::new("radicle.json")); pub static PATH: LazyLock<&Path> = LazyLock::new(|| Path::new("radicle.json"));
@ -256,6 +256,10 @@ impl Payload {
) -> Option<&mut serde_json::value::Map<String, serde_json::Value>> { ) -> Option<&mut serde_json::value::Map<String, serde_json::Value>> {
self.value.as_object_mut() self.value.as_object_mut()
} }
pub fn into_inner(self) -> serde_json::Value {
self.value
}
} }
impl From<serde_json::Value> for Payload { impl From<serde_json::Value> for Payload {
@ -774,13 +778,14 @@ impl Doc {
} }
/// Construct the canonical references for this document. /// Construct the canonical references for this document.
/// The implementation of [`crefs::RawCanonicalRefs`] is used to /// The implementation of [`RawCanonicalRefs`] is used to
/// obtain the payload identified by [`PayloadId::canonical_refs`], if it /// obtain the payload identified by [`PayloadId::canonical_refs`], if it
/// exists. /// exists.
/// The resulting [`CanonicalRefs`] are constructed by extension with /// The resulting [`CanonicalRefs`] are constructed by extension with
/// [`Self::default_branch_rule`]. /// [`Self::default_branch_rule`].
///
/// [`RawCanonicalRefs`]: super::crefs::RawCanonicalRefs
pub fn canonical_refs(&self) -> Result<CanonicalRefs, CanonicalRefsError> { pub fn canonical_refs(&self) -> Result<CanonicalRefs, CanonicalRefsError> {
use crefs::GetRawCanonicalRefs;
let raw_crefs = self.raw_canonical_refs()?.unwrap_or_default(); let raw_crefs = self.raw_canonical_refs()?.unwrap_or_default();
let mut raw_rules = raw_crefs.raw_rules().clone(); let mut raw_rules = raw_crefs.raw_rules().clone();
@ -950,40 +955,34 @@ impl Doc {
#[derive(Debug, Error)] #[derive(Debug, Error)]
pub enum CanonicalRefsError { pub enum CanonicalRefsError {
#[error(transparent)] #[error(transparent)]
Json(#[from] serde_json::Error), Raw(#[from] RawCanonicalRefsError),
#[error(transparent)] #[error(transparent)]
CanonicalRefs(#[from] rules::ValidationError), CanonicalRefs(#[from] rules::ValidationError),
#[error(transparent)] #[error(transparent)]
DefaultBranch(#[from] DefaultBranchRuleError), DefaultBranch(#[from] DefaultBranchRuleError),
} }
impl crefs::GetRawCanonicalRefs for Doc { #[derive(Debug, Error)]
type Error = CanonicalRefsError; pub enum RawCanonicalRefsError {
#[error(transparent)]
Json(#[from] serde_json::Error),
}
fn raw_canonical_refs(&self) -> Result<Option<RawCanonicalRefs>, Self::Error> { pub trait GetRawCanonicalRefs: GetPayload {
let value = self.payload.get(&PayloadId::canonical_refs()); /// Retrieve the [`RawCanonicalRefs`] by deserializing from the payload
let crefs = value /// (if present).
.map(|value| { fn raw_canonical_refs(&self) -> Result<Option<RawCanonicalRefs>, RawCanonicalRefsError> {
serde_json::from_value((**value).clone()).map_err(CanonicalRefsError::from) let Some(value) = self.get_payload(&PayloadId::canonical_refs()) else {
}) return Ok(None);
.transpose()?; };
Ok(crefs)
Ok(Some(serde_json::from_value(value.to_owned().into_inner())?))
} }
} }
impl crefs::GetRawCanonicalRefs for RawDoc { impl GetRawCanonicalRefs for Doc {}
type Error = CanonicalRefsError;
fn raw_canonical_refs(&self) -> Result<Option<RawCanonicalRefs>, Self::Error> { impl GetRawCanonicalRefs for RawDoc {}
let value = self.payload.get(&PayloadId::canonical_refs());
let crefs = value
.map(|value| {
serde_json::from_value((**value).clone()).map_err(CanonicalRefsError::from)
})
.transpose()?;
Ok(crefs)
}
}
#[cfg(test)] #[cfg(test)]
#[allow(clippy::unwrap_used)] #[allow(clippy::unwrap_used)]

View File

@ -211,7 +211,7 @@ pub fn verify(raw: RawDoc) -> Result<Doc, error::DocVerification> {
// Ensure that if we have canonical reference rules and a project, that no // Ensure that if we have canonical reference rules and a project, that no
// rule exists for the default branch. This rule must be synthesized when // rule exists for the default branch. This rule must be synthesized when
// constructing the canonical reference rules. // constructing the canonical reference rules.
use super::crefs::GetRawCanonicalRefs as _; use super::GetRawCanonicalRefs as _;
match raw match raw
.raw_canonical_refs() .raw_canonical_refs()
.map(|rcrefs| rcrefs.and_then(|c| project.map(|p| (c, p)))) .map(|rcrefs| rcrefs.and_then(|c| project.map(|p| (c, p))))