use serde::{de, Deserialize, Deserializer, Serialize}; use sha2::{Digest, Sha256}; use std::{fmt::Display, ops::Deref, str::FromStr}; #[derive( Clone, Debug, Eq, Hash, Ord, PartialOrd, PartialEq, Serialize, borsh::BorshDeserialize, borsh::BorshSerialize, )] /// A string with a max-length checked at compiled time pub struct MaxLengthString(String); impl PartialEq for MaxLengthString { fn eq(&self, other: &str) -> bool { self.0.eq(other) } } impl FromStr for MaxLengthString { type Err = Error; fn from_str(value: &str) -> Result { Self::new(value.to_owned()) } } impl From<&str> for MaxLengthString { fn from(value: &str) -> Self { Self::new(value.to_owned()).expect("The string is too long") } } impl Display for MaxLengthString { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { write!(f, "{}", self.0) } } impl MaxLengthString { /// Creates a new instance of MaxLengthString pub fn new(value: String) -> Result { if value.len() > MAX_LENGTH { Err(Error::TooLong(MAX_LENGTH)) } else { Ok(Self(value)) } } } impl Deref for MaxLengthString { type Target = String; fn deref(&self) -> &Self::Target { &self.0 } } impl<'de, const MAX_LENGTH: usize> de::Deserialize<'de> for MaxLengthString { fn deserialize(deserializer: D) -> Result where D: de::Deserializer<'de>, { ::deserialize(deserializer) .and_then(|inner| Self::new(inner).map_err(|e| de::Error::custom(e.to_string()))) } } /// The AccountId data type pub type AccountId = MaxLengthString<64>; crate::BinaryId!(TxId, "tx-"); crate::BinaryId!(RevId, "rev-"); /// A generic ID wrapper /// /// This enum can be used whenever a human ID is passed and needs to be parsed and validated. #[derive(Debug)] pub enum AnyId { /// TxId Transaction(TxId), /// Payment Payment(PaymentId), /// Account ID Account(AccountId), } impl FromStr for AnyId { type Err = Error; fn from_str(value: &str) -> Result { if value.starts_with("tx") { if let Some(at) = value.find(':') { let (tx, pos) = value.split_at(at); return Ok(Self::Payment(PaymentId { transaction: tx.parse()?, position: (pos[1..]).parse()?, })); } else { return Ok(Self::Transaction(value.parse()?)); } } Ok(Self::Account(value.parse()?)) } } impl<'de> Deserialize<'de> for AnyId { fn deserialize(deserializer: D) -> Result where D: Deserializer<'de>, { let s = String::deserialize(deserializer)?; AnyId::from_str(&s).map_err(serde::de::Error::custom) } } mod binary; mod error; mod payment; pub use self::{error::Error, payment::PaymentId};