Repository: paritytech/substrate
File: frame/support/src/storage/bounded_vec.rs (Rust)

Code before:
		// BoundedVec<T, S> encodes like Vec<T> which encodes like [T], which is a compact u32
		// plus each item in the slice:
		// https://docs.substrate.io/v3/advanced/scale-codec
		codec::Compact(S::get())
			.encoded_size()
			.saturating_add(Self::bound().saturating_mul(T::max_encoded_len()))
	}
}

/// Try and collect into a `BoundedVec` from an `ExactSizedIterator`.
///
/// This useful in preventing the undesirable `.collect::<Vec<_>>().try_into().unwrap()` syntax.
pub trait TryCollect<T> {
	type Error: sp_std::fmt::Debug;

	/// Try and collect `self` into a bounded vec of the given `Bound`.
	///
	/// The length of self must be known in advance (potentially by being an `ExactSizedIterator`),
	/// and if greater than `Bound`, then `Err` is returned.
	fn try_collect<Bound: Get<u32>>(self) -> Result<BoundedVec<T, Bound>, Self::Error>;
}

impl<I, T> TryCollect<T> for I
where
	I: ExactSizeIterator,
	I: Iterator<Item = T>,
{
	type Error = &'static str;

	fn try_collect<Bound: Get<u32>>(self) -> Result<BoundedVec<T, Bound>, Self::Error> {
		if self.len() > Bound::get() as usize {
			Err("iterator length too big")
		} else {
			Ok(BoundedVec::<T, Bound>::unchecked_from(self.collect::<Vec<T>>()))
		}
	}
}

#[cfg(test)]
pub mod test {
	use super::*;
	use crate::Twox128;
	use frame_support::traits::ConstU32;
	use sp_io::TestExternalities;

	crate::generate_storage_alias! { Prefix, Foo => Value<BoundedVec<u32, ConstU32<7>>> }
	crate::generate_storage_alias! { Prefix, FooMap => Map<(u32, Twox128), BoundedVec<u32, ConstU32<7>>> }
	crate::generate_storage_alias! {
		Prefix,
		FooDoubleMap => DoubleMap<(u32, Twox128), (u32, Twox128), BoundedVec<u32, ConstU32<7>>>
	}

Review comment (suggestion):
```suggestion
	I: ExactSizeIterator + Iterator<Item = T>,
```

Code after:
		// BoundedVec<T, S> encodes like Vec<T> which encodes like [T], which is a compact u32
		// plus each item in the slice:
		// https://docs.substrate.io/v3/advanced/scale-codec
		codec::Compact(S::get())
			.encoded_size()
			.saturating_add(Self::bound().saturating_mul(T::max_encoded_len()))
	}
}

impl<I, T, Bound> TryCollect<BoundedVec<T, Bound>> for I
where
	I: ExactSizeIterator + Iterator<Item = T>,
	Bound: Get<u32>,
{
	type Error = &'static str;

	fn try_collect(self) -> Result<BoundedVec<T, Bound>, Self::Error> {
		if self.len() > Bound::get() as usize {
			Err("iterator length too big")
		} else {
			Ok(BoundedVec::<T, Bound>::unchecked_from(self.collect::<Vec<T>>()))
		}
	}
}

#[cfg(test)]
pub mod test {
	use super::*;
	use crate::Twox128;
	use frame_support::traits::ConstU32;
	use sp_io::TestExternalities;

	crate::generate_storage_alias! { Prefix, Foo => Value<BoundedVec<u32, ConstU32<7>>> }
	crate::generate_storage_alias! { Prefix, FooMap => Map<(u32, Twox128), BoundedVec<u32, ConstU32<7>>> }
	crate::generate_storage_alias! {
		Prefix,
		FooDoubleMap => DoubleMap<(u32, Twox128), (u32, Twox128), BoundedVec<u32, ConstU32<7>>>
	}

	#[test]
	fn try_append_is_correct() {
		assert_eq!(BoundedVec::<u32, ConstU32<7>>::bound(), 7);
	}

	#[test]
	fn decode_len_works() {
		TestExternalities::default().execute_with(|| {
			let bounded: BoundedVec<u32, ConstU32<7>> = vec![1, 2, 3].try_into().unwrap();
			Foo::put(bounded);
			assert_eq!(Foo::decode_len().unwrap(), 3);
		});