parity_scale_codec/
max_encoded_len.rs

1// Copyright (C) 2021 Parity Technologies (UK) Ltd.
2// SPDX-License-Identifier: Apache-2.0
3
4// Licensed under the Apache License, Version 2.0 (the "License");
5// you may not use this file except in compliance with the License.
6// You may obtain a copy of the License at
7//
8// 	http://www.apache.org/licenses/LICENSE-2.0
9//
10// Unless required by applicable law or agreed to in writing, software
11// distributed under the License is distributed on an "AS IS" BASIS,
12// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13// See the License for the specific language governing permissions and
14// limitations under the License.
15
16//! `trait MaxEncodedLen` bounds the maximum encoded length of items.
17
18use crate::{Compact, Encode};
19use impl_trait_for_tuples::impl_for_tuples;
20use core::{mem, marker::PhantomData, num::*, ops::{Range, RangeInclusive}, time::Duration};
21use crate::alloc::boxed::Box;
22
23#[cfg(target_has_atomic = "ptr")]
24use crate::alloc::sync::Arc;
25
26/// Items implementing `MaxEncodedLen` have a statically known maximum encoded size.
27///
28/// Some containers, such as `BoundedVec`, have enforced size limits and this trait
29/// can be implemented accurately. Other containers, such as `StorageMap`, do not have enforced size
30/// limits. For those containers, it is necessary to make a documented assumption about the maximum
31/// usage, and compute the max encoded length based on that assumption.
32pub trait MaxEncodedLen: Encode {
33	/// Upper bound, in bytes, of the maximum encoded size of this item.
34	fn max_encoded_len() -> usize;
35}
36
37macro_rules! impl_primitives {
38	( $($t:ty),+ ) => {
39		$(
40			impl MaxEncodedLen for $t {
41				fn max_encoded_len() -> usize {
42					mem::size_of::<$t>()
43				}
44			}
45		)+
46	};
47}
48
49impl_primitives!(u8, u16, u32, u64, u128, i8, i16, i32, i64, i128, bool);
50
51impl_primitives!(
52	NonZeroU8, NonZeroU16, NonZeroU32, NonZeroU64, NonZeroU128, NonZeroI8, NonZeroI16, NonZeroI32,
53	NonZeroI64, NonZeroI128
54);
55
56macro_rules! impl_compact {
57	($( $t:ty => $e:expr; )*) => {
58		$(
59			impl MaxEncodedLen for Compact<$t> {
60				fn max_encoded_len() -> usize {
61					$e
62				}
63			}
64		)*
65	};
66}
67
68impl_compact!(
69	() => 0;
70	// github.com/paritytech/parity-scale-codec/blob/f0341dabb01aa9ff0548558abb6dcc5c31c669a1/src/compact.rs#L261
71	u8 => 2;
72	// github.com/paritytech/parity-scale-codec/blob/f0341dabb01aa9ff0548558abb6dcc5c31c669a1/src/compact.rs#L291
73	u16 => 4;
74	// github.com/paritytech/parity-scale-codec/blob/f0341dabb01aa9ff0548558abb6dcc5c31c669a1/src/compact.rs#L326
75	u32 => 5;
76	// github.com/paritytech/parity-scale-codec/blob/f0341dabb01aa9ff0548558abb6dcc5c31c669a1/src/compact.rs#L369
77	u64 => 9;
78	// github.com/paritytech/parity-scale-codec/blob/f0341dabb01aa9ff0548558abb6dcc5c31c669a1/src/compact.rs#L413
79	u128 => 17;
80);
81
82// impl_for_tuples for values 19 and higher fails because that's where the WrapperTypeEncode impl stops.
83#[impl_for_tuples(18)]
84impl MaxEncodedLen for Tuple {
85	fn max_encoded_len() -> usize {
86		let mut len: usize = 0;
87		for_tuples!( #( len = len.saturating_add(Tuple::max_encoded_len()); )* );
88		len
89	}
90}
91
92impl<T: MaxEncodedLen, const N: usize> MaxEncodedLen for [T; N] {
93	fn max_encoded_len() -> usize {
94		T::max_encoded_len().saturating_mul(N)
95	}
96}
97
98impl<T: MaxEncodedLen> MaxEncodedLen for Box<T> {
99	fn max_encoded_len() -> usize {
100	    T::max_encoded_len()
101	}
102}
103
104#[cfg(target_has_atomic = "ptr")]
105impl<T: MaxEncodedLen> MaxEncodedLen for Arc<T> {
106	fn max_encoded_len() -> usize {
107		T::max_encoded_len()
108	}
109}
110
111impl<T: MaxEncodedLen> MaxEncodedLen for Option<T> {
112	fn max_encoded_len() -> usize {
113		T::max_encoded_len().saturating_add(1)
114	}
115}
116
117impl<T, E> MaxEncodedLen for Result<T, E>
118where
119	T: MaxEncodedLen,
120	E: MaxEncodedLen,
121{
122	fn max_encoded_len() -> usize {
123		T::max_encoded_len().max(E::max_encoded_len()).saturating_add(1)
124	}
125}
126
127impl<T> MaxEncodedLen for PhantomData<T> {
128	fn max_encoded_len() -> usize {
129		0
130	}
131}
132
133impl MaxEncodedLen for Duration {
134	fn max_encoded_len() -> usize {
135	    u64::max_encoded_len() + u32::max_encoded_len()
136	}
137}
138
139impl<T: MaxEncodedLen> MaxEncodedLen for Range<T> {
140	fn max_encoded_len() -> usize {
141	    T::max_encoded_len().saturating_mul(2)
142	}
143}
144
145impl<T: MaxEncodedLen> MaxEncodedLen for RangeInclusive<T> {
146	fn max_encoded_len() -> usize {
147	    T::max_encoded_len().saturating_mul(2)
148	}
149}
150
151#[cfg(test)]
152mod tests {
153	use super::*;
154
155	macro_rules! test_compact_length {
156		($(fn $name:ident($t:ty);)*) => {
157			$(
158				#[test]
159				fn $name() {
160					assert_eq!(Compact(<$t>::MAX).encode().len(), Compact::<$t>::max_encoded_len());
161				}
162			)*
163		};
164	}
165
166	test_compact_length!(
167		fn compact_u8(u8);
168		fn compact_u16(u16);
169		fn compact_u32(u32);
170		fn compact_u64(u64);
171		fn compact_u128(u128);
172	);
173}