Skip to main content

snarkvm_console_network/helpers/
object.rs

1// Copyright (c) 2019-2026 Provable Inc.
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 serde::{Deserialize, Deserializer, Serialize, Serializer, de};
20use std::borrow::Borrow;
21
22pub trait Bech32Object<T: Clone + Debug + ToBytes + FromBytes + PartialEq + Eq + Sync + Send>:
23    From<T>
24    + Deref<Target = T>
25    + Clone
26    + Debug
27    + Display
28    + ToBytes
29    + FromBytes
30    + PartialEq
31    + Eq
32    + Serialize
33    + DeserializeOwned
34    + Sync
35    + Send
36{
37    fn prefix() -> String;
38}
39
40/// Converts a string of 4 characters into a `u32` for a human-readable prefix in Bech32.
41#[macro_export]
42macro_rules! hrp4 {
43    ( $persona: expr ) => {{
44        $crate::const_assert!($persona.len() == 4);
45        let p = $persona.as_bytes();
46        u32::from_le_bytes([p[0], p[1], p[2], p[3]])
47    }};
48}
49
50#[derive(Clone, PartialEq, Eq, Hash)]
51pub struct AleoObject<T: Clone + Debug + ToBytes + FromBytes + PartialEq + Eq + Sync + Send, const PREFIX: u32>(T);
52
53impl<T: Clone + Debug + ToBytes + FromBytes + PartialEq + Eq + Sync + Send, const PREFIX: u32> Bech32Object<T>
54    for AleoObject<T, PREFIX>
55{
56    #[inline]
57    fn prefix() -> String {
58        String::from_utf8(PREFIX.to_le_bytes().to_vec()).expect("Failed to convert prefix to string")
59    }
60}
61
62impl<T: Clone + Debug + ToBytes + FromBytes + PartialEq + Eq + Sync + Send, const PREFIX: u32> From<T>
63    for AleoObject<T, PREFIX>
64{
65    #[inline]
66    fn from(data: T) -> Self {
67        Self(data)
68    }
69}
70
71impl<T: Clone + Debug + ToBytes + FromBytes + PartialEq + Eq + Sync + Send, const PREFIX: u32> FromBytes
72    for AleoObject<T, PREFIX>
73{
74    /// Reads data into a buffer.
75    #[inline]
76    fn read_le<R: Read>(mut reader: R) -> IoResult<Self> {
77        Ok(Self(FromBytes::read_le(&mut reader)?))
78    }
79}
80
81impl<T: Clone + Debug + ToBytes + FromBytes + PartialEq + Eq + Sync + Send, const PREFIX: u32> ToBytes
82    for AleoObject<T, PREFIX>
83{
84    /// Writes the data to a buffer.
85    #[inline]
86    fn write_le<W: Write>(&self, mut writer: W) -> IoResult<()> {
87        self.0.write_le(&mut writer)
88    }
89}
90
91impl<T: Clone + Debug + ToBytes + FromBytes + PartialEq + Eq + Sync + Send, const PREFIX: u32> FromStr
92    for AleoObject<T, PREFIX>
93{
94    type Err = Error;
95
96    /// Reads in a bech32m string.
97    #[inline]
98    fn from_str(string: &str) -> Result<Self, Self::Err> {
99        let checked = bech32::primitives::decode::CheckedHrpstring::new::<LongBech32m>(string)?;
100        let hrp = checked.hrp();
101        let data: Vec<u8> = checked.byte_iter().collect();
102        if hrp.as_bytes() != PREFIX.to_le_bytes() {
103            bail!("Invalid prefix for a bech32m hash: {hrp}")
104        };
105        if data.is_empty() {
106            bail!("Bech32m hash data is empty")
107        }
108        Ok(Self::read_le(&*data)?)
109    }
110}
111
112impl<T: Clone + Debug + ToBytes + FromBytes + PartialEq + Eq + Sync + Send, const PREFIX: u32> Display
113    for AleoObject<T, PREFIX>
114{
115    #[inline]
116    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
117        bech32::encode_to_fmt::<LongBech32m, _>(
118            f,
119            bech32::Hrp::parse_unchecked(&Self::prefix()),
120            &self.0.to_bytes_le().expect("Failed to write data as bytes"),
121        )
122        .map_err(|_| fmt::Error)
123    }
124}
125
126impl<T: Clone + Debug + ToBytes + FromBytes + PartialEq + Eq + Sync + Send, const PREFIX: u32> Debug
127    for AleoObject<T, PREFIX>
128{
129    #[inline]
130    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
131        write!(f, "AleoObject {{ hrp: {:?}, data: {:?} }}", &Self::prefix(), self.0)
132    }
133}
134
135impl<T: Clone + Debug + ToBytes + FromBytes + PartialEq + Eq + Sync + Send, const PREFIX: u32> Serialize
136    for AleoObject<T, PREFIX>
137{
138    #[inline]
139    fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
140        match serializer.is_human_readable() {
141            true => serializer.collect_str(self),
142            false => ToBytesSerializer::serialize_with_size_encoding(self, serializer),
143        }
144    }
145}
146
147impl<'de, T: Clone + Debug + ToBytes + FromBytes + PartialEq + Eq + Sync + Send, const PREFIX: u32> Deserialize<'de>
148    for AleoObject<T, PREFIX>
149{
150    #[inline]
151    fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
152        match deserializer.is_human_readable() {
153            true => FromStr::from_str(&String::deserialize(deserializer)?).map_err(de::Error::custom),
154            false => FromBytesDeserializer::<Self>::deserialize_with_size_encoding(deserializer, &Self::prefix()),
155        }
156    }
157}
158
159impl<T: Default + Clone + Debug + ToBytes + FromBytes + PartialEq + Eq + Sync + Send, const PREFIX: u32> Default
160    for AleoObject<T, PREFIX>
161{
162    fn default() -> Self {
163        Self(T::default())
164    }
165}
166
167impl<T: Clone + Debug + ToBytes + FromBytes + PartialEq + Eq + Sync + Send, const PREFIX: u32> Deref
168    for AleoObject<T, PREFIX>
169{
170    type Target = T;
171
172    #[inline]
173    fn deref(&self) -> &Self::Target {
174        &self.0
175    }
176}
177
178impl<T: Clone + Debug + ToBytes + FromBytes + PartialEq + Eq + Sync + Send, const PREFIX: u32> Borrow<T>
179    for AleoObject<T, PREFIX>
180{
181    #[inline]
182    fn borrow(&self) -> &T {
183        &self.0
184    }
185}