defuse_serde_utils/
base64.rs

1#![allow(rustdoc::broken_intra_doc_links)]
2//! Helper for [`serde_with::base64::Base64`] to implement [`serde_with::schemars_0_8::JsonSchemaAs`] on it.
3pub use near_sdk::serde_with::{
4    base64::{Alphabet, Standard, UrlSafe},
5    formats::{Format, Padded, Unpadded},
6};
7
8use derive_more::From;
9use near_sdk::{
10    serde::{Deserialize, Deserializer, Serialize, Serializer},
11    serde_with::{DeserializeAs, SerializeAs, serde_as},
12};
13
14pub struct Base64<ALPHABET: Alphabet = Standard, PADDING: Format = Padded>(
15    ::near_sdk::serde_with::base64::Base64<ALPHABET, PADDING>,
16);
17
18impl<T, ALPHABET> SerializeAs<T> for Base64<ALPHABET, Padded>
19where
20    T: AsRef<[u8]>,
21    ALPHABET: Alphabet,
22{
23    fn serialize_as<S>(source: &T, serializer: S) -> Result<S::Ok, S::Error>
24    where
25        S: Serializer,
26    {
27        ::near_sdk::serde_with::base64::Base64::<ALPHABET, Padded>::serialize_as(source, serializer)
28    }
29}
30
31impl<T, ALPHABET> SerializeAs<T> for Base64<ALPHABET, Unpadded>
32where
33    T: AsRef<[u8]>,
34    ALPHABET: Alphabet,
35{
36    fn serialize_as<S>(source: &T, serializer: S) -> Result<S::Ok, S::Error>
37    where
38        S: Serializer,
39    {
40        ::near_sdk::serde_with::base64::Base64::<ALPHABET, Unpadded>::serialize_as(
41            source, serializer,
42        )
43    }
44}
45
46impl<'de, T, ALPHABET, FORMAT> DeserializeAs<'de, T> for Base64<ALPHABET, FORMAT>
47where
48    T: TryFrom<Vec<u8>>,
49    ALPHABET: Alphabet,
50    FORMAT: Format,
51{
52    fn deserialize_as<D>(deserializer: D) -> Result<T, D::Error>
53    where
54        D: Deserializer<'de>,
55    {
56        ::near_sdk::serde_with::base64::Base64::<ALPHABET, FORMAT>::deserialize_as(deserializer)
57    }
58}
59
60/// Helper type to implement `#[derive(Serialize, Deserialize)]`,
61/// as `#[near_bindgen]` doesn't support `#[serde(...)]` attributes on method arguments
62#[cfg_attr(
63    feature = "abi",
64    serde_as(schemars = true),
65    derive(::near_sdk::schemars::JsonSchema),
66    schemars(crate = "::near_sdk::schemars", transparent)
67)]
68#[cfg_attr(
69    not(feature = "abi"),
70    serde_as(crate = "::near_sdk::serde_with", schemars = false)
71)]
72#[derive(Debug, Clone, Copy, Default, Serialize, Deserialize, From)]
73#[serde(
74    crate = "::near_sdk::serde",
75    bound(serialize = "T: AsRef<[u8]>", deserialize = "T: TryFrom<Vec<u8>>")
76)]
77pub struct AsBase64<T>(#[serde_as(as = "Base64")] pub T);
78
79impl<T> AsBase64<T> {
80    #[inline]
81    pub fn into_inner(self) -> T {
82        self.0
83    }
84}
85
86#[cfg(feature = "abi")]
87const _: () = {
88    use near_sdk::{
89        schemars::{
90            JsonSchema,
91            r#gen::SchemaGenerator,
92            schema::{InstanceType, Schema, SchemaObject},
93        },
94        serde_with::schemars_0_8::JsonSchemaAs,
95    };
96
97    impl<T, ALPHABET, FORMAT> JsonSchemaAs<T> for Base64<ALPHABET, FORMAT>
98    where
99        ALPHABET: Alphabet,
100        FORMAT: Format,
101    {
102        fn schema_name() -> String {
103            String::schema_name()
104        }
105
106        fn json_schema(_gen: &mut SchemaGenerator) -> Schema {
107            // TODO: use #[schemars(extend(...))] when released
108            SchemaObject {
109                instance_type: Some(InstanceType::String.into()),
110                extensions: [("contentEncoding", "base64".into())]
111                    .into_iter()
112                    .map(|(k, v)| (k.to_string(), v))
113                    .collect(),
114                ..Default::default()
115            }
116            .into()
117        }
118
119        fn is_referenceable() -> bool {
120            false
121        }
122    }
123};