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::{alloc::boxed::Box, Compact, Encode};
19use core::{
20	marker::PhantomData,
21	mem,
22	num::*,
23	ops::{Range, RangeInclusive},
24	time::Duration,
25};
26use impl_trait_for_tuples::impl_for_tuples;
27
28#[cfg(target_has_atomic = "ptr")]
29use crate::alloc::sync::Arc;
30
31/// Items implementing `MaxEncodedLen` have a statically known maximum encoded size.
32///
33/// Some containers, such as `BoundedVec`, have enforced size limits and this trait
34/// can be implemented accurately. Other containers, such as `StorageMap`, do not have enforced size
35/// limits. For those containers, it is necessary to make a documented assumption about the maximum
36/// usage, and compute the max encoded length based on that assumption.
37pub trait MaxEncodedLen: Encode {
38	/// Upper bound, in bytes, of the maximum encoded size of this item.
39	fn max_encoded_len() -> usize;
40}
41
42macro_rules! impl_primitives {
43	( $($t:ty),+ ) => {
44		$(
45			impl MaxEncodedLen for $t {
46				fn max_encoded_len() -> usize {
47					mem::size_of::<$t>()
48				}
49			}
50		)+
51	};
52}
53
54impl_primitives!(u8, u16, u32, u64, u128, i8, i16, i32, i64, i128, bool);
55
56impl_primitives!(
57	NonZeroU8,
58	NonZeroU16,
59	NonZeroU32,
60	NonZeroU64,
61	NonZeroU128,
62	NonZeroI8,
63	NonZeroI16,
64	NonZeroI32,
65	NonZeroI64,
66	NonZeroI128
67);
68
69macro_rules! impl_compact {
70	($( $t:ty => $e:expr; )*) => {
71		$(
72			impl MaxEncodedLen for Compact<$t> {
73				fn max_encoded_len() -> usize {
74					$e
75				}
76			}
77		)*
78	};
79}
80
81impl_compact!(
82	() => 0;
83	// github.com/paritytech/parity-scale-codec/blob/f0341dabb01aa9ff0548558abb6dcc5c31c669a1/src/compact.rs#L261
84	u8 => 2;
85	// github.com/paritytech/parity-scale-codec/blob/f0341dabb01aa9ff0548558abb6dcc5c31c669a1/src/compact.rs#L291
86	u16 => 4;
87	// github.com/paritytech/parity-scale-codec/blob/f0341dabb01aa9ff0548558abb6dcc5c31c669a1/src/compact.rs#L326
88	u32 => 5;
89	// github.com/paritytech/parity-scale-codec/blob/f0341dabb01aa9ff0548558abb6dcc5c31c669a1/src/compact.rs#L369
90	u64 => 9;
91	// github.com/paritytech/parity-scale-codec/blob/f0341dabb01aa9ff0548558abb6dcc5c31c669a1/src/compact.rs#L413
92	u128 => 17;
93);
94
95// impl_for_tuples for values 19 and higher fails because that's where the WrapperTypeEncode impl
96// stops.
97#[impl_for_tuples(18)]
98impl MaxEncodedLen for Tuple {
99	fn max_encoded_len() -> usize {
100		let mut len: usize = 0;
101		for_tuples!( #( len = len.saturating_add(Tuple::max_encoded_len()); )* );
102		len
103	}
104}
105
106impl<T: MaxEncodedLen, const N: usize> MaxEncodedLen for [T; N] {
107	fn max_encoded_len() -> usize {
108		T::max_encoded_len().saturating_mul(N)
109	}
110}
111
112impl<T: MaxEncodedLen> MaxEncodedLen for Box<T> {
113	fn max_encoded_len() -> usize {
114		T::max_encoded_len()
115	}
116}
117
118#[cfg(target_has_atomic = "ptr")]
119impl<T: MaxEncodedLen> MaxEncodedLen for Arc<T> {
120	fn max_encoded_len() -> usize {
121		T::max_encoded_len()
122	}
123}
124
125impl<T: MaxEncodedLen> MaxEncodedLen for Option<T> {
126	fn max_encoded_len() -> usize {
127		T::max_encoded_len().saturating_add(1)
128	}
129}
130
131impl<T, E> MaxEncodedLen for Result<T, E>
132where
133	T: MaxEncodedLen,
134	E: MaxEncodedLen,
135{
136	fn max_encoded_len() -> usize {
137		T::max_encoded_len().max(E::max_encoded_len()).saturating_add(1)
138	}
139}
140
141impl<T> MaxEncodedLen for PhantomData<T> {
142	fn max_encoded_len() -> usize {
143		0
144	}
145}
146
147impl MaxEncodedLen for Duration {
148	fn max_encoded_len() -> usize {
149		u64::max_encoded_len() + u32::max_encoded_len()
150	}
151}
152
153impl<T: MaxEncodedLen> MaxEncodedLen for Range<T> {
154	fn max_encoded_len() -> usize {
155		T::max_encoded_len().saturating_mul(2)
156	}
157}
158
159impl<T: MaxEncodedLen> MaxEncodedLen for RangeInclusive<T> {
160	fn max_encoded_len() -> usize {
161		T::max_encoded_len().saturating_mul(2)
162	}
163}
164
165#[cfg(test)]
166mod tests {
167	use super::*;
168
169	macro_rules! test_compact_length {
170		($(fn $name:ident($t:ty);)*) => {
171			$(
172				#[test]
173				fn $name() {
174					assert_eq!(Compact(<$t>::MAX).encode().len(), Compact::<$t>::max_encoded_len());
175				}
176			)*
177		};
178	}
179
180	test_compact_length!(
181		fn compact_u8(u8);
182		fn compact_u16(u16);
183		fn compact_u32(u32);
184		fn compact_u64(u64);
185		fn compact_u128(u128);
186	);
187}