bounded-vector 0.3.3

Vec wrapper that guarantees upper and lower bounds on type level.
Documentation
use crate::BoundedVec;
use core::fmt;
use serde::{
	de::{self, SeqAccess, Visitor},
	Deserialize, Deserializer, Serialize,
};
use std::marker::PhantomData;

impl<T: Serialize, const UPP: usize, const LOW: usize> Serialize for BoundedVec<T, LOW, UPP> {
	fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
	where
		S: serde::Serializer,
	{
		self.as_vec().serialize(serializer)
	}
}

impl<'de, T, const LOW: usize, const UPP: usize> Deserialize<'de> for BoundedVec<T, LOW, UPP>
where
	T: Deserialize<'de>,
{
	fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
	where
		D: Deserializer<'de>,
	{
		struct BoundedVecVisitor<T> {
			marker: PhantomData<T>,
		}

		impl<'de, T, const LOW: usize, const UPP: usize> Visitor<'de>
			for BoundedVecVisitor<(T, [(); LOW], [(); UPP])>
		where
			T: Deserialize<'de>,
		{
			type Value = BoundedVec<T, LOW, UPP>;

			fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
				write!(formatter, "a sequence with length between {LOW} and {UPP}")
			}

			fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
			where
				A: SeqAccess<'de, Error: >,
			{
				let size_hint = seq.size_hint();
				let capacity = size_hint_cautious::<T>(size_hint);
				let mut values = Vec::<T>::with_capacity(capacity.min(UPP));

				loop {
					match seq.next_element() {
						Ok(Some(_)) if values.len() == UPP => {
							return Err(de::Error::custom(format!(
								"a sequence length is larger than {UPP}"
							)))
						}
						Ok(Some(v)) => values.push(v),
						Ok(None) => break,
						Err(e) => return Err(e),
					}
				}

				values.try_into().map_err(|_| {
					de::Error::custom(format!("a sequence length is not between {LOW} and {UPP}"))
				})
			}
		}

		let visitor = BoundedVecVisitor {
			marker: PhantomData,
		};
		deserializer.deserialize_seq(visitor)
	}
}

pub fn size_hint_cautious<Element>(hint: Option<usize>) -> usize {
	const MAX_PREALLOC_BYTES: usize = 1024 * 1024;

	if size_of::<Element>() == 0 {
		0
	} else {
		hint.unwrap_or(0)
			.min(MAX_PREALLOC_BYTES / size_of::<Element>())
	}
}

#[cfg(test)]
mod tests {
	use super::*;
	use crate::bvec;
	use ron::{from_str, to_string};

	#[test]
	fn serialize() {
		let vec: BoundedVec<i32, 0, 10> = bvec![1, 2, 3];
		assert_eq!(to_string(&vec), Ok("[1,2,3]".to_owned()));
		let vec: BoundedVec<i32, 0, 10> = bvec![];
		assert_eq!(to_string(&vec), Ok("[]".to_owned()));
	}

	#[test]
	fn deserialize() {
		let vec: Result<BoundedVec<i32, 0, 3>, _> = from_str("[1,2,3]");
		assert_eq!(vec, Ok(bvec![1, 2, 3]));
	}

	#[test]
	fn deserialize_too_high() {
		let vec: Result<BoundedVec<i32, 0, 3>, _> = from_str("[1,2,3,4]");
		assert!(vec.is_err())
	}

	#[test]
	fn deserialize_too_low() {
		let vec: Result<BoundedVec<i32, 1, 3>, _> = from_str("[]");
		assert!(vec.is_err())
	}
}