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
245impl<T> CompactLen<T> for WrappedPrimitive<T>
246where
247	T: Copy + Into<u64>,
248{
249	fn compact_len(val: &T) -> usize {
250		let x = (*val).into();
251		1 + if x == 0 {
252			0
253		} else {
254			(0..8)
255				.find(|l| 2_u64.pow(7 * l) <= x && x < 2_u64.pow(7 * (l + 1)))
256				.unwrap_or(8)
257		} as usize
258	}
259}
260
261impl<T> Encode for WrappedPrimitive<T>
262where
263	T: Copy + Into<u64>,
264{
265	fn size_hint(&self) -> usize {
266		Self::compact_len(&self.0)
267	}
268
269	fn encode_to<W: Output + ?Sized>(&self, dest: &mut W) {
270		let x = self.0.into();
271		if x == 0 {
272			dest.push_byte(0);
273		} else if let Some(l) = (0..8).find(|l| 2_u64.pow(7 * l) <= x && x < 2_u64.pow(7 * (l + 1)))
274		{
275			dest.push_byte((2_u64.pow(8) - 2_u64.pow(8 - l) + (x / 2_u64.pow(8 * l))) as u8);
276			dest.write(&(x % 2_u64.pow(8 * l)).to_le_bytes()[..l as usize]);
277		} else {
278			dest.push_byte((2_u64.pow(8) - 1) as u8);
279			dest.write(&x.to_le_bytes());
280		}
281	}
282
283	fn using_encoded<R, F: FnOnce(&[u8]) -> R>(&self, f: F) -> R {
284		let mut r = ArrayVecWrapper(ArrayVec::<u8, 9>::new());
285		self.encode_to(&mut r);
286		f(&r.0)
287	}
288}
289
290impl<T> Decode for WrappedPrimitive<T>
291where
292	T: Copy + TryFrom<u64>,
293{
294	fn decode<I: Input>(input: &mut I) -> Result<Self, Error> {
295		const OUT_OF_RANGE: &str = "Out of range";
296		let v = match input.read_byte()? {
297			0 => 0,
298			0xff => u64::decode(input)?,
299			b => {
300				let l = (0..8).find(|&i| (b & (0b1000_0000 >> i)) == 0).unwrap();
301				let mut buf = [0u8; 8];
302				input.read(&mut buf[..l])?;
303				let rem = (b & ((1 << (7 - l)) - 1)) as u64;
304				u64::from_le_bytes(buf) + (rem << (8 * l))
305			},
306		};
307		let v = T::try_from(v).map_err(|_| Error::from(OUT_OF_RANGE))?;
308		Ok(Self(v))
309	}
310}
311
312impl Encode for CompactRef<'_, u8> {
313	fn size_hint(&self) -> usize {
314		WrappedPrimitive(*self.0).size_hint()
315	}
316
317	fn encode_to<W: Output + ?Sized>(&self, dest: &mut W) {
318		WrappedPrimitive(*self.0).encode_to(dest)
319	}
320
321	fn using_encoded<R, F: FnOnce(&[u8]) -> R>(&self, f: F) -> R {
322		WrappedPrimitive(*self.0).using_encoded(f)
323	}
324}
325
326impl CompactLen<u8> for Compact<u8> {
327	fn compact_len(val: &u8) -> usize {
328		WrappedPrimitive::<u8>::compact_len(val)
329	}
330}
331
332impl Encode for CompactRef<'_, u16> {
333	fn size_hint(&self) -> usize {
334		WrappedPrimitive(*self.0).size_hint()
335	}
336
337	fn encode_to<W: Output + ?Sized>(&self, dest: &mut W) {
338		WrappedPrimitive(*self.0).encode_to(dest)
339	}
340
341	fn using_encoded<R, F: FnOnce(&[u8]) -> R>(&self, f: F) -> R {
342		WrappedPrimitive(*self.0).using_encoded(f)
343	}
344}
345
346impl CompactLen<u16> for Compact<u16> {
347	fn compact_len(val: &u16) -> usize {
348		WrappedPrimitive::<u16>::compact_len(val)
349	}
350}
351
352impl Encode for CompactRef<'_, u32> {
353	fn size_hint(&self) -> usize {
354		WrappedPrimitive(*self.0).size_hint()
355	}
356
357	fn encode_to<W: Output + ?Sized>(&self, dest: &mut W) {
358		WrappedPrimitive(*self.0).encode_to(dest)
359	}
360
361	fn using_encoded<R, F: FnOnce(&[u8]) -> R>(&self, f: F) -> R {
362		WrappedPrimitive(*self.0).using_encoded(f)
363	}
364}
365
366impl CompactLen<u32> for Compact<u32> {
367	fn compact_len(val: &u32) -> usize {
368		WrappedPrimitive::<u32>::compact_len(val)
369	}
370}
371
372impl Encode for CompactRef<'_, u64> {
373	fn size_hint(&self) -> usize {
374		WrappedPrimitive(*self.0).size_hint()
375	}
376
377	fn encode_to<W: Output + ?Sized>(&self, dest: &mut W) {
378		WrappedPrimitive(*self.0).encode_to(dest)
379	}
380
381	fn using_encoded<R, F: FnOnce(&[u8]) -> R>(&self, f: F) -> R {
382		WrappedPrimitive(*self.0).using_encoded(f)
383	}
384}
385
386impl CompactLen<u64> for Compact<u64> {
387	fn compact_len(val: &u64) -> usize {
388		WrappedPrimitive::<u64>::compact_len(val)
389	}
390}
391
392impl Encode for CompactRef<'_, u128> {
393	fn size_hint(&self) -> usize {
394		Compact::<u128>::compact_len(self.0)
395	}
396
397	fn encode_to<W: Output + ?Sized>(&self, dest: &mut W) {
398		let l = (*self.0 & u64::MAX as u128) as u64;
399		let h = (*self.0 >> 64) as u64;
400		WrappedPrimitive::<u64>::encode_to(&WrappedPrimitive(l), dest);
401		WrappedPrimitive::<u64>::encode_to(&WrappedPrimitive(h), dest);
402	}
403}
404
405impl CompactLen<u128> for Compact<u128> {
406	fn compact_len(val: &u128) -> usize {
407		let l = (*val & u64::MAX as u128) as u64;
408		let h = (*val >> 64) as u64;
409		Compact::compact_len(&l) + Compact::compact_len(&h)
410	}
411}
412
413impl Decode for Compact<()> {
414	fn decode<I: Input>(_input: &mut I) -> Result<Self, Error> {
415		Ok(Compact(()))
416	}
417}
418
419impl DecodeWithMemTracking for Compact<()> {}
420
421impl Decode for Compact<u8> {
422	fn decode<I: Input>(input: &mut I) -> Result<Self, Error> {
423		WrappedPrimitive::<u8>::decode(input).map(|w| Compact(w.0))
424	}
425}
426
427impl DecodeWithMemTracking for Compact<u8> {}
428
429impl Decode for Compact<u16> {
430	fn decode<I: Input>(input: &mut I) -> Result<Self, Error> {
431		WrappedPrimitive::<u16>::decode(input).map(|w| Compact(w.0))
432	}
433}
434
435impl DecodeWithMemTracking for Compact<u16> {}
436
437impl Decode for Compact<u32> {
438	fn decode<I: Input>(input: &mut I) -> Result<Self, Error> {
439		WrappedPrimitive::<u32>::decode(input).map(|w| Compact(w.0))
440	}
441}
442
443impl DecodeWithMemTracking for Compact<u32> {}
444
445impl Decode for Compact<u64> {
446	fn decode<I: Input>(input: &mut I) -> Result<Self, Error> {
447		WrappedPrimitive::<u64>::decode(input).map(|w| Compact(w.0))
448	}
449}
450
451impl DecodeWithMemTracking for Compact<u64> {}
452
453impl Decode for Compact<u128> {
454	fn decode<I: Input>(input: &mut I) -> Result<Self, Error> {
455		let l = WrappedPrimitive::<u64>::decode(input).map(|w| Compact(w.0))?.0;
456		let h = WrappedPrimitive::<u64>::decode(input).map(|w| Compact(w.0))?.0;
457		Ok(Compact((h as u128) << 64 | l as u128))
458	}
459}
460
461impl DecodeWithMemTracking for Compact<u128> {}
462
463#[cfg(test)]
464mod tests {
465	use super::*;
466
467	#[test]
468	fn compact_128_encoding_works() {
469		let tests = [
470			(0u128, 2),
471			(63, 2),
472			(64, 2),
473			(16383, 3),
474			(16384, 4),
475			(1073741823, 6),
476			(1073741824, 6),
477			((1 << 32) - 1, 6),
478			(1 << 32, 6),
479			(1 << 40, 7), //10
480			(1 << 48, 8),
481			((1 << 56) - 1, 9),
482			(1 << 56, 10),
483			((1 << 64) - 1, 10),
484			(1 << 64, 2),
485			(1 << 72, 3),
486			(1 << 80, 4),
487			(1 << 88, 5),
488			(1 << 96, 6),
489			(1 << 104, 7), //20
490			(1 << 112, 8),
491			((1 << 120) - 1, 17),
492			(1 << 120, 10),
493			(u128::MAX, 18),
494		];
495		for &(n, l) in &tests {
496			let encoded = Compact(n).encode();
497			println!("{}", hex::encode(&encoded));
498			assert_eq!(encoded.len(), l);
499			assert_eq!(Compact::compact_len(&n), l);
500			assert_eq!(<Compact<u128>>::decode(&mut &encoded[..]).unwrap().0, n);
501		}
502	}
503
504	#[test]
505	fn compact_64_encoding_works() {
506		let tests = [
507			(0u64, 1usize),
508			(63, 1),
509			(64, 1),
510			(16383, 2),
511			(16384, 3),
512			(1073741823, 5),
513			(1073741824, 5),
514			((1 << 32) - 1, 5),
515			(1 << 32, 5),
516			(1 << 40, 6),
517			(1 << 48, 7),
518			((1 << 56) - 1, 8),
519			(1 << 56, 9),
520			(u64::MAX, 9),
521		];
522		for &(n, l) in &tests {
523			let encoded = Compact(n).encode();
524			assert_eq!(encoded.len(), l);
525			assert_eq!(Compact::compact_len(&n), l);
526			assert_eq!(<Compact<u64>>::decode(&mut &encoded[..]).unwrap().0, n);
527		}
528	}
529
530	#[test]
531	fn compact_32_encoding_works() {
532		let tests = [
533			(0u32, 1usize),
534			(63, 1),
535			(64, 1),
536			(16383, 2),
537			(16384, 3),
538			(1073741823, 5),
539			(1073741824, 5),
540			(u32::MAX, 5),
541		];
542		for &(n, l) in &tests {
543			let encoded = Compact(n).encode();
544			assert_eq!(encoded.len(), l);
545			assert_eq!(Compact::compact_len(&n), l);
546			assert_eq!(<Compact<u32>>::decode(&mut &encoded[..]).unwrap().0, n);
547		}
548	}
549
550	#[test]
551	fn compact_16_encoding_works() {
552		let tests = [(0u16, 1usize), (63, 1), (64, 1), (16383, 2), (16384, 3), (65535, 3)];
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<u16>>::decode(&mut &encoded[..]).unwrap().0, n);
558		}
559		assert!(<Compact<u16>>::decode(&mut &Compact(65536u32).encode()[..]).is_err());
560	}
561
562	#[test]
563	fn compact_8_encoding_works() {
564		let tests = [(0u8, 1usize), (63, 1), (64, 1), (255, 2)];
565		for &(n, l) in &tests {
566			let encoded = Compact(n).encode();
567			assert_eq!(encoded.len(), l);
568			assert_eq!(Compact::compact_len(&n), l);
569			assert_eq!(<Compact<u8>>::decode(&mut &encoded[..]).unwrap().0, n);
570		}
571		assert!(<Compact<u8>>::decode(&mut &Compact(256u32).encode()[..]).is_err());
572	}
573
574	fn hexify(bytes: &[u8]) -> String {
575		bytes
576			.iter()
577			.map(|ref b| format!("{:02x}", b))
578			.collect::<Vec<String>>()
579			.join(" ")
580	}
581
582	#[test]
583	fn compact_integers_encoded_as_expected() {
584		let tests = [
585			(0u64, "00"),
586			(63, "3f"),
587			(64, "40"),
588			(16383, "bf ff"),
589			(16384, "c0 00 40"),
590			(1073741823, "f0 ff ff ff 3f"),
591			(1073741824, "f0 00 00 00 40"),
592			((1 << 32) - 1, "f0 ff ff ff ff"),
593			(1 << 32, "f1 00 00 00 00"),
594			(1 << 40, "f9 00 00 00 00 00"),
595			(1 << 48, "fd 00 00 00 00 00 00"),
596			((1 << 56) - 1, "fe ff ff ff ff ff ff ff"),
597			(1 << 56, "ff 00 00 00 00 00 00 00 01"),
598			(u64::MAX, "ff ff ff ff ff ff ff ff ff"),
599		];
600		for &(n, s) in &tests {
601			// Verify u64 encoding
602			let encoded = Compact(n).encode();
603			assert_eq!(hexify(&encoded), s);
604			assert_eq!(<Compact<u64>>::decode(&mut &encoded[..]).unwrap().0, n);
605
606			// Verify encodings for lower-size uints are compatible with u64 encoding
607			if n <= u32::MAX as u64 {
608				assert_eq!(<Compact<u32>>::decode(&mut &encoded[..]).unwrap().0, n as u32);
609				let encoded = Compact(n as u32).encode();
610				assert_eq!(hexify(&encoded), s);
611				assert_eq!(<Compact<u64>>::decode(&mut &encoded[..]).unwrap().0, n);
612			}
613			if n <= u16::MAX as u64 {
614				assert_eq!(<Compact<u16>>::decode(&mut &encoded[..]).unwrap().0, n as u16);
615				let encoded = Compact(n as u16).encode();
616				assert_eq!(hexify(&encoded), s);
617				assert_eq!(<Compact<u64>>::decode(&mut &encoded[..]).unwrap().0, n);
618			}
619			if n <= u8::MAX as u64 {
620				assert_eq!(<Compact<u8>>::decode(&mut &encoded[..]).unwrap().0, n as u8);
621				let encoded = Compact(n as u8).encode();
622				assert_eq!(hexify(&encoded), s);
623				assert_eq!(<Compact<u64>>::decode(&mut &encoded[..]).unwrap().0, n);
624			}
625		}
626	}
627
628	#[cfg_attr(feature = "std", derive(Serialize, Deserialize, Debug))]
629	#[derive(PartialEq, Eq, Clone)]
630	struct Wrapper(u8);
631
632	impl CompactAs for Wrapper {
633		type As = u8;
634		fn encode_as(&self) -> &u8 {
635			&self.0
636		}
637		fn decode_from(x: u8) -> Result<Wrapper, Error> {
638			Ok(Wrapper(x))
639		}
640	}
641
642	impl From<Compact<Wrapper>> for Wrapper {
643		fn from(x: Compact<Wrapper>) -> Wrapper {
644			x.0
645		}
646	}
647
648	#[test]
649	fn compact_as_8_encoding_works() {
650		let tests = [(0u8, 1usize), (63, 1), (64, 1), (255, 2)];
651		for &(n, l) in &tests {
652			let compact: Compact<Wrapper> = Wrapper(n).into();
653			let encoded = compact.encode();
654			assert_eq!(encoded.len(), l);
655			assert_eq!(Compact::compact_len(&n), l);
656			let decoded = <Compact<Wrapper>>::decode(&mut &encoded[..]).unwrap();
657			let wrapper: Wrapper = decoded.into();
658			assert_eq!(wrapper, Wrapper(n));
659		}
660	}
661
662	struct WithCompact<T: HasCompact> {
663		_data: T,
664	}
665
666	#[test]
667	fn compact_as_has_compact() {
668		let _data = WithCompact { _data: Wrapper(1) };
669	}
670
671	#[test]
672	fn compact_using_encoded_arrayvec_size() {
673		Compact(u8::MAX).using_encoded(|_| {});
674		Compact(u16::MAX).using_encoded(|_| {});
675		Compact(u32::MAX).using_encoded(|_| {});
676		Compact(u64::MAX).using_encoded(|_| {});
677		Compact(u128::MAX).using_encoded(|_| {});
678
679		CompactRef(&u8::MAX).using_encoded(|_| {});
680		CompactRef(&u16::MAX).using_encoded(|_| {});
681		CompactRef(&u32::MAX).using_encoded(|_| {});
682		CompactRef(&u64::MAX).using_encoded(|_| {});
683		CompactRef(&u128::MAX).using_encoded(|_| {});
684	}
685
686	#[test]
687	#[should_panic]
688	fn array_vec_output_oob() {
689		let mut v = ArrayVecWrapper(ArrayVec::<u8, 4>::new());
690		v.write(&[1, 2, 3, 4, 5]);
691	}
692
693	#[test]
694	fn array_vec_output() {
695		let mut v = ArrayVecWrapper(ArrayVec::<u8, 4>::new());
696		v.write(&[1, 2, 3, 4]);
697	}
698
699	#[test]
700	fn compact_u64_test() {
701		for a in [
702			u64::MAX,
703			u64::MAX - 1,
704			u64::MAX << 8,
705			(u64::MAX << 8) - 1,
706			u64::MAX << 16,
707			(u64::MAX << 16) - 1,
708		]
709		.iter()
710		{
711			let e = Compact::<u64>::encode(&Compact(*a));
712			let d = Compact::<u64>::decode(&mut &e[..]).unwrap().0;
713			assert_eq!(*a, d);
714		}
715	}
716
717	#[test]
718	fn compact_u128_test() {
719		for a in [u64::MAX as u128, (u64::MAX - 10) as u128, u128::MAX, u128::MAX - 10].iter() {
720			let e = Compact::<u128>::encode(&Compact(*a));
721			let d = Compact::<u128>::decode(&mut &e[..]).unwrap().0;
722			assert_eq!(*a, d);
723		}
724	}
725
726	macro_rules! quick_check_roundtrip {
727		( $( $ty:ty : $test:ident ),* ) => {
728			$(
729				quickcheck::quickcheck! {
730					fn $test(v: $ty) -> bool {
731						let encoded = Compact(v).encode();
732						let deencoded = <Compact<$ty>>::decode(&mut &encoded[..]).unwrap().0;
733
734						v == deencoded
735					}
736				}
737			)*
738		}
739	}
740
741	quick_check_roundtrip! {
742		u8: u8_roundtrip,
743		u16: u16_roundtrip,
744		u32 : u32_roundtrip,
745		u64 : u64_roundtrip,
746		u128 : u128_roundtrip
747	}
748}