Add Op ID string formatting
To help users, create an Op ID string format of the form `<actor-id>/<lamport>`. Signed-off-by: Slack Coder <slackcoder@server.ky>
This commit is contained in:
parent
98f7fe1db8
commit
1cb8986830
|
|
@ -1886,6 +1886,7 @@ dependencies = [
|
|||
"radicle-crypto",
|
||||
"serde",
|
||||
"tempfile",
|
||||
"thiserror",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ fastrand = { version = "1.8.0", optional = true }
|
|||
num-traits = { version = "0.2.15", default-features = false, features = ["std"] }
|
||||
qcheck = { version = "1", optional = true }
|
||||
serde = { version = "1" }
|
||||
thiserror = { version = "1" }
|
||||
|
||||
[dependencies.radicle-crypto]
|
||||
path = "../radicle-crypto"
|
||||
|
|
|
|||
|
|
@ -1,8 +1,11 @@
|
|||
use std::fmt;
|
||||
use std::str::FromStr;
|
||||
use std::time::SystemTime;
|
||||
use std::time::UNIX_EPOCH;
|
||||
|
||||
use num_traits::Bounded;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use thiserror::Error;
|
||||
|
||||
use crate::ord::Max;
|
||||
use crate::Semilattice as _;
|
||||
|
|
@ -45,6 +48,12 @@ impl Lamport {
|
|||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for Lamport {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(f, "{}", self.get())
|
||||
}
|
||||
}
|
||||
|
||||
impl From<u64> for Lamport {
|
||||
fn from(counter: u64) -> Self {
|
||||
Self {
|
||||
|
|
@ -53,6 +62,36 @@ impl From<u64> for Lamport {
|
|||
}
|
||||
}
|
||||
|
||||
impl From<Lamport> for u64 {
|
||||
fn from(arg: Lamport) -> Self {
|
||||
arg.get()
|
||||
}
|
||||
}
|
||||
|
||||
/// Error decoding an operation from an entry.
|
||||
#[derive(Error, Debug)]
|
||||
pub enum LamportError {
|
||||
#[error("invalid lamport clock value")]
|
||||
Invalid,
|
||||
}
|
||||
|
||||
impl FromStr for Lamport {
|
||||
type Err = LamportError;
|
||||
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
Self::try_from(s)
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<&str> for Lamport {
|
||||
type Error = LamportError;
|
||||
|
||||
fn try_from(s: &str) -> Result<Self, Self::Error> {
|
||||
let v = s.parse::<u64>().map_err(|_| LamportError::Invalid)?;
|
||||
Ok(v.into())
|
||||
}
|
||||
}
|
||||
|
||||
impl Bounded for Lamport {
|
||||
fn min_value() -> Self {
|
||||
Self::from(u64::min_value())
|
||||
|
|
|
|||
|
|
@ -1,4 +1,7 @@
|
|||
use std::collections::BTreeMap;
|
||||
use std::fmt;
|
||||
use std::str;
|
||||
use std::str::FromStr;
|
||||
|
||||
use nonempty::NonEmpty;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
|
@ -34,6 +37,47 @@ impl OpId {
|
|||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for OpId {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(f, "{}/{}", self.1, self.0)
|
||||
}
|
||||
}
|
||||
|
||||
/// Error decoding an operation from an entry.
|
||||
#[derive(Error, Debug)]
|
||||
pub enum OpIdError {
|
||||
#[error("cannot parse op id from empty string")]
|
||||
Empty,
|
||||
#[error("badly formatted op id")]
|
||||
BadFormat,
|
||||
}
|
||||
|
||||
impl FromStr for OpId {
|
||||
type Err = OpIdError;
|
||||
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
Self::try_from(s)
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<&str> for OpId {
|
||||
type Error = OpIdError;
|
||||
|
||||
fn try_from(s: &str) -> Result<Self, Self::Error> {
|
||||
if s.is_empty() {
|
||||
return Err(OpIdError::Empty);
|
||||
}
|
||||
|
||||
let Some((actor_id, clock)) = s.split_once('/') else {
|
||||
return Err(OpIdError::BadFormat);
|
||||
};
|
||||
Ok(Self(
|
||||
Lamport::from_str(clock).map_err(|_| OpIdError::BadFormat)?,
|
||||
ActorId::from_str(actor_id).map_err(|_| OpIdError::BadFormat)?,
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
/// The author of an [`Op`].
|
||||
pub type ActorId = PublicKey;
|
||||
|
||||
|
|
@ -182,3 +226,21 @@ impl<G: Signer, A: Clone> Actor<G, A> {
|
|||
op
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_opid_try_from_str() {
|
||||
let str = "z6MksFqXN3Yhqk8pTJdUGLwATkRfQvwZXPqR2qMEhbS9wzpT/12";
|
||||
let id = OpId::try_from(str).expect("Op ID parses string");
|
||||
assert_eq!(str, id.to_string(), "string conversion is consistent");
|
||||
|
||||
let str = "";
|
||||
assert!(OpId::try_from(str).is_err(), "empty strings are invalid");
|
||||
|
||||
let str = "jlkjfksgi";
|
||||
assert!(OpId::try_from(str).is_err(), "badly formatted string");
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue