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<'a, T: EncodeLike<U>, U: Encode> core::ops::Deref for Ref<'a, T, U> {
91    type Target = T;
92    fn deref(&self) -> &Self::Target { self.0 }
93}
94
95impl<'a, T: EncodeLike<U>, U: Encode> From<&'a T> for Ref<'a, T, U> {
96	fn from(x: &'a T) -> Self {
97		Ref(x, Default::default())
98	}
99}
100impl<'a, T: EncodeLike<U>, U: Encode> crate::WrapperTypeEncode for Ref<'a, T, U> {}
101impl<'a, T: EncodeLike<U>, U: Encode> EncodeLike<U> for Ref<'a, T, U> {}
102impl<'a, T: EncodeLike<U>, U: Encode> EncodeLike<U> for &Ref<'a, T, U> {}
103
104#[cfg(test)]
105mod tests {
106	use super::*;
107	use std::collections::BTreeMap;
108
109	struct ComplexStuff<T>(T);
110
111	impl<T: Encode> ComplexStuff<T> {
112		fn complex_method<R: Encode>(value: &R) -> Vec<u8> where T: EncodeLike<R> {
113			value.encode()
114		}
115	}
116
117	#[test]
118	fn vec_and_slice_are_working() {
119		let slice: &[u8] = &[1, 2, 3, 4];
120		let data: Vec<u8> = slice.iter().copied().collect();
121
122		let data_encoded = data.encode();
123		let slice_encoded = ComplexStuff::<Vec<u8>>::complex_method(&slice);
124
125		assert_eq!(slice_encoded, data_encoded);
126	}
127
128	#[test]
129	fn btreemap_and_slice_are_working() {
130		let slice: &[(u32, u32)] = &[(1, 2), (23, 24), (28, 30), (45, 80)];
131		let data: BTreeMap<u32, u32> = slice.iter().copied().collect();
132
133		let data_encoded = data.encode();
134		let slice_encoded = ComplexStuff::<BTreeMap<u32, u32>>::complex_method(&slice);
135
136		assert_eq!(slice_encoded, data_encoded);
137	}
138
139	#[test]
140	fn interface_testing() {
141		let value = 10u32;
142		let data = (value, value, value);
143		let encoded = ComplexStuff::<(u32, u32, u32)>::complex_method(&data);
144		assert_eq!(data.encode(), encoded);
145		let data = (&value, &value, &value);
146		let encoded = ComplexStuff::<(u32, u32, u32)>::complex_method(&data);
147		assert_eq!(data.encode(), encoded);
148		let data = (&value, value, &value);
149		let encoded = ComplexStuff::<(u32, u32, u32)>::complex_method(&data);
150		assert_eq!(data.encode(), encoded);
151
152		let vec_data: Vec<u8> = vec![1, 2, 3];
153		ComplexStuff::<Vec<u8>>::complex_method(&vec_data);
154		ComplexStuff::<&'static str>::complex_method(&String::from("test"));
155		ComplexStuff::<&'static str>::complex_method(&"test");
156
157		let slice: &[u8] = &vec_data;
158		assert_eq!(
159			ComplexStuff::<(u32, Vec<u8>)>::complex_method(&(1u32, slice.to_vec())),
160			ComplexStuff::<(u32, Vec<u8>)>::complex_method(&(1u32, slice))
161		);
162	}
163}