typed_codec/
lib.rs

1#![no_std]
2#![deny(missing_docs)]
3
4//! A highly abstracted encode/decode extension for any values.
5
6#[cfg(test)]
7#[macro_use]
8extern crate std;
9
10/// Trait that provides the encoding of the value.
11pub trait Encode {
12    /// Type of value to encode.
13    type Target;
14    /// Type of encoding output.
15    type Output;
16
17    /// Methods to implement the encoding function
18    fn encode(target: Self::Target) -> Self::Output;
19}
20
21/// Trait that provides contextual encoding of value.
22pub trait ContextualEncode {
23    /// Type of value to encode.
24    type Target;
25    /// Type of encoding context.
26    type Context;
27    /// Type of encoding output.
28    type Output;
29
30    /// Methods to implement the contextual encoding function
31    fn encode(target: Self::Target, ctx: Self::Context) -> Self::Output;
32}
33
34/// Trait that provides the decoding of the value.
35pub trait Decode {
36    /// Type of value to decode.
37    type Target;
38    /// Type of decoding output.
39    type Output;
40
41    /// Methods to implement the decoding function
42    fn decode(target: Self::Target) -> Self::Output;
43}
44
45/// Trait that provides the contextual decoding of the value.
46pub trait ContextualDecode {
47    /// Type of value to decode.
48    type Target;
49    /// Type of decoding context.
50    type Context;
51    /// Type of decoding output.
52    type Output;
53
54    /// Methods to implement the contextual decoding function
55    fn decode(value: Self::Target, ctx: Self::Context) -> Self::Output;
56}
57
58/// Trait that provides the encode method for any value.
59pub trait EncodeExt<'a, OUT>: Sized {
60    /// Call this method if the value is immutable.
61    fn encode<E>(&'a self) -> OUT
62    where
63        E: Encode<Target = &'a Self, Output = OUT>;
64
65    /// Call this method if the value is mutable.
66    fn encode_mut<E>(&'a mut self) -> OUT
67    where
68        E: Encode<Target = &'a mut Self, Output = OUT>;
69}
70
71impl<'a, T, OUT> EncodeExt<'a, OUT> for T {
72    fn encode<E>(&'a self) -> OUT
73    where
74        E: Encode<Target = &'a Self, Output = OUT>,
75    {
76        E::encode(self)
77    }
78
79    fn encode_mut<E>(&'a mut self) -> OUT
80    where
81        E: Encode<Target = &'a mut Self, Output = OUT>,
82    {
83        E::encode(self)
84    }
85}
86
87/// Trait that provides the contextual encode method for any value.
88pub trait ContextualEncodeExt<'a, CTX, OUT>: Sized {
89    /// Call this method if the value is immutable.
90    fn contextual_encode<E>(&'a self, ctx: CTX) -> OUT
91    where
92        E: ContextualEncode<Target = &'a Self, Context = CTX, Output = OUT>;
93
94    /// Call this method if the value is mutable.
95    fn contextual_encode_mut<E>(&'a mut self, ctx: CTX) -> OUT
96    where
97        E: ContextualEncode<Target = &'a mut Self, Context = CTX, Output = OUT>;
98}
99
100impl<'a, T, CTX, OUT> ContextualEncodeExt<'a, CTX, OUT> for T {
101    fn contextual_encode<E>(&'a self, ctx: CTX) -> OUT
102    where
103        E: ContextualEncode<Target = &'a Self, Context = CTX, Output = OUT>,
104    {
105        E::encode(self, ctx)
106    }
107
108    fn contextual_encode_mut<E>(&'a mut self, ctx: CTX) -> OUT
109    where
110        E: ContextualEncode<Target = &'a mut Self, Context = CTX, Output = OUT>,
111    {
112        E::encode(self, ctx)
113    }
114}
115
116/// Trait that provides the decode method for any value.
117pub trait DecodeExt<'a, OUT>: Sized {
118    /// Call this method if the value is immutable.
119    fn decode<D>(&'a self) -> OUT
120    where
121        D: Decode<Target = &'a Self, Output = OUT>;
122
123    /// Call this method if the value is mutable.
124    fn decode_mut<D>(&'a mut self) -> OUT
125    where
126        D: Decode<Target = &'a mut Self, Output = OUT>;
127}
128
129impl<'a, T, OUT> DecodeExt<'a, OUT> for T {
130    fn decode<D>(&'a self) -> OUT
131    where
132        D: Decode<Target = &'a Self, Output = OUT>,
133    {
134        D::decode(self)
135    }
136
137    fn decode_mut<D>(&'a mut self) -> OUT
138    where
139        D: Decode<Target = &'a mut Self, Output = OUT>,
140    {
141        D::decode(self)
142    }
143}
144
145/// Trait that provides the contextual decode method for any value.
146pub trait ContextualDecodeExt<'a, CTX, OUT>: Sized {
147    /// Call this method if the value is immutable.
148    fn contextual_decode<D>(&'a self, ctx: CTX) -> OUT
149    where
150        D: ContextualDecode<Target = &'a Self, Context = CTX, Output = OUT>;
151
152    /// Call this method if the value is mutable.
153    fn contextual_decode_mut<D>(&'a mut self, ctx: CTX) -> OUT
154    where
155        D: ContextualDecode<Target = &'a mut Self, Context = CTX, Output = OUT>;
156}
157
158impl<'a, T, CTX, OUT> ContextualDecodeExt<'a, CTX, OUT> for T {
159    fn contextual_decode<D>(&'a self, ctx: CTX) -> OUT
160    where
161        D: ContextualDecode<Target = &'a Self, Context = CTX, Output = OUT>,
162    {
163        D::decode(self, ctx)
164    }
165
166    fn contextual_decode_mut<D>(&'a mut self, ctx: CTX) -> OUT
167    where
168        D: ContextualDecode<Target = &'a mut Self, Context = CTX, Output = OUT>,
169    {
170        D::decode(self, ctx)
171    }
172}
173
174#[cfg(test)]
175mod property_based_test {
176    use super::*;
177    use quickcheck_macros::quickcheck;
178    use std::vec::Vec;
179
180    struct Raw<T>(T);
181
182    impl<T> Encode for Raw<T> {
183        type Target = T;
184        type Output = T;
185
186        fn encode(target: Self::Target) -> Self::Output {
187            target
188        }
189    }
190
191    impl<T> ContextualEncode for Raw<T> {
192        type Target = T;
193        type Context = ();
194        type Output = T;
195
196        fn encode(target: Self::Target, _: Self::Context) -> Self::Output {
197            target
198        }
199    }
200
201    impl<T> Decode for Raw<T> {
202        type Target = T;
203        type Output = T;
204
205        fn decode(target: Self::Target) -> Self::Output {
206            target
207        }
208    }
209
210    impl<T> ContextualDecode for Raw<T> {
211        type Target = T;
212        type Context = ();
213        type Output = T;
214
215        fn decode(target: Self::Target, _: Self::Context) -> Self::Output {
216            target
217        }
218    }
219
220    #[quickcheck]
221    fn equivalent_when_encode(value: Vec<u8>) {
222        let actual = value.encode::<Raw<_>>();
223        let expected = &value;
224        assert_eq!(actual, expected);
225    }
226
227    #[quickcheck]
228    fn equivalent_when_encode_mut(mut value: Vec<u8>) {
229        let expected = &mut value.clone();
230        let actual = value.encode_mut::<Raw<_>>();
231        assert_eq!(actual, expected);
232    }
233
234    #[quickcheck]
235    fn equivalent_when_contextual_encode(value: Vec<u8>) {
236        let actual = value.contextual_encode::<Raw<_>>(());
237        let expected = &value;
238        assert_eq!(actual, expected);
239    }
240
241    #[quickcheck]
242    fn equivalent_when_contextual_encode_mut(mut value: Vec<u8>) {
243        let expected = &mut value.clone();
244        let actual = value.contextual_encode_mut::<Raw<_>>(());
245        assert_eq!(actual, expected);
246    }
247
248    #[quickcheck]
249    fn equivalent_when_decode(value: Vec<u8>) {
250        let actual = value.decode::<Raw<_>>();
251        let expected = &value;
252        assert_eq!(actual, expected);
253    }
254
255    #[quickcheck]
256    fn equivalent_when_decode_mut(mut value: Vec<u8>) {
257        let expected = &mut value.clone();
258        let actual = value.decode_mut::<Raw<_>>();
259        assert_eq!(actual, expected);
260    }
261
262    #[quickcheck]
263    fn equivalent_when_contextual_decode(value: Vec<u8>) {
264        let actual = value.contextual_decode::<Raw<_>>(());
265        let expected = &value;
266        assert_eq!(actual, expected);
267    }
268
269    #[quickcheck]
270    fn equivalent_when_contextual_decode_mut(mut value: Vec<u8>) {
271        let expected = &mut value.clone();
272        let actual = value.contextual_decode_mut::<Raw<_>>(());
273        assert_eq!(actual, expected);
274    }
275}