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 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    feature = "abi",
60    serde_as(schemars = true),
61    derive(::schemars::JsonSchema),
62    schemars(transparent)
63)]
64#[cfg_attr(not(feature = "abi"), serde_as(schemars = false))]
65#[derive(Debug, Clone, Copy, Default, Serialize, Deserialize, From)]
66#[serde(bound(serialize = "T: AsRef<[u8]>", deserialize = "T: TryFrom<Vec<u8>>"))]
67pub struct AsBase64<T>(#[serde_as(as = "Base64")] pub T);
68
69impl<T> AsBase64<T> {
70    #[inline]
71    pub fn into_inner(self) -> T {
72        self.0
73    }
74}
75
76#[cfg(feature = "abi")]
77const _: () = {
78    use schemars::{
79        JsonSchema,
80        r#gen::SchemaGenerator,
81        schema::{InstanceType, Schema, SchemaObject},
82    };
83    use serde_with::schemars_0_8::JsonSchemaAs;
84
85    impl<T, ALPHABET, FORMAT> JsonSchemaAs<T> for Base64<ALPHABET, FORMAT>
86    where
87        ALPHABET: Alphabet,
88        FORMAT: Format,
89    {
90        fn schema_name() -> String {
91            String::schema_name()
92        }
93
94        fn json_schema(_gen: &mut SchemaGenerator) -> Schema {
95            // TODO: use #[schemars(extend(...))] when released
96            SchemaObject {
97                instance_type: Some(InstanceType::String.into()),
98                extensions: std::iter::once(("contentEncoding", "base64".into()))
99                    .map(|(k, v)| (k.to_string(), v))
100                    .collect(),
101                ..Default::default()
102            }
103            .into()
104        }
105
106        fn is_referenceable() -> bool {
107            false
108        }
109    }
110};