1use crate::generated::envoy::{
2 config::{
3 cluster::v3 as xds_cluster, endpoint::v3 as xds_endpoint, listener::v3 as xds_listener,
4 route::v3 as xds_route,
5 },
6 extensions::filters::network::http_connection_manager::v3 as xds_http,
7 extensions::transport_sockets::tls::v3 as xds_tls,
8 service::runtime::v3 as xds_runtime,
9};
10use crate::generated::google::protobuf;
11
12macro_rules! well_known_types {
13 ($(#[$id_attr:meta])* pub enum $id_name:ident { $($(#[$variant_attr:meta])* $variant:ident => $xds_type:ty),* $(,)* }) => {
14 #[derive(Clone, Copy, Debug, PartialEq, Eq)]
15 #[derive(enum_map::Enum)]
16 $(#[$id_attr])*
17 pub enum $id_name {
18 $(
19 $(#[$variant_attr])*
20 $variant,
21 )*
22 }
23
24 impl $id_name {
25 pub fn all() -> &'static [$id_name] {
26 &[
27 $(
28 $id_name::$variant,
29 )*
30 ]
31 }
32
33 pub fn from_type_url(type_url: &str) -> Option<Self> {
34 use prost::Name;
35
36 static FROM_TYPE_URL: std::sync::LazyLock<Box<[(String, $id_name)]>> = std::sync::LazyLock::new(|| {
37 let urls = vec![
38 $(
39 (<$xds_type>::type_url(), $id_name::$variant),
40 )*
41 ];
42 urls.into_boxed_slice()
43 });
44
45 FROM_TYPE_URL.iter().find(|(k, _)| k == type_url).map(|(_, v)| *v)
46 }
47
48 pub fn type_url(&self) -> &'static str {
49 use prost::Name;
50
51 static TO_TYPE_URL: std::sync::LazyLock<enum_map::EnumMap<$id_name, String>> = std::sync::LazyLock::new(|| {
52 enum_map::enum_map! {
53 $(
54 $id_name::$variant => <$xds_type>::type_url(),
55 )*
56 }
57 });
58
59 TO_TYPE_URL[*self].as_str()
60 }
61
62 #[cfg(feature = "pbjson")]
63 fn decode(&self, bs: &[u8]) -> Result<JsonAny, prost::DecodeError> {
64 match self {
65 $(
66 $id_name::$variant => Ok(JsonAny::$variant(prost::Message::decode(bs)?)),
67 )*
68 }
69 }
70 }
71
72 #[cfg(feature = "pbjson")]
73 #[allow(clippy::large_enum_variant)]
74 #[derive(Debug)]
75 enum JsonAny {
76 $(
77 $variant($xds_type),
78 )*
79 }
80
81 #[cfg(feature = "pbjson")]
82 impl serde::Serialize for JsonAny {
83 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
84 where
85 S: serde::Serializer,
86 {
87 #[derive(serde::Serialize)]
88 struct AnyWrapper<'a, T> {
89 #[serde(rename = "@type")]
90 type_url: &'static str,
91
92 #[serde(flatten)]
93 value: &'a T,
94 }
95
96 match self {
97 $(
98 JsonAny::$variant(ref inner) => {
99 let type_url = $id_name::$variant.type_url();
100 let wrapped = AnyWrapper {
101 type_url,
102 value: inner,
103 };
104 wrapped.serialize(serializer)
105 }
106 )*
107 }
108 }
109 }
110 };
111}
112
113well_known_types! {
114 pub enum WellKnownTypes {
149 Listener => xds_listener::Listener,
151
152 HttpConnectionManager => xds_http::HttpConnectionManager,
154
155 RouteConfiguration => xds_route::RouteConfiguration,
157
158 ScopedRouteConfiguration => xds_route::ScopedRouteConfiguration,
160
161 VirtualHost => xds_route::VirtualHost,
163
164 Cluster => xds_cluster::Cluster,
166
167 ClusterLoadAssignment => xds_endpoint::ClusterLoadAssignment,
169
170 Secret => xds_tls::Secret,
172
173 Runtime => xds_runtime::Runtime,
175 }
176}
177
178impl protobuf::Any {
179 pub fn from_msg<M: prost::Name>(m: &M) -> Result<Self, prost::EncodeError> {
180 let type_url = M::type_url();
181 let mut value = Vec::new();
182 prost::Message::encode(m, &mut value)?;
183
184 Ok(Self { type_url, value })
185 }
186
187 pub fn to_msg<M: prost::Name + Default + Sized>(&self) -> Result<M, prost::DecodeError> {
188 let expected_url = M::type_url();
189
190 if self.type_url != expected_url {
191 return Err(prost::DecodeError::new(format!(
192 "unexpected type URL: \"{}\": message url: \"{}\"",
193 &self.type_url, &expected_url,
194 )));
195 }
196
197 M::decode(self.value.as_slice())
198 }
199}
200
201#[cfg(feature = "pbjson")]
202impl serde::Serialize for protobuf::Any {
203 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
204 where
205 S: serde::Serializer,
206 {
207 use serde::ser::SerializeStruct;
208
209 match WellKnownTypes::from_type_url(&self.type_url) {
210 Some(wkt) => {
211 let type_url = wkt.type_url();
212
213 let wk_struct = wkt.decode(&self.value).map_err(|_| {
214 serde::ser::Error::custom(format!(
215 "failed to transcode google.protobuf.Any into {type_url}",
216 ))
217 })?;
218
219 wk_struct.serialize(serializer)
220 }
221 None => {
222 let mut struct_ser = serializer.serialize_struct("google.protobuf.Any", 2)?;
223 struct_ser.serialize_field("@type", &self.type_url)?;
224 struct_ser.serialize_field("value", &self.value)?;
225 struct_ser.end()
226 }
227 }
228 }
229}
230
231#[cfg(feature = "pbjson")]
232impl<'de> serde::Deserialize<'de> for protobuf::Any {
233 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
234 where
235 D: serde::Deserializer<'de>,
236 {
237 const FIELDS: &[&str] = &["@type", "type_url", "typeUrl", "value"];
238
239 enum Field {
240 TypeUrl,
241 Value,
242 }
243
244 impl<'de> serde::Deserialize<'de> for Field {
245 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
246 where
247 D: serde::Deserializer<'de>,
248 {
249 struct Visitor;
250
251 impl<'de> serde::de::Visitor<'de> for Visitor {
252 type Value = Field;
253
254 fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
255 write!(formatter, "expected one of: {FIELDS:?}")
256 }
257
258 fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
259 where
260 E: serde::de::Error,
261 {
262 match v {
263 "@type" | "type_url" | "typeUrl" => Ok(Field::TypeUrl),
264 "value" => Ok(Field::Value),
265 _ => Err(serde::de::Error::unknown_field(v, FIELDS)),
266 }
267 }
268 }
269
270 deserializer.deserialize_identifier(Visitor)
271 }
272 }
273
274 struct Visitor;
275
276 impl<'de> serde::de::Visitor<'de> for Visitor {
277 type Value = protobuf::Any;
278
279 fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
280 formatter.write_str("google.protobuf.Any")
281 }
282
283 fn visit_map<A>(self, mut map: A) -> Result<Self::Value, A::Error>
284 where
285 A: serde::de::MapAccess<'de>,
286 {
287 let mut type_url = None;
288 let mut value = None;
289
290 while let Some(k) = map.next_key()? {
291 match k {
292 Field::TypeUrl => {
293 if type_url.is_some() {
294 return Err(serde::de::Error::duplicate_field("type_url"));
295 }
296 type_url = Some(map.next_value()?);
297 }
298 Field::Value => {
299 if value.is_some() {
300 return Err(serde::de::Error::duplicate_field("value"));
301 }
302 value = Some(map.next_value()?);
303 }
304 }
305 }
306
307 Ok(protobuf::Any {
308 type_url: type_url.unwrap_or_default(),
309 value: value.unwrap_or_default(),
310 })
311 }
312 }
313
314 deserializer.deserialize_struct("google.protobuf.Any", FIELDS, Visitor)
315 }
316}