use std::ops::Deref; use std::{ffi::OsString, fmt, str::FromStr}; use thiserror::Error; use crate::crypto; use crate::git; use crate::serde_ext; pub use crypto::PublicKey; #[derive(Error, Debug)] pub enum IdError { #[error("invalid git object id: {0}")] InvalidOid(#[from] git2::Error), #[error(transparent)] Multibase(#[from] multibase::Error), } #[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] pub struct Id(git::Oid); impl fmt::Display for Id { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.write_str(&self.to_human()) } } impl fmt::Debug for Id { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "Id({})", self) } } impl Id { pub fn to_human(&self) -> String { multibase::encode(multibase::Base::Base58Btc, self.0.as_bytes()) } pub fn from_human(s: &str) -> Result { let (_, bytes) = multibase::decode(s)?; let array: git::Oid = bytes.as_slice().try_into()?; Ok(Self(array)) } } impl FromStr for Id { type Err = IdError; fn from_str(s: &str) -> Result { Self::from_human(s) } } impl TryFrom for Id { type Error = IdError; fn try_from(value: OsString) -> Result { let string = value.to_string_lossy(); Self::from_str(&string) } } impl From for Id { fn from(oid: git::Oid) -> Self { Self(oid) } } impl From for Id { fn from(oid: git2::Oid) -> Self { Self(oid.into()) } } impl Deref for Id { type Target = git::Oid; fn deref(&self) -> &Self::Target { &self.0 } } impl serde::Serialize for Id { fn serialize(&self, serializer: S) -> Result where S: serde::Serializer, { serde_ext::string::serialize(self, serializer) } } impl<'de> serde::Deserialize<'de> for Id { fn deserialize(deserializer: D) -> Result where D: serde::Deserializer<'de>, { serde_ext::string::deserialize(deserializer) } }