snarkvm_console_network/helpers/
object.rs

1// Copyright 2024 Aleo Network Foundation
2// This file is part of the snarkVM library.
3
4// Licensed under the Apache License, Version 2.0 (the "License");
5// you may not use this file except in compliance with the License.
6// You may obtain a copy of the License at:
7
8// http://www.apache.org/licenses/LICENSE-2.0
9
10// Unless required by applicable law or agreed to in writing, software
11// distributed under the License is distributed on an "AS IS" BASIS,
12// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13// See the License for the specific language governing permissions and
14// limitations under the License.
15
16use crate::prelude::*;
17
18use anyhow::Result;
19use bech32::{self, FromBase32, ToBase32};
20use serde::{Deserialize, Deserializer, Serialize, Serializer, de};
21use std::borrow::Borrow;
22
23pub trait Bech32Object<T: Clone + Debug + ToBytes + FromBytes + PartialEq + Eq + Sync + Send>:
24    From<T>
25    + Deref<Target = T>
26    + Clone
27    + Debug
28    + Display
29    + ToBytes
30    + FromBytes
31    + PartialEq
32    + Eq
33    + Serialize
34    + DeserializeOwned
35    + Sync
36    + Send
37{
38    fn prefix() -> String;
39}
40
41/// Converts a string of 4 characters into a `u32` for a human-readable prefix in Bech32.
42#[macro_export]
43macro_rules! hrp4 {
44    ( $persona: expr ) => {{
45        $crate::const_assert!($persona.len() == 4);
46        let p = $persona.as_bytes();
47        u32::from_le_bytes([p[0], p[1], p[2], p[3]])
48    }};
49}
50
51#[derive(Clone, PartialEq, Eq, Hash)]
52pub struct AleoObject<T: Clone + Debug + ToBytes + FromBytes + PartialEq + Eq + Sync + Send, const PREFIX: u32>(T);
53
54impl<T: Clone + Debug + ToBytes + FromBytes + PartialEq + Eq + Sync + Send, const PREFIX: u32> Bech32Object<T>
55    for AleoObject<T, PREFIX>
56{
57    #[inline]
58    fn prefix() -> String {
59        String::from_utf8(PREFIX.to_le_bytes().to_vec()).expect("Failed to convert prefix to string")
60    }
61}
62
63impl<T: Clone + Debug + ToBytes + FromBytes + PartialEq + Eq + Sync + Send, const PREFIX: u32> From<T>
64    for AleoObject<T, PREFIX>
65{
66    #[inline]
67    fn from(data: T) -> Self {
68        Self(data)
69    }
70}
71
72impl<T: Clone + Debug + ToBytes + FromBytes + PartialEq + Eq + Sync + Send, const PREFIX: u32> FromBytes
73    for AleoObject<T, PREFIX>
74{
75    /// Reads data into a buffer.
76    #[inline]
77    fn read_le<R: Read>(mut reader: R) -> IoResult<Self> {
78        Ok(Self(FromBytes::read_le(&mut reader)?))
79    }
80}
81
82impl<T: Clone + Debug + ToBytes + FromBytes + PartialEq + Eq + Sync + Send, const PREFIX: u32> ToBytes
83    for AleoObject<T, PREFIX>
84{
85    /// Writes the data to a buffer.
86    #[inline]
87    fn write_le<W: Write>(&self, mut writer: W) -> IoResult<()> {
88        self.0.write_le(&mut writer)
89    }
90}
91
92impl<T: Clone + Debug + ToBytes + FromBytes + PartialEq + Eq + Sync + Send, const PREFIX: u32> FromStr
93    for AleoObject<T, PREFIX>
94{
95    type Err = Error;
96
97    /// Reads in a bech32m string.
98    #[inline]
99    fn from_str(string: &str) -> Result<Self, Self::Err> {
100        let (hrp, data, variant) = bech32::decode(string)?;
101        if hrp.as_bytes() != PREFIX.to_le_bytes() {
102            bail!("Invalid prefix for a bech32m hash: {hrp}")
103        };
104        if data.is_empty() {
105            bail!("Bech32m hash data is empty")
106        }
107        if variant != bech32::Variant::Bech32m {
108            bail!("Hash is not a bech32m hash")
109        }
110        Ok(Self::read_le(&*Vec::from_base32(&data)?)?)
111    }
112}
113
114impl<T: Clone + Debug + ToBytes + FromBytes + PartialEq + Eq + Sync + Send, const PREFIX: u32> Display
115    for AleoObject<T, PREFIX>
116{
117    #[inline]
118    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
119        bech32::encode_to_fmt(
120            f,
121            &Self::prefix(),
122            self.0.to_bytes_le().expect("Failed to write data as bytes").to_base32(),
123            bech32::Variant::Bech32m,
124        )
125        .expect("Failed to encode in bech32m")
126    }
127}
128
129impl<T: Clone + Debug + ToBytes + FromBytes + PartialEq + Eq + Sync + Send, const PREFIX: u32> Debug
130    for AleoObject<T, PREFIX>
131{
132    #[inline]
133    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
134        write!(f, "AleoObject {{ hrp: {:?}, data: {:?} }}", &Self::prefix(), self.0)
135    }
136}
137
138impl<T: Clone + Debug + ToBytes + FromBytes + PartialEq + Eq + Sync + Send, const PREFIX: u32> Serialize
139    for AleoObject<T, PREFIX>
140{
141    #[inline]
142    fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
143        match serializer.is_human_readable() {
144            true => serializer.collect_str(self),
145            false => ToBytesSerializer::serialize_with_size_encoding(self, serializer),
146        }
147    }
148}
149
150impl<'de, T: Clone + Debug + ToBytes + FromBytes + PartialEq + Eq + Sync + Send, const PREFIX: u32> Deserialize<'de>
151    for AleoObject<T, PREFIX>
152{
153    #[inline]
154    fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
155        match deserializer.is_human_readable() {
156            true => FromStr::from_str(&String::deserialize(deserializer)?).map_err(de::Error::custom),
157            false => FromBytesDeserializer::<Self>::deserialize_with_size_encoding(deserializer, &Self::prefix()),
158        }
159    }
160}
161
162impl<T: Default + Clone + Debug + ToBytes + FromBytes + PartialEq + Eq + Sync + Send, const PREFIX: u32> Default
163    for AleoObject<T, PREFIX>
164{
165    fn default() -> Self {
166        Self(T::default())
167    }
168}
169
170impl<T: Clone + Debug + ToBytes + FromBytes + PartialEq + Eq + Sync + Send, const PREFIX: u32> Deref
171    for AleoObject<T, PREFIX>
172{
173    type Target = T;
174
175    #[inline]
176    fn deref(&self) -> &Self::Target {
177        &self.0
178    }
179}
180
181impl<T: Clone + Debug + ToBytes + FromBytes + PartialEq + Eq + Sync + Send, const PREFIX: u32> Borrow<T>
182    for AleoObject<T, PREFIX>
183{
184    #[inline]
185    fn borrow(&self) -> &T {
186        &self.0
187    }
188}