tendermint_proto/google/protobuf/
any.rs1use prost::{DecodeError, EncodeError, Message, Name};
5use subtle_encoding::base64;
6
7use crate::prelude::*;
8
9use super::type_url::{type_url_for, TypeUrl};
10use super::PACKAGE;
11
12#[derive(Clone, PartialEq, Eq, ::prost::Message)]
52#[cfg_attr(feature = "json-schema", derive(::schemars::JsonSchema))]
53pub struct Any {
54 #[prost(string, tag = "1")]
82 pub type_url: ::prost::alloc::string::String,
83 #[prost(bytes = "vec", tag = "2")]
85 pub value: ::prost::alloc::vec::Vec<u8>,
86}
87
88impl Any {
89 pub fn from_msg<M>(msg: &M) -> Result<Self, EncodeError>
91 where
92 M: Name,
93 {
94 let type_url = M::type_url();
95 let mut value = Vec::new();
96 Message::encode(msg, &mut value)?;
97 Ok(Any { type_url, value })
98 }
99
100 pub fn to_msg<M>(&self) -> Result<M, DecodeError>
103 where
104 M: Default + Name + Sized,
105 {
106 let expected_type_url = M::type_url();
107
108 if let (Some(expected), Some(actual)) = (
109 TypeUrl::new(&expected_type_url),
110 TypeUrl::new(&self.type_url),
111 ) {
112 if expected == actual {
113 return M::decode(self.value.as_slice());
114 }
115 }
116
117 let mut err = DecodeError::new(format!(
118 "expected type URL: \"{}\" (got: \"{}\")",
119 expected_type_url, &self.type_url
120 ));
121 err.push("unexpected type URL", "type_url");
122 Err(err)
123 }
124}
125
126impl Name for Any {
127 const PACKAGE: &'static str = PACKAGE;
128 const NAME: &'static str = "Any";
129
130 fn type_url() -> String {
131 type_url_for::<Self>()
132 }
133}
134
135impl serde::Serialize for Any {
136 fn serialize<S>(&self, serializer: S) -> core::result::Result<S::Ok, S::Error>
137 where
138 S: serde::Serializer,
139 {
140 use serde::ser::SerializeStruct;
141 let mut len = 0;
142 if !self.type_url.is_empty() {
143 len += 1;
144 }
145 if !self.value.is_empty() {
146 len += 1;
147 }
148 let mut struct_ser = serializer.serialize_struct("google.protobuf.Any", len)?;
149 if !self.type_url.is_empty() {
150 struct_ser.serialize_field("typeUrl", &self.type_url)?;
151 }
152 if !self.value.is_empty() {
153 struct_ser.serialize_field(
155 "value",
156 &String::from_utf8_lossy(&base64::encode(&self.value)),
157 )?;
158 }
159 struct_ser.end()
160 }
161}
162impl<'de> serde::Deserialize<'de> for Any {
163 fn deserialize<D>(deserializer: D) -> core::result::Result<Self, D::Error>
164 where
165 D: serde::Deserializer<'de>,
166 {
167 const FIELDS: &[&str] = &["type_url", "typeUrl", "value"];
168
169 #[allow(clippy::enum_variant_names)]
170 enum GeneratedField {
171 TypeUrl,
172 Value,
173 }
174 impl<'de> serde::Deserialize<'de> for GeneratedField {
175 fn deserialize<D>(deserializer: D) -> core::result::Result<GeneratedField, D::Error>
176 where
177 D: serde::Deserializer<'de>,
178 {
179 struct GeneratedVisitor;
180
181 impl serde::de::Visitor<'_> for GeneratedVisitor {
182 type Value = GeneratedField;
183
184 fn expecting(
185 &self,
186 formatter: &mut core::fmt::Formatter<'_>,
187 ) -> core::fmt::Result {
188 write!(formatter, "expected one of: {:?}", &FIELDS)
189 }
190
191 #[allow(unused_variables)]
192 fn visit_str<E>(self, value: &str) -> core::result::Result<GeneratedField, E>
193 where
194 E: serde::de::Error,
195 {
196 match value {
197 "typeUrl" | "type_url" => Ok(GeneratedField::TypeUrl),
198 "value" => Ok(GeneratedField::Value),
199 _ => Err(serde::de::Error::unknown_field(value, FIELDS)),
200 }
201 }
202 }
203 deserializer.deserialize_identifier(GeneratedVisitor)
204 }
205 }
206 struct GeneratedVisitor;
207 impl<'de> serde::de::Visitor<'de> for GeneratedVisitor {
208 type Value = Any;
209
210 fn expecting(&self, formatter: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
211 formatter.write_str("struct google.protobuf.Any")
212 }
213
214 fn visit_map<V>(self, mut map_: V) -> core::result::Result<Any, V::Error>
215 where
216 V: serde::de::MapAccess<'de>,
217 {
218 let mut type_url__ = None;
219 let mut value__ = None;
220 while let Some(k) = map_.next_key()? {
221 match k {
222 GeneratedField::TypeUrl => {
223 if type_url__.is_some() {
224 return Err(serde::de::Error::duplicate_field("typeUrl"));
225 }
226 type_url__ = Some(map_.next_value()?);
227 },
228 GeneratedField::Value => {
229 if value__.is_some() {
230 return Err(serde::de::Error::duplicate_field("value"));
231 }
232 let b64_str = map_.next_value::<String>()?;
233 let value = base64::decode(b64_str.as_bytes()).map_err(|e| {
234 serde::de::Error::custom(format!("base64 decode error: {e}"))
235 })?;
236 value__ = Some(value);
237 },
238 }
239 }
240 Ok(Any {
241 type_url: type_url__.unwrap_or_default(),
242 value: value__.unwrap_or_default(),
243 })
244 }
245 }
246 deserializer.deserialize_struct("google.protobuf.Any", FIELDS, GeneratedVisitor)
247 }
248}
249
250#[cfg(any(feature = "borsh", feature = "parity-scale-codec"))]
251mod sealed {
252 use super::Any;
253
254 use alloc::string::String;
255 use alloc::vec::Vec;
256
257 #[cfg_attr(
258 feature = "parity-scale-codec",
259 derive(
260 parity_scale_codec::Encode,
261 parity_scale_codec::Decode,
262 scale_info::TypeInfo
263 )
264 )]
265 #[cfg_attr(
266 feature = "borsh",
267 derive(borsh::BorshSerialize, borsh::BorshDeserialize)
268 )]
269 struct InnerAny {
270 pub type_url: String,
271 pub value: Vec<u8>,
272 }
273
274 #[cfg(feature = "borsh")]
275 impl borsh::BorshSerialize for Any {
276 fn serialize<W: borsh::io::Write>(&self, writer: &mut W) -> borsh::io::Result<()> {
277 let inner_any = InnerAny {
278 type_url: self.type_url.clone(),
279 value: self.value.clone(),
280 };
281
282 borsh::BorshSerialize::serialize(&inner_any, writer)
283 }
284 }
285
286 #[cfg(feature = "borsh")]
287 impl borsh::BorshDeserialize for Any {
288 fn deserialize_reader<R: borsh::io::Read>(reader: &mut R) -> borsh::io::Result<Self> {
289 let inner_any = InnerAny::deserialize_reader(reader)?;
290
291 Ok(Any {
292 type_url: inner_any.type_url,
293 value: inner_any.value,
294 })
295 }
296 }
297
298 #[cfg(feature = "parity-scale-codec")]
299 impl parity_scale_codec::Encode for Any {
300 fn encode_to<T: parity_scale_codec::Output + ?Sized>(&self, writer: &mut T) {
301 let inner_any = InnerAny {
302 type_url: self.type_url.clone(),
303 value: self.value.clone(),
304 };
305 inner_any.encode_to(writer);
306 }
307 }
308 #[cfg(feature = "parity-scale-codec")]
309 impl parity_scale_codec::Decode for Any {
310 fn decode<I: parity_scale_codec::Input>(
311 input: &mut I,
312 ) -> Result<Self, parity_scale_codec::Error> {
313 let inner_any = InnerAny::decode(input)?;
314 Ok(Any {
315 type_url: inner_any.type_url.clone(),
316 value: inner_any.value,
317 })
318 }
319 }
320
321 #[cfg(feature = "parity-scale-codec")]
322 impl scale_info::TypeInfo for Any {
323 type Identity = Self;
324
325 fn type_info() -> scale_info::Type {
326 scale_info::Type::builder()
327 .path(scale_info::Path::new("Any", "ibc_proto::google::protobuf"))
328 .composite(
330 scale_info::build::Fields::named()
331 .field(|f| f.ty::<String>().name("type_url").type_name("String"))
332 .field(|f| f.ty::<Vec<u8>>().name("value").type_name("Vec<u8>")),
333 )
334 }
335 }
336}