#![allow(clippy::large_enum_variant)] use std::str::FromStr; use std::sync::Arc; pub use automerge::{ScalarValue, Value}; use crate::cob::patch::*; use crate::git; use crate::prelude::*; /// Implemented by types that can be converted from a [`Value`]. pub trait FromValue<'a>: Sized { fn from_value(val: Value<'a>) -> Result; } #[derive(thiserror::Error, Debug)] pub enum ValueError { #[error("invalid type")] InvalidType, #[error("invalid value: `{0}`")] InvalidValue(String), #[error("value error: {0}")] Other(Arc), } impl<'a, T> FromValue<'a> for Option where T: FromValue<'a>, { fn from_value(val: Value<'a>) -> Result, ValueError> { match val { Value::Scalar(s) if s.is_null() => Ok(None), _ => Ok(Some(T::from_value(val)?)), } } } impl<'a> FromValue<'a> for NodeId { fn from_value(val: Value<'a>) -> Result { let peer = String::from_value(val)?; let peer = NodeId::from_str(&peer).map_err(|e| ValueError::Other(Arc::new(e)))?; Ok(peer) } } impl<'a> FromValue<'a> for uuid::Uuid { fn from_value(val: Value<'a>) -> Result { let uuid = String::from_value(val)?; let uuid = uuid::Uuid::from_str(&uuid).map_err(|e| ValueError::Other(Arc::new(e)))?; Ok(uuid) } } impl<'a> FromValue<'a> for Id { fn from_value(val: Value<'a>) -> Result { let id = String::from_value(val)?; let id = Id::from_str(&id).map_err(|e| ValueError::Other(Arc::new(e)))?; Ok(id) } } impl<'a> FromValue<'a> for git::Oid { fn from_value(val: Value<'a>) -> Result { let oid = String::from_value(val)?; let oid = git::Oid::from_str(&oid).map_err(|e| ValueError::Other(Arc::new(e)))?; Ok(oid) } } impl<'a> FromValue<'a> for String { fn from_value(val: Value) -> Result { val.into_string().map_err(|_| ValueError::InvalidType) } } impl<'a> FromValue<'a> for MergeTarget { fn from_value(value: Value<'a>) -> Result { let state = value.to_str().ok_or(ValueError::InvalidType)?; match state { "delegates" => Ok(Self::Delegates), _ => Err(ValueError::InvalidValue(value.to_string())), } } } impl From for ScalarValue { fn from(target: MergeTarget) -> Self { match target { MergeTarget::Delegates => ScalarValue::from("delegates"), } } }