id.rs 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230
  1. use crate::PaymentId;
  2. use serde::{Deserialize, Deserializer, Serialize};
  3. use sha2::{Digest, Sha256};
  4. use std::fmt::Display;
  5. use std::num::ParseIntError;
  6. use std::str::FromStr;
  7. /// Error
  8. #[derive(thiserror::Error, Debug)]
  9. pub enum Error {
  10. /// The number of bytes is invalid
  11. #[error("Invalid length for {0}: {1} (expected: {2})")]
  12. InvalidLength(String, usize, usize),
  13. /// The provided prefix on the string ID is unknown
  14. #[error("Unknown prefix {0}")]
  15. UnknownPrefix(String),
  16. /// Invalid payment ID
  17. #[error("Invalid PaymentId: {0}")]
  18. InvalidPaymentId(#[from] ParseIntError),
  19. }
  20. macro_rules! Id {
  21. ($id:ident, $suffix:expr) => {
  22. #[derive(Clone, Debug, Eq, PartialOrd, Ord, Hash, PartialEq)]
  23. /// A unique identifier for $id
  24. pub struct $id {
  25. bytes: [u8; 32],
  26. }
  27. impl $id {
  28. /// Creates a new instance of $id from the raw bytes
  29. pub fn new(bytes: [u8; 32]) -> Self {
  30. Self { bytes }
  31. }
  32. }
  33. impl FromStr for $id {
  34. type Err = Error;
  35. fn from_str(value: &str) -> Result<Self, Self::Err> {
  36. Ok(Self::try_from(value).unwrap_or_else(|_| {
  37. let mut hasher = Sha256::new();
  38. hasher.update(&value);
  39. Self {
  40. bytes: hasher.finalize().into(),
  41. }
  42. }))
  43. }
  44. }
  45. impl Serialize for $id {
  46. fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
  47. where
  48. S: serde::Serializer,
  49. {
  50. serializer.collect_str(&self)
  51. }
  52. }
  53. impl<'de> Deserialize<'de> for $id {
  54. fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
  55. where
  56. D: Deserializer<'de>,
  57. {
  58. let s = String::deserialize(deserializer)?;
  59. // Use FromStr to parse the string and construct the struct
  60. $id::from_str(&s).map_err(serde::de::Error::custom)
  61. }
  62. }
  63. impl TryFrom<&str> for $id {
  64. type Error = Error;
  65. fn try_from(value: &str) -> Result<Self, Self::Error> {
  66. if $suffix.len() + 64 != value.len() {
  67. return Err(Error::InvalidLength(
  68. stringify!($id).to_owned(),
  69. value.len(),
  70. $suffix.len() + 64,
  71. ));
  72. }
  73. if !value.starts_with($suffix) {
  74. return Err(Error::InvalidLength(
  75. stringify!($id).to_owned(),
  76. value.len(),
  77. $suffix.len() + 64,
  78. ));
  79. }
  80. let bytes = hex::decode(&value[$suffix.len()..]).map_err(|_| {
  81. Error::InvalidLength(stringify!($id).to_owned(), value.len(), 32)
  82. })?;
  83. bytes.try_into()
  84. }
  85. }
  86. impl TryFrom<&[u8]> for $id {
  87. type Error = Error;
  88. fn try_from(value: &[u8]) -> Result<Self, Self::Error> {
  89. if value.len() != 32 {
  90. return Err(Error::InvalidLength(
  91. stringify!($id).to_owned(),
  92. value.len(),
  93. 32,
  94. ));
  95. }
  96. let mut bytes = [0u8; 32];
  97. bytes.copy_from_slice(&value);
  98. Ok(Self { bytes })
  99. }
  100. }
  101. impl TryFrom<Vec<u8>> for $id {
  102. type Error = Error;
  103. fn try_from(value: Vec<u8>) -> Result<Self, Self::Error> {
  104. if value.len() != 32 {
  105. return Err(Error::InvalidLength(
  106. stringify!($id).to_owned(),
  107. value.len(),
  108. 32,
  109. ));
  110. }
  111. let mut bytes = [0u8; 32];
  112. bytes.copy_from_slice(&value);
  113. Ok(Self { bytes })
  114. }
  115. }
  116. impl Display for $id {
  117. fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
  118. write!(f, "{}{}", $suffix, hex::encode(self.bytes))
  119. }
  120. }
  121. impl AsRef<[u8]> for $id {
  122. fn as_ref(&self) -> &[u8] {
  123. &self.bytes
  124. }
  125. }
  126. impl AsRef<[u8; 32]> for $id {
  127. fn as_ref(&self) -> &[u8; 32] {
  128. &self.bytes
  129. }
  130. }
  131. impl std::ops::Deref for $id {
  132. type Target = [u8; 32];
  133. fn deref(&self) -> &Self::Target {
  134. &self.bytes
  135. }
  136. }
  137. };
  138. }
  139. Id!(AccountId, "account");
  140. Id!(TransactionId, "tx");
  141. /// A generic ID wrapper
  142. ///
  143. /// This enum can be used whenever a human ID is passed and needs to be parsed and validated.
  144. #[derive(Debug)]
  145. pub enum AnyId {
  146. /// AccountId
  147. Account(AccountId),
  148. /// TransactionId
  149. Transaction(TransactionId),
  150. /// Payment
  151. Payment(PaymentId),
  152. }
  153. impl FromStr for AnyId {
  154. type Err = Error;
  155. fn from_str(value: &str) -> Result<Self, Self::Err> {
  156. if value.starts_with("account") {
  157. Ok(Self::Account(value.parse()?))
  158. } else if value.starts_with("tx") {
  159. if let Some(at) = value.find(':') {
  160. let (tx, pos) = value.split_at(at);
  161. Ok(Self::Payment(PaymentId {
  162. transaction: tx.parse()?,
  163. position: (pos[1..]).parse()?,
  164. }))
  165. } else {
  166. Ok(Self::Transaction(value.parse()?))
  167. }
  168. } else {
  169. Err(Error::UnknownPrefix(value.to_owned()))
  170. }
  171. }
  172. }
  173. impl<'de> Deserialize<'de> for AnyId {
  174. fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
  175. where
  176. D: Deserializer<'de>,
  177. {
  178. let s = String::deserialize(deserializer)?;
  179. AnyId::from_str(&s).map_err(serde::de::Error::custom)
  180. }
  181. }
  182. #[cfg(test)]
  183. mod test {
  184. use super::*;
  185. #[test]
  186. fn from_random_data() {
  187. let id = "something".parse::<AccountId>().expect("hashed value");
  188. let id_str = id.to_string();
  189. let id_bin: &[u8] = id.as_ref();
  190. assert_eq!(71, id_str.len());
  191. assert_eq!(
  192. <&str as TryInto<AccountId>>::try_into(id_str.as_str()).expect("valid"),
  193. id
  194. );
  195. assert_eq!(
  196. <Vec<u8> as TryInto<AccountId>>::try_into(id_bin.to_owned()).expect("valid"),
  197. id
  198. );
  199. assert_eq!(
  200. <&[u8] as TryInto<AccountId>>::try_into(id_bin).expect("valid"),
  201. id
  202. );
  203. }
  204. }