1use std::fmt::Write;
2use std::marker::PhantomData;
3
4use base64ct::Encoding;
5use serde::{de, ser, Serialize};
6
7use crate::fmt::{self, IndentWriter};
8
9#[derive(Debug, Clone)]
12pub struct Base64Data<T>(pub T);
13
14impl<T> From<T> for Base64Data<T> {
15 fn from(value: T) -> Self {
16 Base64Data(value)
17 }
18}
19
20impl<T> ser::Serialize for Base64Data<T>
21where
22 T: AsRef<[u8]>,
23{
24 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
25 where
26 S: serde::Serializer,
27 {
28 let target = base64ct::Base64UrlUnpadded::encode_string(self.0.as_ref());
29 serializer.serialize_str(&target)
30 }
31}
32
33impl<T> fmt::AcmeFormat for Base64Data<T>
34where
35 T: AsRef<[u8]>,
36{
37 fn fmt<W: fmt::Write>(&self, f: &mut IndentWriter<'_, W>) -> fmt::Result {
38 write!(
39 f,
40 "b64\"{}\"",
41 base64ct::Base64UrlUnpadded::encode_string(self.0.as_ref())
42 )
43 }
44}
45
46#[derive(Debug, Clone)]
49pub struct Base64JSON<T>(pub T);
50
51impl<T> Base64JSON<T>
52where
53 T: Serialize,
54{
55 pub(crate) fn serialized_value(&self) -> Result<String, serde_json::Error> {
56 let inner = serde_json::to_vec(&self.0)?;
57 Ok(base64ct::Base64UrlUnpadded::encode_string(&inner))
58 }
59}
60
61impl<T> From<T> for Base64JSON<T> {
62 fn from(value: T) -> Self {
63 Base64JSON(value)
64 }
65}
66
67impl<T> fmt::AcmeFormat for Base64JSON<T>
68where
69 T: Serialize,
70{
71 fn fmt<W: fmt::Write>(&self, f: &mut IndentWriter<'_, W>) -> fmt::Result {
72 write!(f, "base64url(")?;
73 f.write_json(&self.0)?;
74 f.write_str(")")
75 }
76}
77
78struct Base64JSONVisitor<T>(PhantomData<T>);
79
80impl<'de, T> de::Visitor<'de> for Base64JSONVisitor<T>
81where
82 T: de::DeserializeOwned,
83{
84 type Value = Base64JSON<T>;
85
86 fn expecting(&self, formatter: &mut std::fmt::Formatter) -> fmt::Result {
87 formatter.write_str("a base64url encoded type")
88 }
89
90 fn visit_borrowed_str<E>(self, v: &'de str) -> Result<Self::Value, E>
91 where
92 E: de::Error,
93 {
94 let data = base64ct::Base64UrlUnpadded::decode_vec(v)
95 .map_err(|_| E::invalid_value(de::Unexpected::Str(v), &"invalid base64url encoding"))?;
96
97 let data = serde_json::from_slice(&data)
98 .map_err(|err| E::custom(format!("invalid JSON: {err}")))?;
99 Ok(Base64JSON(data))
100 }
101}
102
103impl<'de, T> de::Deserialize<'de> for Base64JSON<T>
104where
105 T: de::DeserializeOwned,
106{
107 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
108 where
109 D: serde::Deserializer<'de>,
110 {
111 deserializer.deserialize_str(Base64JSONVisitor(PhantomData))
112 }
113}
114
115impl<T> ser::Serialize for Base64JSON<T>
116where
117 T: ser::Serialize,
118{
119 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
120 where
121 S: serde::Serializer,
122 {
123 use serde::ser::Error;
124 let inner = self
125 .serialized_value()
126 .map_err(|err| S::Error::custom(format!("Error producing inner JSON: {err}")))?;
127 serializer.serialize_str(&inner)
128 }
129}