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}