Skip to main content

jam_codec/
compact.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
15//! [Compact encoding](https://docs.substrate.io/v3/advanced/scale-codec/#compactgeneral-integers)
16
17use arrayvec::ArrayVec;
18
19use crate::{
20	alloc::vec::Vec,
21	codec::{Decode, Encode, EncodeAsRef, Input, Output},
22	encode_like::EncodeLike,
23	DecodeWithMemTracking, Error,
24};
25
26#[cfg(feature = "fuzz")]
27use arbitrary::Arbitrary;
28
29struct ArrayVecWrapper<const N: usize>(ArrayVec<u8, N>);
30
31impl<const N: usize> Output for ArrayVecWrapper<N> {
32	fn write(&mut self, bytes: &[u8]) {
33		let old_len = self.0.len();
34		let new_len = old_len + bytes.len();
35
36		assert!(new_len <= self.0.capacity());
37		unsafe {
38			self.0.set_len(new_len);
39		}
40
41		self.0[old_len..new_len].copy_from_slice(bytes);
42	}
43
44	fn push_byte(&mut self, byte: u8) {
45		self.0.push(byte);
46	}
47}
48
49/// Something that can return the compact encoded length for a given value.
50pub trait CompactLen<T> {
51	/// Returns the compact encoded length for the given value.
52	fn compact_len(val: &T) -> usize;
53}
54
55/// Compact-encoded variant of T. This is more space-efficient but less compute-efficient.
56#[derive(Eq, PartialEq, Clone, Copy, Ord, PartialOrd)]
57#[cfg_attr(feature = "fuzz", derive(Arbitrary))]
58pub struct Compact<T>(pub T);
59
60impl<T> From<T> for Compact<T> {
61	fn from(x: T) -> Compact<T> {
62		Compact(x)
63	}
64}
65
66impl<'a, T: Copy> From<&'a T> for Compact<T> {
67	fn from(x: &'a T) -> Compact<T> {
68		Compact(*x)
69	}
70}
71
72/// Allow foreign structs to be wrap in Compact
73pub trait CompactAs: From<Compact<Self>> {
74	/// A compact-encodable type that should be used as the encoding.
75	type As;
76
77	/// Returns the compact-encodable type.
78	fn encode_as(&self) -> &Self::As;
79
80	/// Decode `Self` from the compact-decoded type.
81	fn decode_from(_: Self::As) -> Result<Self, Error>;
82}
83
84impl<T> EncodeLike for Compact<T> where for<'a> CompactRef<'a, T>: Encode {}
85
86impl<T> Encode for Compact<T>
87where
88	for<'a> CompactRef<'a, T>: Encode,
89{
90	fn size_hint(&self) -> usize {
91		CompactRef(&self.0).size_hint()
92	}
93
94	fn encode_to<W: Output + ?Sized>(&self, dest: &mut W) {
95		CompactRef(&self.0).encode_to(dest)
96	}
97
98	fn encode(&self) -> Vec<u8> {
99		CompactRef(&self.0).encode()
100	}
101
102	fn using_encoded<R, F: FnOnce(&[u8]) -> R>(&self, f: F) -> R {
103		CompactRef(&self.0).using_encoded(f)
104	}
105}
106
107impl<T> EncodeLike for CompactRef<'_, T>
108where
109	T: CompactAs,
110	for<'b> CompactRef<'b, T::As>: Encode,
111{
112}
113
114impl<T> Encode for CompactRef<'_, T>
115where
116	T: CompactAs,
117	for<'b> CompactRef<'b, T::As>: Encode,
118{
119	fn size_hint(&self) -> usize {
120		CompactRef(self.0.encode_as()).size_hint()
121	}
122
123	fn encode_to<Out: Output + ?Sized>(&self, dest: &mut Out) {
124		CompactRef(self.0.encode_as()).encode_to(dest)
125	}
126
127	fn encode(&self) -> Vec<u8> {
128		CompactRef(self.0.encode_as()).encode()
129	}
130
131	fn using_encoded<R, F: FnOnce(&[u8]) -> R>(&self, f: F) -> R {
132		CompactRef(self.0.encode_as()).using_encoded(f)
133	}
134}
135
136impl<T> Decode for Compact<T>
137where
138	T: CompactAs,
139	Compact<T::As>: Decode,
140{
141	fn decode<I: Input>(input: &mut I) -> Result<Self, Error> {
142		let as_ = Compact::<T::As>::decode(input)?;
143		Ok(Compact(<T as CompactAs>::decode_from(as_.0)?))
144	}
145}
146
147impl<T> DecodeWithMemTracking for Compact<T>
148where
149	T: CompactAs,
150	Compact<T::As>: DecodeWithMemTracking,
151{
152}
153
154macro_rules! impl_from_compact {
155	( $( $ty:ty ),* ) => {
156		$(
157			impl From<Compact<$ty>> for $ty {
158				fn from(x: Compact<$ty>) -> $ty { x.0 }
159			}
160		)*
161	}
162}
163
164impl_from_compact! { (), u8, u16, u32, u64, u128 }
165
166/// Compact-encoded variant of &'a T. This is more space-efficient but less compute-efficient.
167#[derive(Eq, PartialEq, Clone, Copy)]
168pub struct CompactRef<'a, T>(pub &'a T);
169
170impl<'a, T> From<&'a T> for CompactRef<'a, T> {
171	fn from(x: &'a T) -> Self {
172		CompactRef(x)
173	}
174}
175
176impl<T> core::fmt::Debug for Compact<T>
177where
178	T: core::fmt::Debug,
179{
180	fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
181		self.0.fmt(f)
182	}
183}
184
185#[cfg(feature = "serde")]
186impl<T> serde::Serialize for Compact<T>
187where
188	T: serde::Serialize,
189{
190	fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
191	where
192		S: serde::Serializer,
193	{
194		T::serialize(&self.0, serializer)
195	}
196}
197
198#[cfg(feature = "serde")]
199impl<'de, T> serde::Deserialize<'de> for Compact<T>
200where
201	T: serde::Deserialize<'de>,
202{
203	fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
204	where
205		D: serde::Deserializer<'de>,
206	{
207		T::deserialize(deserializer).map(Compact)
208	}
209}
210
211/// Trait that tells you if a given type can be encoded/decoded in a compact way.
212pub trait HasCompact: Sized {
213	/// The compact type; this can be
214	type Type: for<'a> EncodeAsRef<'a, Self> + Decode + From<Self> + Into<Self>;
215}
216
217impl<'a, T: 'a> EncodeAsRef<'a, T> for Compact<T>
218where
219	CompactRef<'a, T>: Encode + From<&'a T>,
220{
221	type RefType = CompactRef<'a, T>;
222}
223
224impl<T: 'static> HasCompact for T
225where
226	Compact<T>: for<'a> EncodeAsRef<'a, T> + Decode + From<Self> + Into<Self>,
227{
228	type Type = Compact<T>;
229}
230
231impl Encode for CompactRef<'_, ()> {
232	fn encode_to<W: Output + ?Sized>(&self, _dest: &mut W) {}
233
234	fn using_encoded<R, F: FnOnce(&[u8]) -> R>(&self, f: F) -> R {
235		f(&[])
236	}
237
238	fn encode(&self) -> Vec<u8> {
239		Vec::new()
240	}
241}
242
243struct WrappedPrimitive<T>(T);
244
245#[inline(always)]
246fn compact_extra_bytes(x: u64) -> usize {
247	(0..8).find(|&l| x < 1 << (7 * (l + 1))).unwrap_or(8)
248}
249
250impl<T> CompactLen<T> for WrappedPrimitive<T>
251where
252	T: Copy + Into<u64>,
253{
254	fn compact_len(val: &T) -> usize {
255		1 + compact_extra_bytes((*val).into())
256	}
257}
258
259impl<T> Encode for WrappedPrimitive<T>
260where
261	T: Copy + Into<u64>,
262{
263	fn size_hint(&self) -> usize {
264		Self::compact_len(&self.0)
265	}
266
267	fn encode_to<W: Output + ?Sized>(&self, dest: &mut W) {
268		let x = self.0.into();
269		let l = compact_extra_bytes(x);
270		let prefix = if l == 8 { 0xff } else { !(0xff >> l) | (x >> (8 * l)) as u8 };
271		dest.push_byte(prefix);
272		dest.write(&x.to_le_bytes()[..l]);
273	}
274
275	fn using_encoded<R, F: FnOnce(&[u8]) -> R>(&self, f: F) -> R {
276		let mut r = ArrayVecWrapper(ArrayVec::<u8, 9>::new());
277		self.encode_to(&mut r);
278		f(&r.0)
279	}
280}
281
282impl<T> Decode for WrappedPrimitive<T>
283where
284	T: Copy + TryFrom<u64>,
285{
286	fn decode<I: Input>(input: &mut I) -> Result<Self, Error> {
287		let prefix = input.read_byte()?;
288		let l = prefix.leading_ones() as usize;
289		let mut buf = [0u8; 8];
290		input.read(&mut buf[..l])?;
291		let high = if l == 8 { 0 } else { u64::from(prefix & (0x7f >> l)) << (8 * l) };
292		let x = u64::from_le_bytes(buf) | high;
293		if compact_extra_bytes(x) != l {
294			return Err("Non-canonical compact encoding".into());
295		}
296		T::try_from(x).map(Self).map_err(|_| "Out of range".into())
297	}
298}
299
300impl Encode for CompactRef<'_, u8> {
301	fn size_hint(&self) -> usize {
302		WrappedPrimitive(*self.0).size_hint()
303	}
304
305	fn encode_to<W: Output + ?Sized>(&self, dest: &mut W) {
306		WrappedPrimitive(*self.0).encode_to(dest)
307	}
308
309	fn using_encoded<R, F: FnOnce(&[u8]) -> R>(&self, f: F) -> R {
310		WrappedPrimitive(*self.0).using_encoded(f)
311	}
312}
313
314impl CompactLen<u8> for Compact<u8> {
315	fn compact_len(val: &u8) -> usize {
316		WrappedPrimitive::<u8>::compact_len(val)
317	}
318}
319
320impl Encode for CompactRef<'_, u16> {
321	fn size_hint(&self) -> usize {
322		WrappedPrimitive(*self.0).size_hint()
323	}
324
325	fn encode_to<W: Output + ?Sized>(&self, dest: &mut W) {
326		WrappedPrimitive(*self.0).encode_to(dest)
327	}
328
329	fn using_encoded<R, F: FnOnce(&[u8]) -> R>(&self, f: F) -> R {
330		WrappedPrimitive(*self.0).using_encoded(f)
331	}
332}
333
334impl CompactLen<u16> for Compact<u16> {
335	fn compact_len(val: &u16) -> usize {
336		WrappedPrimitive::<u16>::compact_len(val)
337	}
338}
339
340impl Encode for CompactRef<'_, u32> {
341	fn size_hint(&self) -> usize {
342		WrappedPrimitive(*self.0).size_hint()
343	}
344
345	fn encode_to<W: Output + ?Sized>(&self, dest: &mut W) {
346		WrappedPrimitive(*self.0).encode_to(dest)
347	}
348
349	fn using_encoded<R, F: FnOnce(&[u8]) -> R>(&self, f: F) -> R {
350		WrappedPrimitive(*self.0).using_encoded(f)
351	}
352}
353
354impl CompactLen<u32> for Compact<u32> {
355	fn compact_len(val: &u32) -> usize {
356		WrappedPrimitive::<u32>::compact_len(val)
357	}
358}
359
360impl Encode for CompactRef<'_, u64> {
361	fn size_hint(&self) -> usize {
362		WrappedPrimitive(*self.0).size_hint()
363	}
364
365	fn encode_to<W: Output + ?Sized>(&self, dest: &mut W) {
366		WrappedPrimitive(*self.0).encode_to(dest)
367	}
368
369	fn using_encoded<R, F: FnOnce(&[u8]) -> R>(&self, f: F) -> R {
370		WrappedPrimitive(*self.0).using_encoded(f)
371	}
372}
373
374impl CompactLen<u64> for Compact<u64> {
375	fn compact_len(val: &u64) -> usize {
376		WrappedPrimitive::<u64>::compact_len(val)
377	}
378}
379
380impl Encode for CompactRef<'_, u128> {
381	fn size_hint(&self) -> usize {
382		Compact::<u128>::compact_len(self.0)
383	}
384
385	fn encode_to<W: Output + ?Sized>(&self, dest: &mut W) {
386		let l = (*self.0 & u64::MAX as u128) as u64;
387		let h = (*self.0 >> 64) as u64;
388		WrappedPrimitive::<u64>::encode_to(&WrappedPrimitive(l), dest);
389		WrappedPrimitive::<u64>::encode_to(&WrappedPrimitive(h), dest);
390	}
391}
392
393impl CompactLen<u128> for Compact<u128> {
394	fn compact_len(val: &u128) -> usize {
395		let l = (*val & u64::MAX as u128) as u64;
396		let h = (*val >> 64) as u64;
397		Compact::compact_len(&l) + Compact::compact_len(&h)
398	}
399}
400
401impl Decode for Compact<()> {
402	fn decode<I: Input>(_input: &mut I) -> Result<Self, Error> {
403		Ok(Compact(()))
404	}
405}
406
407impl DecodeWithMemTracking for Compact<()> {}
408
409impl Decode for Compact<u8> {
410	fn decode<I: Input>(input: &mut I) -> Result<Self, Error> {
411		WrappedPrimitive::<u8>::decode(input).map(|w| Compact(w.0))
412	}
413}
414
415impl DecodeWithMemTracking for Compact<u8> {}
416
417impl Decode for Compact<u16> {
418	fn decode<I: Input>(input: &mut I) -> Result<Self, Error> {
419		WrappedPrimitive::<u16>::decode(input).map(|w| Compact(w.0))
420	}
421}
422
423impl DecodeWithMemTracking for Compact<u16> {}
424
425impl Decode for Compact<u32> {
426	fn decode<I: Input>(input: &mut I) -> Result<Self, Error> {
427		WrappedPrimitive::<u32>::decode(input).map(|w| Compact(w.0))
428	}
429}
430
431impl DecodeWithMemTracking for Compact<u32> {}
432
433impl Decode for Compact<u64> {
434	fn decode<I: Input>(input: &mut I) -> Result<Self, Error> {
435		WrappedPrimitive::<u64>::decode(input).map(|w| Compact(w.0))
436	}
437}
438
439impl DecodeWithMemTracking for Compact<u64> {}
440
441impl Decode for Compact<u128> {
442	fn decode<I: Input>(input: &mut I) -> Result<Self, Error> {
443		let l = WrappedPrimitive::<u64>::decode(input).map(|w| Compact(w.0))?.0;
444		let h = WrappedPrimitive::<u64>::decode(input).map(|w| Compact(w.0))?.0;
445		Ok(Compact((h as u128) << 64 | l as u128))
446	}
447}
448
449impl DecodeWithMemTracking for Compact<u128> {}
450
451#[cfg(test)]
452mod tests {
453	use super::*;
454
455	#[test]
456	fn compact_128_encoding_works() {
457		let tests = [
458			(0u128, 2),
459			(63, 2),
460			(64, 2),
461			(16383, 3),
462			(16384, 4),
463			(1073741823, 6),
464			(1073741824, 6),
465			((1 << 32) - 1, 6),
466			(1 << 32, 6),
467			(1 << 40, 7), //10
468			(1 << 48, 8),
469			((1 << 56) - 1, 9),
470			(1 << 56, 10),
471			((1 << 64) - 1, 10),
472			(1 << 64, 2),
473			(1 << 72, 3),
474			(1 << 80, 4),
475			(1 << 88, 5),
476			(1 << 96, 6),
477			(1 << 104, 7), //20
478			(1 << 112, 8),
479			((1 << 120) - 1, 17),
480			(1 << 120, 10),
481			(u128::MAX, 18),
482		];
483		for &(n, l) in &tests {
484			let encoded = Compact(n).encode();
485			println!("{}", hex::encode(&encoded));
486			assert_eq!(encoded.len(), l);
487			assert_eq!(Compact::compact_len(&n), l);
488			assert_eq!(<Compact<u128>>::decode(&mut &encoded[..]).unwrap().0, n);
489		}
490	}
491
492	#[test]
493	fn compact_64_encoding_works() {
494		let tests = [
495			(0u64, 1usize),
496			(63, 1),
497			(64, 1),
498			(16383, 2),
499			(16384, 3),
500			(1073741823, 5),
501			(1073741824, 5),
502			((1 << 32) - 1, 5),
503			(1 << 32, 5),
504			(1 << 40, 6),
505			(1 << 48, 7),
506			((1 << 56) - 1, 8),
507			(1 << 56, 9),
508			(u64::MAX, 9),
509		];
510		for &(n, l) in &tests {
511			let encoded = Compact(n).encode();
512			assert_eq!(encoded.len(), l);
513			assert_eq!(Compact::compact_len(&n), l);
514			assert_eq!(<Compact<u64>>::decode(&mut &encoded[..]).unwrap().0, n);
515		}
516	}
517
518	#[test]
519	fn compact_32_encoding_works() {
520		let tests = [
521			(0u32, 1usize),
522			(63, 1),
523			(64, 1),
524			(16383, 2),
525			(16384, 3),
526			(1073741823, 5),
527			(1073741824, 5),
528			(u32::MAX, 5),
529		];
530		for &(n, l) in &tests {
531			let encoded = Compact(n).encode();
532			assert_eq!(encoded.len(), l);
533			assert_eq!(Compact::compact_len(&n), l);
534			assert_eq!(<Compact<u32>>::decode(&mut &encoded[..]).unwrap().0, n);
535		}
536	}
537
538	#[test]
539	fn compact_16_encoding_works() {
540		let tests = [(0u16, 1usize), (63, 1), (64, 1), (16383, 2), (16384, 3), (65535, 3)];
541		for &(n, l) in &tests {
542			let encoded = Compact(n).encode();
543			assert_eq!(encoded.len(), l);
544			assert_eq!(Compact::compact_len(&n), l);
545			assert_eq!(<Compact<u16>>::decode(&mut &encoded[..]).unwrap().0, n);
546		}
547		assert!(<Compact<u16>>::decode(&mut &Compact(65536u32).encode()[..]).is_err());
548	}
549
550	#[test]
551	fn compact_8_encoding_works() {
552		let tests = [(0u8, 1usize), (63, 1), (64, 1), (255, 2)];
553		for &(n, l) in &tests {
554			let encoded = Compact(n).encode();
555			assert_eq!(encoded.len(), l);
556			assert_eq!(Compact::compact_len(&n), l);
557			assert_eq!(<Compact<u8>>::decode(&mut &encoded[..]).unwrap().0, n);
558		}
559		assert!(<Compact<u8>>::decode(&mut &Compact(256u32).encode()[..]).is_err());
560	}
561
562	fn hexify(bytes: &[u8]) -> String {
563		bytes
564			.iter()
565			.map(|ref b| format!("{:02x}", b))
566			.collect::<Vec<String>>()
567			.join(" ")
568	}
569
570	#[test]
571	fn compact_integers_encoded_as_expected() {
572		let tests = [
573			(0u64, "00"),
574			(63, "3f"),
575			(64, "40"),
576			(16383, "bf ff"),
577			(16384, "c0 00 40"),
578			(1073741823, "f0 ff ff ff 3f"),
579			(1073741824, "f0 00 00 00 40"),
580			((1 << 32) - 1, "f0 ff ff ff ff"),
581			(1 << 32, "f1 00 00 00 00"),
582			(1 << 40, "f9 00 00 00 00 00"),
583			(1 << 48, "fd 00 00 00 00 00 00"),
584			((1 << 56) - 1, "fe ff ff ff ff ff ff ff"),
585			(1 << 56, "ff 00 00 00 00 00 00 00 01"),
586			(u64::MAX, "ff ff ff ff ff ff ff ff ff"),
587		];
588		for &(n, s) in &tests {
589			// Verify u64 encoding
590			let encoded = Compact(n).encode();
591			assert_eq!(hexify(&encoded), s);
592			assert_eq!(<Compact<u64>>::decode(&mut &encoded[..]).unwrap().0, n);
593
594			// Verify encodings for lower-size uints are compatible with u64 encoding
595			if n <= u32::MAX as u64 {
596				assert_eq!(<Compact<u32>>::decode(&mut &encoded[..]).unwrap().0, n as u32);
597				let encoded = Compact(n as u32).encode();
598				assert_eq!(hexify(&encoded), s);
599				assert_eq!(<Compact<u64>>::decode(&mut &encoded[..]).unwrap().0, n);
600			}
601			if n <= u16::MAX as u64 {
602				assert_eq!(<Compact<u16>>::decode(&mut &encoded[..]).unwrap().0, n as u16);
603				let encoded = Compact(n as u16).encode();
604				assert_eq!(hexify(&encoded), s);
605				assert_eq!(<Compact<u64>>::decode(&mut &encoded[..]).unwrap().0, n);
606			}
607			if n <= u8::MAX as u64 {
608				assert_eq!(<Compact<u8>>::decode(&mut &encoded[..]).unwrap().0, n as u8);
609				let encoded = Compact(n as u8).encode();
610				assert_eq!(hexify(&encoded), s);
611				assert_eq!(<Compact<u64>>::decode(&mut &encoded[..]).unwrap().0, n);
612			}
613		}
614	}
615
616	// JAM decoding is the inverse of the encoding, which writes each value in one form only. A
617	// longer form must fail, or one value has two encodings and two hashes.
618	#[test]
619	fn compact_decode_rejects_non_canonical_encodings() {
620		for extra_bytes in 1..=8 {
621			let prefix = u8::MAX << (8 - extra_bytes);
622			let encode_with_length = |value: u64| {
623				let mut bytes = vec![prefix];
624				bytes.extend_from_slice(&value.to_le_bytes()[..extra_bytes]);
625				bytes
626			};
627			let smallest_value = 1u64 << (7 * extra_bytes);
628			for value in [0, smallest_value - 1] {
629				assert!(<Compact<u64>>::decode(&mut &encode_with_length(value)[..]).is_err());
630			}
631			let canonical = encode_with_length(smallest_value);
632			assert_eq!(canonical, Compact(smallest_value).encode());
633			assert_eq!(<Compact<u64>>::decode(&mut &canonical[..]).unwrap().0, smallest_value);
634		}
635		assert!(<Vec<u8>>::decode(&mut &[0x80, 0x00][..]).is_err());
636	}
637
638	#[cfg_attr(feature = "std", derive(Serialize, Deserialize, Debug))]
639	#[derive(PartialEq, Eq, Clone)]
640	struct Wrapper(u8);
641
642	impl CompactAs for Wrapper {
643		type As = u8;
644		fn encode_as(&self) -> &u8 {
645			&self.0
646		}
647		fn decode_from(x: u8) -> Result<Wrapper, Error> {
648			Ok(Wrapper(x))
649		}
650	}
651
652	impl From<Compact<Wrapper>> for Wrapper {
653		fn from(x: Compact<Wrapper>) -> Wrapper {
654			x.0
655		}
656	}
657
658	#[test]
659	fn compact_as_8_encoding_works() {
660		let tests = [(0u8, 1usize), (63, 1), (64, 1), (255, 2)];
661		for &(n, l) in &tests {
662			let compact: Compact<Wrapper> = Wrapper(n).into();
663			let encoded = compact.encode();
664			assert_eq!(encoded.len(), l);
665			assert_eq!(Compact::compact_len(&n), l);
666			let decoded = <Compact<Wrapper>>::decode(&mut &encoded[..]).unwrap();
667			let wrapper: Wrapper = decoded.into();
668			assert_eq!(wrapper, Wrapper(n));
669		}
670	}
671
672	struct WithCompact<T: HasCompact> {
673		_data: T,
674	}
675
676	#[test]
677	fn compact_as_has_compact() {
678		let _data = WithCompact { _data: Wrapper(1) };
679	}
680
681	#[test]
682	fn compact_using_encoded_arrayvec_size() {
683		Compact(u8::MAX).using_encoded(|_| {});
684		Compact(u16::MAX).using_encoded(|_| {});
685		Compact(u32::MAX).using_encoded(|_| {});
686		Compact(u64::MAX).using_encoded(|_| {});
687		Compact(u128::MAX).using_encoded(|_| {});
688
689		CompactRef(&u8::MAX).using_encoded(|_| {});
690		CompactRef(&u16::MAX).using_encoded(|_| {});
691		CompactRef(&u32::MAX).using_encoded(|_| {});
692		CompactRef(&u64::MAX).using_encoded(|_| {});
693		CompactRef(&u128::MAX).using_encoded(|_| {});
694	}
695
696	#[test]
697	#[should_panic]
698	fn array_vec_output_oob() {
699		let mut v = ArrayVecWrapper(ArrayVec::<u8, 4>::new());
700		v.write(&[1, 2, 3, 4, 5]);
701	}
702
703	#[test]
704	fn array_vec_output() {
705		let mut v = ArrayVecWrapper(ArrayVec::<u8, 4>::new());
706		v.write(&[1, 2, 3, 4]);
707	}
708
709	#[test]
710	fn compact_u64_test() {
711		for a in [
712			u64::MAX,
713			u64::MAX - 1,
714			u64::MAX << 8,
715			(u64::MAX << 8) - 1,
716			u64::MAX << 16,
717			(u64::MAX << 16) - 1,
718		]
719		.iter()
720		{
721			let e = Compact::<u64>::encode(&Compact(*a));
722			let d = Compact::<u64>::decode(&mut &e[..]).unwrap().0;
723			assert_eq!(*a, d);
724		}
725	}
726
727	#[test]
728	fn compact_u128_test() {
729		for a in [u64::MAX as u128, (u64::MAX - 10) as u128, u128::MAX, u128::MAX - 10].iter() {
730			let e = Compact::<u128>::encode(&Compact(*a));
731			let d = Compact::<u128>::decode(&mut &e[..]).unwrap().0;
732			assert_eq!(*a, d);
733		}
734	}
735
736	macro_rules! quick_check_roundtrip {
737		( $( $ty:ty : $test:ident ),* ) => {
738			$(
739				quickcheck::quickcheck! {
740					fn $test(v: $ty) -> bool {
741						let encoded = Compact(v).encode();
742						let deencoded = <Compact<$ty>>::decode(&mut &encoded[..]).unwrap().0;
743
744						v == deencoded
745					}
746				}
747			)*
748		}
749	}
750
751	quick_check_roundtrip! {
752		u8: u8_roundtrip,
753		u16: u16_roundtrip,
754		u32 : u32_roundtrip,
755		u64 : u64_roundtrip,
756		u128 : u128_roundtrip
757	}
758}