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