cob: Unify change decoding

Signed-off-by: Alexis Sellier <alexis@radicle.xyz>
This commit is contained in:
Alexis Sellier 2022-12-01 20:19:57 +01:00
parent 4e0efa4690
commit fa3c155865
No known key found for this signature in database
4 changed files with 32 additions and 41 deletions

View File

@ -1,15 +1,25 @@
use std::collections::BTreeMap;
use serde::{Deserialize, Serialize};
use thiserror::Error;
use radicle_cob::history::EntryWithClock;
use radicle_crdt::clock;
use radicle_crdt::clock::Lamport;
use radicle_crypto::{PublicKey, Signer};
use serde::{Deserialize, Serialize};
/// Identifies a change.
pub type ChangeId = (Lamport, ActorId);
/// The author of a change.
pub type ActorId = PublicKey;
/// Error decoding a change from an entry.
#[derive(Error, Debug)]
pub enum ChangeDecodeError {
#[error("deserialization from json failed: {0}")]
Deserialize(#[from] serde_json::Error),
}
/// The `Change` is the unit of replication.
/// Everything that can be done in the system is represented by a `Change` object.
/// Changes are applied to an accumulator to yield a final state.
@ -25,6 +35,21 @@ pub struct Change<A> {
pub timestamp: clock::Physical,
}
impl<'a: 'de, 'de, A: serde::Deserialize<'de>> TryFrom<&'a EntryWithClock> for Change<A> {
type Error = ChangeDecodeError;
fn try_from(entry: &'a EntryWithClock) -> Result<Self, Self::Error> {
let action = serde_json::from_slice(entry.contents())?;
Ok(Change {
action,
author: *entry.actor(),
clock: entry.clock().into(),
timestamp: entry.timestamp().into(),
})
}
}
impl<A> Change<A> {
/// Get the change id.
pub fn id(&self) -> ChangeId {

View File

@ -111,13 +111,8 @@ impl store::FromHistory for Issue {
history: &radicle_cob::History,
) -> Result<(Self, clock::Lamport), store::Error> {
let obj = history.traverse(Self::default(), |mut acc, entry| {
if let Ok(action) = Action::decode(entry.contents()) {
if let Err(err) = acc.apply(Change {
action,
author: *entry.actor(),
clock: entry.clock().into(),
timestamp: entry.timestamp().into(),
}) {
if let Ok(change) = Change::try_from(entry) {
if let Err(err) = acc.apply(change) {
log::warn!("Error applying change to issue state: {err}");
return ControlFlow::Break(acc);
}
@ -394,12 +389,6 @@ pub enum Action {
Thread { action: thread::Action },
}
impl Action {
pub fn decode(bytes: &[u8]) -> Result<Self, serde_json::Error> {
serde_json::from_slice(bytes)
}
}
impl From<thread::Action> for Action {
fn from(action: thread::Action) -> Self {
Self::Thread { action }

View File

@ -99,12 +99,6 @@ pub enum Action {
},
}
impl Action {
pub fn decode(bytes: &[u8]) -> Result<Self, serde_json::Error> {
serde_json::from_slice(bytes)
}
}
/// Where a patch is intended to be merged.
#[derive(Default, Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)]
#[serde(rename_all = "lowercase")]
@ -332,13 +326,8 @@ impl store::FromHistory for Patch {
history: &radicle_cob::History,
) -> Result<(Self, clock::Lamport), store::Error> {
let obj = history.traverse(Self::default(), |mut acc, entry| {
if let Ok(action) = Action::decode(entry.contents()) {
if let Err(err) = acc.apply([Change {
action,
author: *entry.actor(),
clock: entry.clock().into(),
timestamp: entry.timestamp().into(),
}]) {
if let Ok(change) = Change::try_from(entry) {
if let Err(err) = acc.apply([change]) {
log::warn!("Error applying change to patch state: {err}");
return ControlFlow::Break(acc);
}

View File

@ -78,13 +78,6 @@ pub enum Action {
},
}
impl Action {
/// Deserialize an action from a byte string.
pub fn decode(bytes: &[u8]) -> Result<Self, serde_json::Error> {
serde_json::from_slice(bytes)
}
}
/// A discussion thread.
#[derive(Debug, Default, Clone, PartialEq, Eq)]
pub struct Thread {
@ -103,13 +96,8 @@ impl store::FromHistory for Thread {
fn from_history(history: &History) -> Result<(Self, Lamport), store::Error> {
let obj = history.traverse(Thread::default(), |mut acc, entry| {
if let Ok(action) = Action::decode(entry.contents()) {
acc.apply([Change {
action,
author: *entry.actor(),
clock: entry.clock().into(),
timestamp: entry.timestamp().into(),
}]);
if let Ok(change) = Change::try_from(entry) {
acc.apply([change]);
ControlFlow::Continue(acc)
} else {
ControlFlow::Break(acc)