diff --git a/radicle/src/cob/op.rs b/radicle/src/cob/op.rs index 495a6fb5..ced7b46d 100644 --- a/radicle/src/cob/op.rs +++ b/radicle/src/cob/op.rs @@ -14,6 +14,7 @@ use radicle_crypto::{PublicKey, Signer}; /// Identifies an [`Op`] internally and within the change graph. #[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)] +#[serde(into = "String", try_from = "String")] pub struct OpId(Lamport, ActorId); impl OpId { @@ -43,6 +44,22 @@ impl fmt::Display for OpId { } } +// Used by `serde::Serialize`. +impl From for String { + fn from(value: OpId) -> Self { + value.to_string() + } +} + +// Used by `serde::Deserialize`. +impl TryFrom for OpId { + type Error = OpIdError; + + fn try_from(value: String) -> Result { + value.as_str().try_into() + } +} + /// Error decoding an operation from an entry. #[derive(Error, Debug)] pub enum OpIdError { @@ -233,14 +250,19 @@ mod test { #[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 s = "z6MksFqXN3Yhqk8pTJdUGLwATkRfQvwZXPqR2qMEhbS9wzpT/12"; + let id = OpId::try_from(s).expect("Op ID parses string"); + assert_eq!(s, id.to_string(), "string conversion is consistent"); - let str = ""; - assert!(OpId::try_from(str).is_err(), "empty strings are invalid"); + let s = ""; + assert!(OpId::try_from(s).is_err(), "empty strings are invalid"); - let str = "jlkjfksgi"; - assert!(OpId::try_from(str).is_err(), "badly formatted string"); + let s = "jlkjfksgi"; + assert!(OpId::try_from(s).is_err(), "badly formatted string"); + + assert_eq!( + serde_json::from_str::(serde_json::to_string(&id).unwrap().as_str()).unwrap(), + id + ); } }