parity_scale_codec/encode_like.rs
1// Copyright 2019 Parity Technologies
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15use crate::codec::Encode;
16
17/// A marker trait that tells the compiler that a type encode to the same representation as another
18/// type.
19///
20/// E.g. `Vec<u8>` has the same encoded representation as `&[u8]`.
21///
22/// # Example
23///
24/// ```
25/// # use parity_scale_codec::{EncodeLike, Encode};
26/// fn encode_like<T: Encode, R: EncodeLike<T>>(data: &R) {
27/// data.encode(); // Valid `T` encoded value.
28/// }
29///
30/// fn main() {
31/// // Just pass the a reference to the normal tuple.
32/// encode_like::<(u32, u32), _>(&(1u32, 2u32));
33/// // Pass a tuple of references
34/// encode_like::<(u32, u32), _>(&(&1u32, &2u32));
35/// // Pass a tuple of a reference and a value.
36/// encode_like::<(u32, u32), _>(&(&1u32, 2u32));
37/// }
38/// ```
39///
40/// # Warning
41///
42/// The relation is not symetric, `T` implements `EncodeLike<U>` does not mean `U` has same
43/// representation as `T`.
44/// For instance we could imaging a non zero integer to be encoded to the same representation as
45/// the said integer but not the other way around.
46///
47/// # Limitation
48///
49/// Not all possible implementations of EncodeLike are implemented (for instance `Box<Box<u32>>`
50/// does not implement `EncodeLike<u32>`). To bypass this issue either open a PR to add the new
51/// combination or use [`Ref`](./struct.Ref.html) reference wrapper or define your own wrapper
52/// and implement `EncodeLike` on it as such:
53/// ```
54/// # use parity_scale_codec::{EncodeLike, Encode, WrapperTypeEncode};
55/// fn encode_like<T: Encode, R: EncodeLike<T>>(data: &R) {
56/// data.encode(); // Valid `T` encoded value.
57/// }
58///
59/// struct MyWrapper<'a>(&'a (Box<Box<u32>>, u32));
60/// impl<'a> core::ops::Deref for MyWrapper<'a> { // Or use derive_deref crate
61/// type Target = (Box<Box<u32>>, u32);
62/// fn deref(&self) -> &Self::Target { &self.0 }
63/// }
64///
65/// impl<'a> parity_scale_codec::WrapperTypeEncode for MyWrapper<'a> {}
66/// impl<'a> parity_scale_codec::EncodeLike<(u32, u32)> for MyWrapper<'a> {}
67///
68/// fn main() {
69/// let v = (Box::new(Box::new(0)), 0);
70/// encode_like::<(u32, u32), _>(&MyWrapper(&v));
71/// }
72/// ```
73pub trait EncodeLike<T: Encode = Self>: Sized + Encode {}
74
75/// Reference wrapper that implement encode like any type that is encoded like its inner type.
76///
77/// # Example
78///
79/// ```rust
80/// # use parity_scale_codec::{EncodeLike, Ref};
81/// fn foo<T: EncodeLike<u8>>(t: T) -> T {
82/// store_t(Ref::from(&t)); // Store t without moving it, but only using a reference.
83/// t
84/// }
85///
86/// fn store_t<T: EncodeLike<u8>>(t: T) {
87/// }
88/// ```
89pub struct Ref<'a, T: EncodeLike<U>, U: Encode>(&'a T, core::marker::PhantomData<U>);
90impl<T: EncodeLike<U>, U: Encode> core::ops::Deref for Ref<'_, T, U> {
91 type Target = T;
92 fn deref(&self) -> &Self::Target {
93 self.0
94 }
95}
96
97impl<'a, T: EncodeLike<U>, U: Encode> From<&'a T> for Ref<'a, T, U> {
98 fn from(x: &'a T) -> Self {
99 Ref(x, Default::default())
100 }
101}
102impl<T: EncodeLike<U>, U: Encode> crate::WrapperTypeEncode for Ref<'_, T, U> {}
103impl<T: EncodeLike<U>, U: Encode> EncodeLike<U> for Ref<'_, T, U> {}
104impl<T: EncodeLike<U>, U: Encode> EncodeLike<U> for &Ref<'_, T, U> {}
105
106#[cfg(test)]
107mod tests {
108 use super::*;
109 use std::collections::BTreeMap;
110
111 struct ComplexStuff<T>(T);
112
113 impl<T: Encode> ComplexStuff<T> {
114 fn complex_method<R: Encode>(value: &R) -> Vec<u8>
115 where
116 T: EncodeLike<R>,
117 {
118 value.encode()
119 }
120 }
121
122 #[test]
123 fn vec_and_slice_are_working() {
124 let slice: &[u8] = &[1, 2, 3, 4];
125 let data: Vec<u8> = slice.to_vec();
126
127 let data_encoded = data.encode();
128 let slice_encoded = ComplexStuff::<Vec<u8>>::complex_method(&slice);
129
130 assert_eq!(slice_encoded, data_encoded);
131 }
132
133 #[test]
134 fn btreemap_and_slice_are_working() {
135 let slice: &[(u32, u32)] = &[(1, 2), (23, 24), (28, 30), (45, 80)];
136 let data: BTreeMap<u32, u32> = slice.iter().copied().collect();
137
138 let data_encoded = data.encode();
139 let slice_encoded = ComplexStuff::<BTreeMap<u32, u32>>::complex_method(&slice);
140
141 assert_eq!(slice_encoded, data_encoded);
142 }
143
144 #[test]
145 fn interface_testing() {
146 let value = 10u32;
147 let data = (value, value, value);
148 let encoded = ComplexStuff::<(u32, u32, u32)>::complex_method(&data);
149 assert_eq!(data.encode(), encoded);
150 let data = (&value, &value, &value);
151 let encoded = ComplexStuff::<(u32, u32, u32)>::complex_method(&data);
152 assert_eq!(data.encode(), encoded);
153 let data = (&value, value, &value);
154 let encoded = ComplexStuff::<(u32, u32, u32)>::complex_method(&data);
155 assert_eq!(data.encode(), encoded);
156
157 let vec_data: Vec<u8> = vec![1, 2, 3];
158 ComplexStuff::<Vec<u8>>::complex_method(&vec_data);
159 ComplexStuff::<&'static str>::complex_method(&String::from("test"));
160 ComplexStuff::<&'static str>::complex_method(&"test");
161
162 let slice: &[u8] = &vec_data;
163 assert_eq!(
164 ComplexStuff::<(u32, Vec<u8>)>::complex_method(&(1u32, slice.to_vec())),
165 ComplexStuff::<(u32, Vec<u8>)>::complex_method(&(1u32, slice))
166 );
167 }
168}