1use alloc::vec;
2use alloc::vec::Vec;
3use core::convert::{TryFrom, TryInto};
4use core::slice::{Iter, IterMut};
5use thiserror::Error;
6
7#[derive(PartialEq, Eq, Debug, Clone, Hash, PartialOrd, Ord)]
13pub struct BoundedVec<T, const L: usize, const U: usize, W = witnesses::NonEmpty<L, U>> {
14 inner: Vec<T>,
15 witness: W,
16}
17
18#[derive(Error, PartialEq, Eq, Debug, Clone)]
20pub enum BoundedVecOutOfBounds {
21 #[error("Lower bound violation: got {got} (expected >= {lower_bound})")]
23 LowerBoundError {
24 lower_bound: usize,
26 got: usize,
28 },
29 #[error("Upper bound violation: got {got} (expected <= {upper_bound})")]
31 UpperBoundError {
32 upper_bound: usize,
34 got: usize,
36 },
37}
38
39pub mod witnesses {
41
42 #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
46 pub struct NonEmpty<const L: usize, const U: usize>(());
47
48 #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
50 pub struct Empty<const U: usize>(());
51
52 pub const fn non_empty<const L: usize, const U: usize>() -> NonEmpty<L, U> {
54 const {
55 if L == 0 {
56 panic!("L must be greater than 0")
57 }
58 if L > U {
59 panic!("L must be less than or equal to U")
60 }
61
62 NonEmpty::<L, U>(())
63 }
64 }
65
66 pub const fn empty<const U: usize>() -> Empty<U> {
68 const { Empty::<U>(()) }
69 }
70}
71
72impl<T, const U: usize> BoundedVec<T, 0, U, witnesses::Empty<U>> {
73 pub fn from_vec(items: Vec<T>) -> Result<Self, BoundedVecOutOfBounds> {
91 let witness = witnesses::empty::<U>();
92 let len = items.len();
93 if len > U {
94 Err(BoundedVecOutOfBounds::UpperBoundError {
95 upper_bound: U,
96 got: len,
97 })
98 } else {
99 Ok(BoundedVec {
100 inner: items,
101 witness,
102 })
103 }
104 }
105
106 pub fn first(&self) -> Option<&T> {
118 self.inner.first()
119 }
120
121 pub fn is_empty(&self) -> bool {
133 self.inner.is_empty()
134 }
135
136 pub fn last(&self) -> Option<&T> {
148 self.inner.last()
149 }
150}
151
152impl<T, const L: usize, const U: usize, W> BoundedVec<T, L, U, W> {
154 pub fn as_vec(&self) -> &Vec<T> {
165 &self.inner
166 }
167
168 pub fn to_vec(self) -> Vec<T> {
179 self.inner
180 }
181
182 pub fn as_slice(&self) -> &[T] {
193 self.inner.as_slice()
194 }
195
196 pub fn get(&self, index: usize) -> Option<&T> {
207 self.inner.get(index)
208 }
209
210 pub fn iter(&self) -> Iter<T> {
212 self.inner.iter()
213 }
214
215 pub fn iter_mut(&mut self) -> IterMut<T> {
217 self.inner.iter_mut()
218 }
219}
220
221impl<T, const L: usize, const U: usize> BoundedVec<T, L, U, witnesses::NonEmpty<L, U>> {
222 pub fn from_vec(items: Vec<T>) -> Result<Self, BoundedVecOutOfBounds> {
241 let witness = witnesses::non_empty::<L, U>();
242 let len = items.len();
243 if len < L {
244 Err(BoundedVecOutOfBounds::LowerBoundError {
245 lower_bound: L,
246 got: len,
247 })
248 } else if len > U {
249 Err(BoundedVecOutOfBounds::UpperBoundError {
250 upper_bound: U,
251 got: len,
252 })
253 } else {
254 Ok(BoundedVec {
255 inner: items,
256 witness,
257 })
258 }
259 }
260
261 pub fn len(&self) -> usize {
272 self.inner.len()
273 }
274
275 pub fn first(&self) -> &T {
286 #[allow(clippy::unwrap_used)]
287 self.inner.first().unwrap()
288 }
289
290 pub fn last(&self) -> &T {
301 #[allow(clippy::unwrap_used)]
302 self.inner.last().unwrap()
303 }
304
305 pub fn mapped<F, N>(self, map_fn: F) -> BoundedVec<N, L, U, witnesses::NonEmpty<L, U>>
319 where
320 F: FnMut(T) -> N,
321 {
322 BoundedVec {
323 inner: self.inner.into_iter().map(map_fn).collect::<Vec<_>>(),
324 witness: self.witness,
325 }
326 }
327
328 pub fn mapped_ref<F, N>(&self, map_fn: F) -> BoundedVec<N, L, U, witnesses::NonEmpty<L, U>>
342 where
343 F: FnMut(&T) -> N,
344 {
345 BoundedVec {
346 inner: self.inner.iter().map(map_fn).collect::<Vec<_>>(),
347 witness: self.witness,
348 }
349 }
350
351 pub fn try_mapped<F, N, E>(
377 self,
378 map_fn: F,
379 ) -> Result<BoundedVec<N, L, U, witnesses::NonEmpty<L, U>>, E>
380 where
381 F: FnMut(T) -> Result<N, E>,
382 {
383 let mut map_fn = map_fn;
384 let mut out = Vec::with_capacity(self.len());
385 for element in self.inner.into_iter() {
386 out.push(map_fn(element)?);
387 }
388 #[allow(clippy::unwrap_used)]
389 Ok(BoundedVec::<N, L, U, witnesses::NonEmpty<L, U>>::from_vec(out).unwrap())
390 }
391
392 pub fn try_mapped_ref<F, N, E>(
412 &self,
413 map_fn: F,
414 ) -> Result<BoundedVec<N, L, U, witnesses::NonEmpty<L, U>>, E>
415 where
416 F: FnMut(&T) -> Result<N, E>,
417 {
418 let mut map_fn = map_fn;
419 let mut out = Vec::with_capacity(self.len());
420 for element in self.inner.iter() {
421 out.push(map_fn(element)?);
422 }
423 #[allow(clippy::unwrap_used)]
424 Ok(BoundedVec::<N, L, U, witnesses::NonEmpty<L, U>>::from_vec(out).unwrap())
425 }
426
427 pub fn split_last(&self) -> (&T, &[T]) {
429 #[allow(clippy::unwrap_used)]
430 self.inner.split_last().unwrap()
431 }
432
433 pub fn enumerated(self) -> BoundedVec<(usize, T), L, U, witnesses::NonEmpty<L, U>> {
435 #[allow(clippy::unwrap_used)]
436 self.inner
437 .into_iter()
438 .enumerate()
439 .collect::<Vec<(usize, T)>>()
440 .try_into()
441 .unwrap()
442 }
443
444 pub fn opt_empty_vec(
458 v: Vec<T>,
459 ) -> Result<Option<BoundedVec<T, L, U, witnesses::NonEmpty<L, U>>>, BoundedVecOutOfBounds> {
460 if v.is_empty() {
461 Ok(None)
462 } else {
463 Ok(Some(Self::from_vec(v)?))
464 }
465 }
466}
467
468pub type NonEmptyVec<T> = BoundedVec<T, 1, { usize::MAX }, witnesses::NonEmpty<1, { usize::MAX }>>;
470
471pub type EmptyBoundedVec<T, const U: usize> = BoundedVec<T, 0, U, witnesses::Empty<U>>;
473
474pub type NonEmptyBoundedVec<T, const L: usize, const U: usize> =
476 BoundedVec<T, L, U, witnesses::NonEmpty<L, U>>;
477
478impl<T, const L: usize, const U: usize> TryFrom<Vec<T>>
479 for BoundedVec<T, L, U, witnesses::NonEmpty<L, U>>
480{
481 type Error = BoundedVecOutOfBounds;
482
483 fn try_from(value: Vec<T>) -> Result<Self, Self::Error> {
484 Self::from_vec(value)
485 }
486}
487
488impl<T, const U: usize> TryFrom<Vec<T>> for BoundedVec<T, 0, U, witnesses::Empty<U>> {
489 type Error = BoundedVecOutOfBounds;
490
491 fn try_from(value: Vec<T>) -> Result<Self, Self::Error> {
492 Self::from_vec(value)
493 }
494}
495
496impl<T, const L: usize, const U: usize> From<[T; L]>
498 for BoundedVec<T, L, U, witnesses::NonEmpty<L, U>>
499{
500 fn from(arr: [T; L]) -> Self {
501 BoundedVec {
502 inner: arr.into(),
503 witness: witnesses::non_empty(),
504 }
505 }
506}
507
508impl<T, const L: usize, const U: usize> From<BoundedVec<T, L, U, witnesses::NonEmpty<L, U>>>
509 for Vec<T>
510{
511 fn from(v: BoundedVec<T, L, U, witnesses::NonEmpty<L, U>>) -> Self {
512 v.inner
513 }
514}
515
516impl<T, const L: usize, const U: usize, W> IntoIterator for BoundedVec<T, L, U, W> {
517 type Item = T;
518 type IntoIter = vec::IntoIter<T>;
519
520 fn into_iter(self) -> Self::IntoIter {
521 self.inner.into_iter()
522 }
523}
524
525impl<'a, T, const L: usize, const U: usize, W> IntoIterator for &'a BoundedVec<T, L, U, W> {
526 type Item = &'a T;
527 type IntoIter = core::slice::Iter<'a, T>;
528
529 fn into_iter(self) -> Self::IntoIter {
530 self.inner.iter()
531 }
532}
533
534impl<'a, T, const L: usize, const U: usize, W> IntoIterator for &'a mut BoundedVec<T, L, U, W> {
535 type Item = &'a mut T;
536 type IntoIter = core::slice::IterMut<'a, T>;
537
538 fn into_iter(self) -> Self::IntoIter {
539 self.inner.iter_mut()
540 }
541}
542
543impl<T, const L: usize, const U: usize, W> AsRef<Vec<T>> for BoundedVec<T, L, U, W> {
544 fn as_ref(&self) -> &Vec<T> {
545 &self.inner
546 }
547}
548
549impl<T, const L: usize, const U: usize, W> AsRef<[T]> for BoundedVec<T, L, U, W> {
550 fn as_ref(&self) -> &[T] {
551 self.inner.as_ref()
552 }
553}
554
555impl<T, const L: usize, const U: usize, W> AsMut<Vec<T>> for BoundedVec<T, L, U, W> {
556 fn as_mut(&mut self) -> &mut Vec<T> {
557 self.inner.as_mut()
558 }
559}
560
561impl<T, const L: usize, const U: usize, W> AsMut<[T]> for BoundedVec<T, L, U, W> {
562 fn as_mut(&mut self) -> &mut [T] {
563 self.inner.as_mut()
564 }
565}
566
567pub trait OptBoundedVecToVec<T> {
569 fn to_vec(self) -> Vec<T>;
571}
572
573impl<T, const L: usize, const U: usize> OptBoundedVecToVec<T>
574 for Option<BoundedVec<T, L, U, witnesses::NonEmpty<L, U>>>
575{
576 fn to_vec(self) -> Vec<T> {
577 self.map(|bv| bv.into()).unwrap_or_default()
578 }
579}
580
581#[allow(clippy::unwrap_used)]
582#[cfg(feature = "arbitrary")]
583mod arbitrary {
584
585 use super::*;
586 use proptest::collection::vec;
587 use proptest::prelude::Arbitrary;
588 use proptest::prelude::*;
589 use proptest::strategy::BoxedStrategy;
590
591 impl<T: Arbitrary, const L: usize, const U: usize> Arbitrary
592 for BoundedVec<T, L, U, witnesses::NonEmpty<L, U>>
593 where
594 T::Strategy: 'static,
595 {
596 type Strategy = BoxedStrategy<Self>;
597 type Parameters = ();
598
599 fn arbitrary_with(_args: Self::Parameters) -> Self::Strategy {
600 vec(any::<T>(), L..=U)
601 .prop_map(|items| Self::from_vec(items).unwrap())
602 .boxed()
603 }
604 }
605}
606
607#[cfg(feature = "serde")]
608mod serde_impl {
609 use super::*;
610 use serde::{Deserialize, Serialize};
611
612 impl<T: Serialize, const L: usize, const U: usize, W> Serialize for BoundedVec<T, L, U, W> {
614 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
615 where
616 S: serde::Serializer,
617 {
618 self.inner.serialize(serializer)
619 }
620 }
621
622 impl<'de, T: Deserialize<'de>, const L: usize, const U: usize> Deserialize<'de>
623 for BoundedVec<T, L, U>
624 {
625 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
626 where
627 D: serde::Deserializer<'de>,
628 {
629 let inner = Vec::<T>::deserialize(deserializer)?;
630 BoundedVec::<T, L, U>::from_vec(inner).map_err(serde::de::Error::custom)
631 }
632 }
633
634 impl<'de, T: Deserialize<'de>, const U: usize> Deserialize<'de> for EmptyBoundedVec<T, U> {
635 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
636 where
637 D: serde::Deserializer<'de>,
638 {
639 let inner = Vec::<T>::deserialize(deserializer)?;
640 EmptyBoundedVec::from_vec(inner).map_err(serde::de::Error::custom)
641 }
642 }
643
644 #[cfg(feature = "schema")]
645 mod schema {
646 use super::*;
647 use alloc::borrow::Cow;
648 use schemars::JsonSchema;
649
650 impl<T: JsonSchema, const L: usize, const U: usize, W> JsonSchema for BoundedVec<T, L, U, W> {
652 fn schema_name() -> Cow<'static, str> {
653 alloc::format!("BoundedVec{}Min{}Max{}", T::schema_name(), L, U).into()
654 }
655
656 fn json_schema(gen: &mut schemars::SchemaGenerator) -> schemars::Schema {
657 schemars::json_schema!({
658 "type": "array",
659 "items": T::json_schema(gen),
660 "minItems": L as u32,
661 "maxItems": U as u32
662 })
663 }
664 }
665 }
666}
667
668#[allow(clippy::unwrap_used)]
669#[cfg(test)]
670mod tests {
671 use core::convert::TryInto;
672
673 use super::*;
674
675 #[test]
676 fn from_vec() {
677 assert!(BoundedVec::<u8, 2, 8>::from_vec(vec![1, 2]).is_ok());
678 assert!(BoundedVec::<u8, 2, 8>::from_vec(vec![]).is_err());
679 assert!(BoundedVec::<u8, 3, 8>::from_vec(vec![1, 2]).is_err());
680 assert!(BoundedVec::<u8, 1, 2>::from_vec(vec![1, 2, 3]).is_err());
681 }
682
683 #[test]
684 fn is_empty() {
685 let data: EmptyBoundedVec<_, 8> = vec![1u8, 2].try_into().unwrap();
686 assert!(!data.is_empty());
687 }
688
689 #[test]
690 fn as_vec() {
691 let data: BoundedVec<_, 2, 8> = vec![1u8, 2].try_into().unwrap();
692 assert_eq!(data.as_vec(), &vec![1u8, 2]);
693 }
694
695 #[test]
696 fn as_slice() {
697 let data: BoundedVec<_, 2, 8> = vec![1u8, 2].try_into().unwrap();
698 assert_eq!(data.as_slice(), &[1u8, 2]);
699 }
700
701 #[test]
702 fn len() {
703 let data: BoundedVec<_, 2, 8> = vec![1u8, 2].try_into().unwrap();
704 assert_eq!(data.len(), 2);
705 }
706
707 #[test]
708 fn first() {
709 let data: BoundedVec<_, 2, 8> = vec![1u8, 2].try_into().unwrap();
710 assert_eq!(data.first(), &1u8);
711 }
712
713 #[test]
714 fn last() {
715 let data: BoundedVec<_, 2, 8> = vec![1u8, 2].try_into().unwrap();
716 assert_eq!(data.last(), &2u8);
717 }
718
719 #[test]
720 fn mapped() {
721 let data: BoundedVec<u8, 2, 8> = [1u8, 2].into();
722 let data = data.mapped(|x| x * 2);
723 assert_eq!(data, [2u8, 4].into());
724 }
725
726 #[test]
727 fn mapped_ref() {
728 let data: BoundedVec<u8, 2, 8> = [1u8, 2].into();
729 let data = data.mapped_ref(|x| x * 2);
730 assert_eq!(data, [2u8, 4].into());
731 }
732
733 #[test]
734 fn get() {
735 let data: BoundedVec<_, 2, 8> = vec![1u8, 2].try_into().unwrap();
736 assert_eq!(data.get(1).unwrap(), &2u8);
737 assert!(data.get(3).is_none());
738 }
739
740 #[test]
741 fn try_mapped() {
742 let data: BoundedVec<u8, 2, 8> = [1u8, 2].into();
743 let data = data.try_mapped(|x| 100u8.checked_div(x).ok_or("error"));
744 assert_eq!(data, Ok([100u8, 50].into()));
745 }
746
747 #[test]
748 fn try_mapped_error() {
749 let data: BoundedVec<u8, 2, 8> = [0u8, 2].into();
750 let data = data.try_mapped(|x| 100u8.checked_div(x).ok_or("error"));
751 assert_eq!(data, Err("error"));
752 }
753
754 #[test]
755 fn try_mapped_ref() {
756 let data: BoundedVec<u8, 2, 8> = [1u8, 2].into();
757 let data = data.try_mapped_ref(|x| 100u8.checked_div(*x).ok_or("error"));
758 assert_eq!(data, Ok([100u8, 50].into()));
759 }
760
761 #[test]
762 fn try_mapped_ref_error() {
763 let data: BoundedVec<u8, 2, 8> = [0u8, 2].into();
764 let data = data.try_mapped_ref(|x| 100u8.checked_div(*x).ok_or("error"));
765 assert_eq!(data, Err("error"));
766 }
767
768 #[test]
769 fn split_last() {
770 let data: BoundedVec<_, 2, 8> = vec![1u8, 2].try_into().unwrap();
771 assert_eq!(data.split_last(), (&2u8, [1u8].as_ref()));
772 let data1: BoundedVec<_, 1, 8> = vec![1u8].try_into().unwrap();
773 assert_eq!(data1.split_last(), (&1u8, Vec::new().as_ref()));
774 }
775
776 #[test]
777 fn enumerated() {
778 let data: BoundedVec<_, 2, 8> = vec![1u8, 2].try_into().unwrap();
779 let expected: BoundedVec<_, 2, 8> = vec![(0, 1u8), (1, 2)].try_into().unwrap();
780 assert_eq!(data.enumerated(), expected);
781 }
782
783 #[test]
784 fn into_iter() {
785 let mut vec = vec![1u8, 2];
786 let mut data: BoundedVec<_, 2, 8> = vec.clone().try_into().unwrap();
787 assert_eq!(data.clone().into_iter().collect::<Vec<u8>>(), vec);
788 assert_eq!(
789 data.iter().collect::<Vec<&u8>>(),
790 vec.iter().collect::<Vec<&u8>>()
791 );
792 assert_eq!(
793 data.iter_mut().collect::<Vec<&mut u8>>(),
794 vec.iter_mut().collect::<Vec<&mut u8>>()
795 );
796 }
797}
798
799#[cfg(feature = "serde")]
800#[cfg(test)]
801#[allow(clippy::unwrap_used)]
802mod serde_tests {
803 use super::*;
804 use alloc::vec;
805 #[test]
806 fn deserialize_nonempty() {
807 assert_eq!(
808 serde_json::from_str::<BoundedVec::<u8, 2, 3>>("[1, 2]")
809 .unwrap()
810 .as_vec(),
811 &vec![1, 2]
812 );
813 }
814
815 #[test]
816 fn deserialize_empty() {
817 assert!(serde_json::from_str::<BoundedVec::<u8, 2, 3>>("[]").is_err());
818 assert!(serde_json::from_str::<EmptyBoundedVec::<u8, 3>>("[]").is_ok());
819 }
820}
821
822#[cfg(feature = "arbitrary")]
823#[cfg(test)]
824#[allow(clippy::len_zero)]
825mod arb_tests {
826
827 use super::*;
828 use alloc::format;
829 use proptest::prelude::*;
830
831 proptest! {
832
833 #[test]
834 fn bounded_vec_length_bounded(v: BoundedVec<u8, 1, 2>) {
835 prop_assert!(1 <= v.len() && v.len() <= 2);
836 }
837 }
838}