Skip to main content

bilrost/encoding/
proxy.rs

1use crate::buf::ReverseBuf;
2use crate::encoding::{
3    Capped, DecodeContext, DistinguishedValueBorrowDecoder, DistinguishedValueDecoder,
4    ForOverwrite, RestrictedDecodeContext, ValueBorrowDecoder, ValueDecoder, ValueEncoder,
5    WireType, Wiretyped,
6};
7use crate::{Canonicity, DecodeError, DecodeErrorKind};
8use bytes::{Buf, BufMut};
9use core::ops::Deref;
10
11/// `Proxied` is a special encoder which translates the encoded type into its "proxy" type first,
12/// simplifying the encoding logic. It provides value-encoding implementations for types that
13/// implement the proxied conversions defined in `Proxiable` and `DistinguishedProxiable`, which can
14/// then be delegated (such as with `delegate_value_encoding!`) to another encoding to be used as
15/// field types in messages.
16///
17/// `Proxied` itself cannot be used to encode message fields because its
18/// trait support means that it cannot ever implement `Encoder`, `Decoder` etc. for its supported,
19/// un-wrapped types; only when they are nested in `Option<T>`, or appear in a oneof, or in some
20/// other container.
21pub struct Proxied<E, Tag = ()>(E, Tag);
22
23/// Tag struct used for sealing proxy implementations to our own crate specifically. Other crates
24/// may do the same in order to keep their proxy implementations from leaking.
25pub(crate) struct SealedBilrostTag;
26
27/// Implement this trait to make a type supported for encoding by proxy; this can be thought of like
28/// a special pair of `Into` and `TryFrom` implementations that are dedicated to this proxy
29/// specification and are used every time this type is encoded or decoded, since that is essentially
30/// exactly what happens.
31pub trait Proxiable<Tag = ()> {
32    /// The type that the value should appear as when it is encoded on the wire.
33    type Proxy;
34
35    /// Convert this value into a value of the proxy's type.
36    fn encode_proxy(&self) -> Self::Proxy;
37
38    /// Try to store the value represented in the proxy's type in this value, returning an error if
39    /// the value is not valid (ideally the error should be `OutOfDomainValue`, `InvalidValue`, or
40    /// `Other`).
41    fn decode_proxy(&mut self, proxy: Self::Proxy) -> Result<(), DecodeErrorKind>;
42}
43
44/// Extension trait for distinguished types that can decode by proxy.
45pub trait DistinguishedProxiable<Tag = ()>: Proxiable<Tag> {
46    /// Try to store the value represented in the proxy's type in this value, returning an error if
47    /// the value is not valid (ideally the error should be `OutOfDomainValue`, `InvalidValue`, or
48    /// `Other`). On success, return whether the value was a canonical representation (the same
49    /// proxy value that would have been created for this value, `Canonical`) or not
50    /// (`NotCanonical`).
51    fn decode_proxy_distinguished(
52        &mut self,
53        proxy: Self::Proxy,
54    ) -> Result<Canonicity, DecodeErrorKind>;
55}
56
57impl<T, E, Tag> Wiretyped<Proxied<E, Tag>, T> for ()
58where
59    T: Proxiable<Tag>,
60    (): Wiretyped<E, T::Proxy> + ForOverwrite<E, T::Proxy>,
61{
62    const WIRE_TYPE: WireType = <() as Wiretyped<E, T::Proxy>>::WIRE_TYPE;
63}
64
65impl<T, E, Tag> ValueEncoder<Proxied<E, Tag>, T> for ()
66where
67    T: Proxiable<Tag>,
68    (): ForOverwrite<E, T::Proxy> + ValueEncoder<E, T::Proxy>,
69{
70    #[inline]
71    fn encode_value<B: BufMut + ?Sized>(value: &T, buf: &mut B) {
72        <() as ValueEncoder<E, _>>::encode_value(&value.encode_proxy(), buf);
73    }
74
75    #[inline]
76    fn prepend_value<B: ReverseBuf + ?Sized>(value: &T, buf: &mut B) {
77        <() as ValueEncoder<E, _>>::prepend_value(&value.encode_proxy(), buf);
78    }
79
80    #[inline]
81    fn value_encoded_len(value: &T) -> usize {
82        <() as ValueEncoder<E, _>>::value_encoded_len(&value.encode_proxy())
83    }
84
85    #[inline]
86    fn many_values_encoded_len<I>(values: I) -> usize
87    where
88        I: ExactSizeIterator,
89        I::Item: Deref<Target = T>,
90    {
91        /// Do-nothing wrapper allowing us to return items by-value and still have them Deref to T. Maybe
92        /// it would be "more correct" to use Borrow or something like that but this is pretty easy too.
93        #[repr(transparent)]
94        struct WrapDeref<T>(T);
95
96        impl<T> Deref for WrapDeref<T> {
97            type Target = T;
98
99            fn deref(&self) -> &Self::Target {
100                &self.0
101            }
102        }
103
104        <() as ValueEncoder<E, _>>::many_values_encoded_len(
105            values.map(|item| WrapDeref(item.encode_proxy())),
106        )
107    }
108}
109
110impl<T, E, Tag> ValueDecoder<Proxied<E, Tag>, T> for ()
111where
112    T: Proxiable<Tag>,
113    (): ForOverwrite<E, T::Proxy> + ValueDecoder<E, T::Proxy>,
114{
115    #[inline]
116    fn decode_value<B: Buf + ?Sized>(
117        value: &mut T,
118        buf: Capped<B>,
119        ctx: DecodeContext,
120    ) -> Result<(), DecodeError> {
121        let mut proxy = <() as ForOverwrite<E, T::Proxy>>::for_overwrite();
122        <() as ValueDecoder<E, _>>::decode_value(&mut proxy, buf, ctx)?;
123        Ok(value.decode_proxy(proxy)?)
124    }
125}
126
127impl<T, E, Tag> DistinguishedValueDecoder<Proxied<E, Tag>, T> for ()
128where
129    T: DistinguishedProxiable<Tag> + Eq,
130    (): ForOverwrite<E, T::Proxy> + DistinguishedValueDecoder<E, T::Proxy>,
131{
132    const CHECKS_EMPTY: bool = <() as DistinguishedValueDecoder<E, T::Proxy>>::CHECKS_EMPTY;
133
134    fn decode_value_distinguished<const ALLOW_EMPTY: bool>(
135        value: &mut T,
136        buf: Capped<impl Buf + ?Sized>,
137        ctx: RestrictedDecodeContext,
138    ) -> Result<Canonicity, DecodeError> {
139        let mut proxy = <() as ForOverwrite<E, T::Proxy>>::for_overwrite();
140        let mut canon = <() as DistinguishedValueDecoder<E, _>>::decode_value_distinguished::<
141            ALLOW_EMPTY,
142        >(&mut proxy, buf, ctx.clone())?;
143        canon.update(ctx.check(value.decode_proxy_distinguished(proxy)?)?);
144        Ok(canon)
145    }
146}
147
148impl<'a, T, E, Tag> ValueBorrowDecoder<'a, Proxied<E, Tag>, T> for ()
149where
150    T: Proxiable<Tag>,
151    (): ForOverwrite<E, T::Proxy> + ValueBorrowDecoder<'a, E, T::Proxy>,
152{
153    #[inline]
154    fn borrow_decode_value(
155        value: &mut T,
156        buf: Capped<&'a [u8]>,
157        ctx: DecodeContext,
158    ) -> Result<(), DecodeError> {
159        let mut proxy = <() as ForOverwrite<E, T::Proxy>>::for_overwrite();
160        <() as ValueBorrowDecoder<E, _>>::borrow_decode_value(&mut proxy, buf, ctx)?;
161        Ok(value.decode_proxy(proxy)?)
162    }
163}
164
165impl<'a, T, E, Tag> DistinguishedValueBorrowDecoder<'a, Proxied<E, Tag>, T> for ()
166where
167    T: DistinguishedProxiable<Tag> + Eq,
168    (): ForOverwrite<E, T::Proxy> + DistinguishedValueBorrowDecoder<'a, E, T::Proxy>,
169{
170    const CHECKS_EMPTY: bool = <() as DistinguishedValueBorrowDecoder<E, T::Proxy>>::CHECKS_EMPTY;
171
172    fn borrow_decode_value_distinguished<const ALLOW_EMPTY: bool>(
173        value: &mut T,
174        buf: Capped<&'a [u8]>,
175        ctx: RestrictedDecodeContext,
176    ) -> Result<Canonicity, DecodeError> {
177        let mut proxy = <() as ForOverwrite<E, T::Proxy>>::for_overwrite();
178        let mut canon =
179            <() as DistinguishedValueBorrowDecoder<E, _>>::borrow_decode_value_distinguished::<
180                ALLOW_EMPTY,
181            >(&mut proxy, buf, ctx.clone())?;
182        canon.update(ctx.check(value.decode_proxy_distinguished(proxy)?)?);
183        Ok(canon)
184    }
185}