af_sui_types/
encoding.rs

1//! Encoding types used by Sui.
2//!
3//! This module is mostly to avoid importing [`fastcrypto`](https://github.com/MystenLabs/fastcrypto)
4
5use base64::Engine;
6use base64::engine::GeneralPurpose;
7use serde::{Deserialize, Deserializer, Serialize, Serializer};
8use serde_with::base64::Base64;
9use serde_with::{DeserializeAs, SerializeAs, formats};
10
11/// Default encoder for Base64 data.
12pub(crate) const BASE64_DEFAULT_ENGINE: GeneralPurpose = GeneralPurpose::new(
13    &base64::alphabet::STANDARD,
14    base64::engine::general_purpose::PAD,
15);
16
17/// Convenience method for decoding base64 bytes the way Sui expects.
18pub fn decode_base64_default(value: impl AsRef<[u8]>) -> Result<Vec<u8>, base64::DecodeError> {
19    BASE64_DEFAULT_ENGINE.decode(value)
20}
21
22/// Convenience method for encoding bytes to base64 the way Sui expects.
23pub fn encode_base64_default(value: impl AsRef<[u8]>) -> String {
24    BASE64_DEFAULT_ENGINE.encode(value)
25}
26
27// =============================================================================
28//  Base64Bcs
29// =============================================================================
30
31/// Serialize values with base64-encoded BCS.
32///
33/// The type serializes a value as a base64 string of its BCS encoding.
34/// It works on any type compatible with [`bcs`] for (de)serialization.
35pub struct Base64Bcs<Alphabet = serde_with::base64::Standard, Padding = formats::Padded>(
36    std::marker::PhantomData<(Alphabet, Padding)>,
37)
38where
39    Alphabet: serde_with::base64::Alphabet,
40    Padding: formats::Format;
41
42impl<'de, T, Alphabet, Padding> DeserializeAs<'de, T> for Base64Bcs<Alphabet, Padding>
43where
44    Alphabet: serde_with::base64::Alphabet,
45    Padding: formats::Format,
46    T: for<'a> Deserialize<'a>,
47{
48    fn deserialize_as<D>(deserializer: D) -> Result<T, D::Error>
49    where
50        D: Deserializer<'de>,
51    {
52        let bytes: Vec<u8> = Base64::<Alphabet, Padding>::deserialize_as(deserializer)?;
53        bcs::from_bytes(&bytes).map_err(serde::de::Error::custom)
54    }
55}
56
57impl<T, Alphabet> SerializeAs<T> for Base64Bcs<Alphabet, formats::Padded>
58where
59    Alphabet: serde_with::base64::Alphabet,
60    T: Serialize,
61{
62    fn serialize_as<S>(source: &T, serializer: S) -> Result<S::Ok, S::Error>
63    where
64        S: Serializer,
65    {
66        let bytes = bcs::to_bytes(source).map_err(serde::ser::Error::custom)?;
67        Base64::<Alphabet, formats::Padded>::serialize_as(&bytes, serializer)
68    }
69}
70
71impl<T, Alphabet> SerializeAs<T> for Base64Bcs<Alphabet, formats::Unpadded>
72where
73    Alphabet: serde_with::base64::Alphabet,
74    T: Serialize,
75{
76    fn serialize_as<S>(source: &T, serializer: S) -> Result<S::Ok, S::Error>
77    where
78        S: Serializer,
79    {
80        let bytes = bcs::to_bytes(source).map_err(serde::ser::Error::custom)?;
81        Base64::<Alphabet, formats::Unpadded>::serialize_as(&bytes, serializer)
82    }
83}
84
85// =============================================================================
86//  Base58
87// =============================================================================
88
89/// Base58 encoding format. Can be used with [`serde_with::serde_as`].
90pub struct Base58;
91
92impl Base58 {
93    pub fn decode(data: impl AsRef<[u8]>) -> Result<Vec<u8>, bs58::decode::Error> {
94        bs58::decode(data).into_vec()
95    }
96
97    pub fn encode(data: impl AsRef<[u8]>) -> String {
98        bs58::encode(data).into_string()
99    }
100}
101
102impl<'de, T> DeserializeAs<'de, T> for Base58
103where
104    T: TryFrom<Vec<u8>>,
105    T::Error: std::fmt::Debug,
106{
107    fn deserialize_as<D>(deserializer: D) -> Result<T, D::Error>
108    where
109        D: Deserializer<'de>,
110    {
111        let s = String::deserialize(deserializer)?;
112        let value = Self::decode(&s).map_err(serde::de::Error::custom)?;
113        let length = value.len();
114        value
115            .try_into()
116            .map_err(|error| serde::de::Error::custom(BytesConversionError { length, error }))
117    }
118}
119
120#[derive(thiserror::Error, Debug)]
121#[error("Converting from a Byte Vector of length {length}: {error:?}")]
122pub struct BytesConversionError<E> {
123    pub length: usize,
124    pub error: E,
125}
126
127impl<T> SerializeAs<T> for Base58
128where
129    T: AsRef<[u8]>,
130{
131    fn serialize_as<S>(value: &T, serializer: S) -> Result<S::Ok, S::Error>
132    where
133        S: Serializer,
134    {
135        Self::encode(value).serialize(serializer)
136    }
137}