fuel_core_client/client/schema/
primitives.rs

1use super::schema;
2use crate::client::schema::{
3    ConversionError,
4    ConversionError::HexStringPrefixError,
5};
6use core::fmt;
7use cynic::impl_scalar;
8use fuel_core_types::{
9    fuel_tx::PanicInstruction,
10    fuel_types::BlockHeight,
11};
12use serde::{
13    Deserialize,
14    Deserializer,
15    Serialize,
16    Serializer,
17    de::Error,
18};
19use std::{
20    fmt::{
21        Debug,
22        Display,
23        Formatter,
24        LowerHex,
25    },
26    ops::Deref,
27    str::FromStr,
28};
29use tai64::Tai64;
30
31#[derive(Debug, Clone, Default)]
32pub struct HexFormatted<T: Debug + Clone + Default>(pub T);
33
34impl<T: LowerHex + Debug + Clone + Default> Serialize for HexFormatted<T> {
35    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
36    where
37        S: Serializer,
38    {
39        serializer.serialize_str(format!("{:#x}", self.0).as_str())
40    }
41}
42
43impl<'de, T: FromStr<Err = E> + Debug + Clone + Default, E: Display> Deserialize<'de>
44    for HexFormatted<T>
45{
46    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
47    where
48        D: Deserializer<'de>,
49    {
50        let s: String = Deserialize::deserialize(deserializer)?;
51        T::from_str(s.as_str()).map_err(D::Error::custom).map(Self)
52    }
53}
54
55impl<T: FromStr<Err = E> + Debug + Clone + Default, E: Display> FromStr
56    for HexFormatted<T>
57{
58    type Err = ConversionError;
59
60    fn from_str(s: &str) -> Result<Self, Self::Err> {
61        T::from_str(s)
62            .map_err(|e| ConversionError::HexError(format!("{e}")))
63            .map(Self)
64    }
65}
66
67impl<T: LowerHex + Debug + Clone + Default> Display for HexFormatted<T> {
68    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
69        write!(f, "0x{:x}", self.0)
70    }
71}
72
73macro_rules! fuel_type_scalar {
74    ($id:ident, $ft_id:ident) => {
75        #[derive(cynic::Scalar, Debug, Clone, Default)]
76        pub struct $id(pub HexFormatted<::fuel_core_types::fuel_types::$ft_id>);
77
78        impl FromStr for $id {
79            type Err = ConversionError;
80
81            fn from_str(s: &str) -> Result<Self, Self::Err> {
82                let b =
83                    HexFormatted::<::fuel_core_types::fuel_types::$ft_id>::from_str(s)?;
84                Ok($id(b))
85            }
86        }
87
88        impl From<$id> for ::fuel_core_types::fuel_types::$ft_id {
89            fn from(s: $id) -> Self {
90                ::fuel_core_types::fuel_types::$ft_id::new(s.0.0.into())
91            }
92        }
93
94        impl From<::fuel_core_types::fuel_types::$ft_id> for $id {
95            fn from(s: ::fuel_core_types::fuel_types::$ft_id) -> Self {
96                $id(HexFormatted::<::fuel_core_types::fuel_types::$ft_id>(s))
97            }
98        }
99
100        impl Display for $id {
101            fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
102                Display::fmt(&self.0, f)
103            }
104        }
105    };
106}
107
108fuel_type_scalar!(Bytes32, Bytes32);
109fuel_type_scalar!(Address, Address);
110fuel_type_scalar!(BlockId, Bytes32);
111fuel_type_scalar!(AssetId, AssetId);
112fuel_type_scalar!(BlobId, BlobId);
113fuel_type_scalar!(ContractId, ContractId);
114fuel_type_scalar!(SubId, SubAssetId);
115fuel_type_scalar!(Salt, Salt);
116fuel_type_scalar!(TransactionId, Bytes32);
117fuel_type_scalar!(RelayedTransactionId, Bytes32);
118fuel_type_scalar!(Signature, Bytes64);
119fuel_type_scalar!(Nonce, Nonce);
120
121impl LowerHex for Nonce {
122    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
123        LowerHex::fmt(&self.0.0, f)
124    }
125}
126
127#[derive(cynic::Scalar, Debug, Clone, Default)]
128pub struct UtxoId(pub HexFormatted<::fuel_core_types::fuel_tx::UtxoId>);
129
130impl FromStr for UtxoId {
131    type Err = ConversionError;
132
133    fn from_str(s: &str) -> Result<Self, Self::Err> {
134        let b = HexFormatted::<::fuel_core_types::fuel_tx::UtxoId>::from_str(s)?;
135        Ok(UtxoId(b))
136    }
137}
138
139impl From<UtxoId> for ::fuel_core_types::fuel_tx::UtxoId {
140    fn from(s: UtxoId) -> Self {
141        s.0.0
142    }
143}
144
145impl From<fuel_core_types::fuel_tx::UtxoId> for UtxoId {
146    fn from(value: fuel_core_types::fuel_tx::UtxoId) -> Self {
147        Self(HexFormatted(value))
148    }
149}
150
151impl LowerHex for UtxoId {
152    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
153        LowerHex::fmt(&self.0.0, f)
154    }
155}
156
157#[derive(cynic::Scalar, Debug, Clone, Default)]
158pub struct TxPointer(pub HexFormatted<::fuel_core_types::fuel_tx::TxPointer>);
159
160impl FromStr for TxPointer {
161    type Err = ConversionError;
162
163    fn from_str(s: &str) -> Result<Self, Self::Err> {
164        let b = HexFormatted::<::fuel_core_types::fuel_tx::TxPointer>::from_str(s)?;
165        Ok(TxPointer(b))
166    }
167}
168
169impl From<TxPointer> for ::fuel_core_types::fuel_tx::TxPointer {
170    fn from(s: TxPointer) -> Self {
171        s.0.0
172    }
173}
174
175impl LowerHex for TxPointer {
176    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
177        LowerHex::fmt(&self.0.0, f)
178    }
179}
180
181#[derive(cynic::Scalar, Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
182pub struct HexString(pub Bytes);
183
184impl From<HexString> for Vec<u8> {
185    fn from(s: HexString) -> Self {
186        s.0.0
187    }
188}
189
190impl From<HexString> for fuel_core_types::fuel_types::bytes::Bytes {
191    fn from(s: HexString) -> Self {
192        s.0.0.into()
193    }
194}
195
196impl From<Vec<u8>> for HexString {
197    fn from(s: Vec<u8>) -> Self {
198        HexString(Bytes(s))
199    }
200}
201
202impl Deref for HexString {
203    type Target = Bytes;
204
205    fn deref(&self) -> &Self::Target {
206        &self.0
207    }
208}
209
210#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
211pub struct Bytes(pub Vec<u8>);
212
213impl FromStr for Bytes {
214    type Err = ConversionError;
215
216    fn from_str(s: &str) -> Result<Self, Self::Err> {
217        // trim leading 0x
218        let value = s.strip_prefix("0x").ok_or(HexStringPrefixError)?;
219        // decode value into bytes
220        Ok(Bytes(hex::decode(value)?))
221    }
222}
223
224impl Serialize for Bytes {
225    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
226    where
227        S: Serializer,
228    {
229        let hex = format!("0x{}", hex::encode(&self.0));
230        serializer.serialize_str(hex.as_str())
231    }
232}
233
234impl<'de> Deserialize<'de> for Bytes {
235    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
236    where
237        D: Deserializer<'de>,
238    {
239        let s: String = Deserialize::deserialize(deserializer)?;
240        Self::from_str(s.as_str()).map_err(D::Error::custom)
241    }
242}
243
244impl Display for Bytes {
245    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
246        write!(f, "0x{}", hex::encode(&self.0))
247    }
248}
249
250impl Deref for Bytes {
251    type Target = [u8];
252
253    fn deref(&self) -> &Self::Target {
254        &self.0
255    }
256}
257
258macro_rules! number_scalar {
259    ($i:ident, $t:ty) => {
260        #[derive(
261            Debug, Clone, derive_more::Into, derive_more::From, PartialOrd, Eq, PartialEq,
262        )]
263        pub struct $i(pub $t);
264        impl_scalar!($i, schema::$i);
265
266        impl Serialize for $i {
267            fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
268            where
269                S: Serializer,
270            {
271                let s = self.0.to_string();
272                serializer.serialize_str(s.as_str())
273            }
274        }
275
276        impl<'de> Deserialize<'de> for $i {
277            fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
278            where
279                D: Deserializer<'de>,
280            {
281                let s: String = Deserialize::deserialize(deserializer)?;
282                Ok(Self(s.parse().map_err(D::Error::custom)?))
283            }
284        }
285    };
286}
287
288number_scalar!(U128, u128);
289number_scalar!(U64, u64);
290number_scalar!(U32, u32);
291number_scalar!(U16, u16);
292
293impl TryFrom<U64> for PanicInstruction {
294    type Error = ConversionError;
295
296    fn try_from(s: U64) -> Result<Self, Self::Error> {
297        Ok(s.0.into())
298    }
299}
300
301impl From<usize> for U64 {
302    fn from(i: usize) -> Self {
303        U64(i as u64)
304    }
305}
306
307impl From<U32> for BlockHeight {
308    fn from(s: U32) -> Self {
309        s.0.into()
310    }
311}
312
313impl From<BlockHeight> for U32 {
314    fn from(s: BlockHeight) -> U32 {
315        (*s).into()
316    }
317}
318
319#[derive(
320    Debug, Clone, derive_more::Into, derive_more::From, PartialOrd, Eq, PartialEq,
321)]
322pub struct Tai64Timestamp(pub Tai64);
323impl_scalar!(Tai64Timestamp, schema::Tai64Timestamp);
324
325impl Tai64Timestamp {
326    /// Convert Unix timestamp to `Tai64Timestamp`.
327    pub fn from_unix(secs: i64) -> Self {
328        Tai64Timestamp(Tai64::from_unix(secs))
329    }
330
331    /// Convert `Tai64Timestamp` to unix timestamp.
332    pub fn to_unix(self) -> i64 {
333        self.0.to_unix()
334    }
335}
336
337impl Serialize for Tai64Timestamp {
338    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
339    where
340        S: Serializer,
341    {
342        let s = self.0.0.to_string();
343        serializer.serialize_str(s.as_str())
344    }
345}
346
347impl<'de> Deserialize<'de> for Tai64Timestamp {
348    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
349    where
350        D: Deserializer<'de>,
351    {
352        let s: String = Deserialize::deserialize(deserializer)?;
353        Ok(Self(Tai64(s.parse().map_err(D::Error::custom)?)))
354    }
355}
356
357impl BlockId {
358    /// Converts the hash into a message having the same bytes.
359    pub fn into_message(self) -> fuel_core_types::fuel_crypto::Message {
360        let bytes: fuel_core_types::fuel_types::Bytes32 = self.into();
361        fuel_core_types::fuel_crypto::Message::from_bytes(*bytes)
362    }
363}
364
365impl Signature {
366    pub fn into_signature(self) -> fuel_core_types::fuel_crypto::Signature {
367        let bytes: fuel_core_types::fuel_types::Bytes64 = self.into();
368        fuel_core_types::fuel_crypto::Signature::from_bytes(*bytes)
369    }
370}