hermes_protobuf_encoding_components/impls/
any.rs

1use core::fmt::Display;
2use core::marker::PhantomData;
3
4use cgp::prelude::*;
5use hermes_encoding_components::traits::convert::Converter;
6use hermes_encoding_components::traits::decode::Decoder;
7use hermes_encoding_components::traits::encode::Encoder;
8use hermes_encoding_components::traits::schema::HasSchema;
9use hermes_encoding_components::traits::types::encoded::HasEncodedType;
10use prost::{DecodeError, Message};
11use prost_types::Any;
12
13#[derive(Debug)]
14pub struct TypeUrlMismatchError {
15    pub expected_url: String,
16    pub actual_url: String,
17}
18
19pub struct EncodeAsAnyProtobuf<InStrategy, InEncoder>(pub PhantomData<(InStrategy, InEncoder)>);
20
21pub struct DecodeAsAnyProtobuf<InStrategy, InEncoder>(pub PhantomData<(InStrategy, InEncoder)>);
22
23impl<InEncoder, Encoding, Strategy, InStrategy, Value> Encoder<Encoding, Strategy, Value>
24    for EncodeAsAnyProtobuf<InStrategy, InEncoder>
25where
26    Encoding: HasEncodedType<Encoded = Vec<u8>> + HasSchema<Value> + HasErrorType,
27    InEncoder: Encoder<Encoding, InStrategy, Value>,
28    Encoding::Schema: Display,
29    Self: Converter<Encoding, Value, Any>,
30{
31    fn encode(encoding: &Encoding, value: &Value) -> Result<Vec<u8>, Encoding::Error> {
32        let any = Self::convert(encoding, value)?;
33
34        Ok(any.encode_to_vec())
35    }
36}
37
38impl<InEncoder, Encoding, InStrategy, Value> Converter<Encoding, Value, Any>
39    for EncodeAsAnyProtobuf<InStrategy, InEncoder>
40where
41    Encoding: HasEncodedType<Encoded = Vec<u8>> + HasSchema<Value> + HasErrorType,
42    InEncoder: Encoder<Encoding, InStrategy, Value>,
43    Encoding::Schema: Display,
44    InStrategy: Async,
45{
46    fn convert(encoding: &Encoding, value: &Value) -> Result<Any, Encoding::Error> {
47        let encoded = InEncoder::encode(encoding, value)?;
48        let type_url = encoding.schema(PhantomData::<Value>);
49
50        let any = Any {
51            value: encoded,
52            type_url: type_url.to_string(),
53        };
54
55        Ok(any)
56    }
57}
58
59impl<InEncoder, Encoding, Strategy, InStrategy, Value> Decoder<Encoding, Strategy, Value>
60    for DecodeAsAnyProtobuf<InStrategy, InEncoder>
61where
62    Encoding: HasEncodedType<Encoded = Vec<u8>> + CanRaiseError<DecodeError>,
63    Self: Converter<Encoding, Any, Value>,
64{
65    fn decode(encoding: &Encoding, encoded: &Vec<u8>) -> Result<Value, Encoding::Error> {
66        let any: Any = Message::decode(encoded.as_ref()).map_err(Encoding::raise_error)?;
67
68        Self::convert(encoding, &any)
69    }
70}
71
72impl<InEncoder, Encoding, InStrategy, Value> Converter<Encoding, Any, Value>
73    for DecodeAsAnyProtobuf<InStrategy, InEncoder>
74where
75    Encoding:
76        HasEncodedType<Encoded = Vec<u8>> + HasSchema<Value> + CanRaiseError<TypeUrlMismatchError>,
77    InEncoder: Decoder<Encoding, InStrategy, Value>,
78    Encoding::Schema: Display,
79    InStrategy: Async,
80{
81    fn convert(encoding: &Encoding, any: &Any) -> Result<Value, Encoding::Error> {
82        let type_url = encoding.schema(PhantomData::<Value>).to_string();
83
84        if any.type_url != type_url {
85            return Err(Encoding::raise_error(TypeUrlMismatchError {
86                expected_url: type_url,
87                actual_url: any.type_url.clone(),
88            }));
89        }
90
91        InEncoder::decode(encoding, &any.value)
92    }
93}