bounded_vec/
bounded_vec.rs

1use alloc::vec;
2use alloc::vec::Vec;
3use core::convert::{TryFrom, TryInto};
4use core::slice::{Iter, IterMut};
5use thiserror::Error;
6
7/// Non-empty Vec bounded with minimal (L - lower bound) and maximal (U - upper bound) items quantity.
8///
9/// # Type Parameters
10///
11/// * `W` - witness type to prove vector ranges and shape of interface accordingly
12#[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/// BoundedVec errors
19#[derive(Error, PartialEq, Eq, Debug, Clone)]
20pub enum BoundedVecOutOfBounds {
21    /// Items quantity is less than L (lower bound)
22    #[error("Lower bound violation: got {got} (expected >= {lower_bound})")]
23    LowerBoundError {
24        /// L (lower bound)
25        lower_bound: usize,
26        /// provided value
27        got: usize,
28    },
29    /// Items quantity is more than U (upper bound)
30    #[error("Upper bound violation: got {got} (expected <= {upper_bound})")]
31    UpperBoundError {
32        /// U (upper bound)
33        upper_bound: usize,
34        /// provided value
35        got: usize,
36    },
37}
38
39/// Module for type witnesses used to prove vector bounds at compile time
40pub mod witnesses {
41
42    // NOTE: we can have proves if needed for some cases like 8/16/32/64 upper bound, so can make memory and serde more compile safe and efficient
43
44    /// Compile-time proof of valid bounds. Must be constructed with same bounds to instantiate `BoundedVec`.
45    #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
46    pub struct NonEmpty<const L: usize, const U: usize>(());
47
48    /// Possibly empty vector with upper bound.
49    #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
50    pub struct Empty<const U: usize>(());
51
52    /// Type a compile-time proof of valid bounds
53    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    /// Type a compile-time proof for possibly empty vector with upper bound
67    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    /// Creates new BoundedVec or returns error if items count is out of bounds
74    ///
75    /// # Parameters
76    ///
77    /// * `items` - vector of items within bounds
78    ///
79    /// # Errors
80    ///
81    /// * `UpperBoundError` - if `items`` len is more than U (upper bound)
82    ///
83    /// # Example
84    /// ```
85    /// use bounded_vec::BoundedVec;
86    /// use bounded_vec::witnesses;
87    /// let data: BoundedVec<_, 0, 8, witnesses::Empty<8>> =
88    ///     BoundedVec::<_, 0, 8, witnesses::Empty<8>>::from_vec(vec![1u8, 2]).unwrap();
89    /// ```
90    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    /// Returns the first element of the vector, or `None` if it is empty
107    ///
108    /// # Example
109    /// ```
110    /// use bounded_vec::BoundedVec;
111    /// use bounded_vec::witnesses;
112    /// use std::convert::TryInto;
113    ///
114    /// let data: BoundedVec<u8, 0, 8, witnesses::Empty<8>> = vec![1u8, 2].try_into().unwrap();
115    /// assert_eq!(data.first(), Some(&1u8));
116    /// ```
117    pub fn first(&self) -> Option<&T> {
118        self.inner.first()
119    }
120
121    /// Returns `true` if the vector contains no elements
122    ///
123    /// # Example
124    /// ```
125    /// use bounded_vec::BoundedVec;
126    /// use bounded_vec::witnesses;
127    /// use std::convert::TryInto;
128    ///
129    /// let data: BoundedVec<u8, 0, 8, witnesses::Empty<8>> = vec![1u8, 2].try_into().unwrap();
130    /// assert_eq!(data.is_empty(), false);
131    /// ```
132    pub fn is_empty(&self) -> bool {
133        self.inner.is_empty()
134    }
135
136    /// Returns the last element of the vector, or `None` if it is empty
137    ///
138    /// # Example
139    /// ```
140    /// use bounded_vec::BoundedVec;
141    /// use bounded_vec::witnesses;
142    /// use std::convert::TryInto;
143    ///
144    /// let data: BoundedVec<u8, 0, 8, witnesses::Empty<8>> = vec![1u8, 2].try_into().unwrap();
145    /// assert_eq!(data.last(), Some(&2u8));
146    /// ```
147    pub fn last(&self) -> Option<&T> {
148        self.inner.last()
149    }
150}
151
152/// Methods which works for all witnesses
153impl<T, const L: usize, const U: usize, W> BoundedVec<T, L, U, W> {
154    /// Returns a reference to underlying `Vec``
155    ///
156    /// # Example
157    /// ```
158    /// use bounded_vec::BoundedVec;
159    /// use std::convert::TryInto;
160    ///
161    /// let data: BoundedVec<_, 2, 8> = vec![1u8, 2].try_into().unwrap();
162    /// assert_eq!(data.as_vec(), &vec![1u8,2]);
163    /// ```
164    pub fn as_vec(&self) -> &Vec<T> {
165        &self.inner
166    }
167
168    /// Returns an underlying `Vec``
169    ///
170    /// # Example
171    /// ```
172    /// use bounded_vec::BoundedVec;
173    /// use std::convert::TryInto;
174    ///
175    /// let data: BoundedVec<_, 2, 8> = vec![1u8, 2].try_into().unwrap();
176    /// assert_eq!(data.to_vec(), vec![1u8,2]);
177    /// ```
178    pub fn to_vec(self) -> Vec<T> {
179        self.inner
180    }
181
182    /// Extracts a slice containing the entire vector.
183    ///
184    /// # Example
185    /// ```
186    /// use bounded_vec::BoundedVec;
187    /// use std::convert::TryInto;
188    ///
189    /// let data: BoundedVec<_, 2, 8> = vec![1u8, 2].try_into().unwrap();
190    /// assert_eq!(data.as_slice(), &[1u8,2]);
191    /// ```
192    pub fn as_slice(&self) -> &[T] {
193        self.inner.as_slice()
194    }
195
196    /// Returns a reference for an element at index or `None` if out of bounds
197    ///
198    /// # Example
199    ///
200    /// ```
201    /// use bounded_vec::BoundedVec;
202    /// let data: BoundedVec<u8, 2, 8> = [1u8,2].into();
203    /// let elem = *data.get(1).unwrap();
204    /// assert_eq!(elem, 2);
205    /// ```
206    pub fn get(&self, index: usize) -> Option<&T> {
207        self.inner.get(index)
208    }
209
210    /// Returns an iterator
211    pub fn iter(&self) -> Iter<T> {
212        self.inner.iter()
213    }
214
215    /// Returns an iterator that allows to modify each value
216    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    /// Creates new BoundedVec or returns error if items count is out of bounds
223    ///
224    /// # Parameters
225    ///
226    /// * `items` - vector of items within bounds
227    ///
228    /// # Errors
229    ///
230    /// * `LowerBoundError` - if `items`` len is less than L (lower bound)
231    /// * `UpperBoundError` - if `items`` len is more than U (upper bound)
232    ///
233    /// # Example
234    /// ```
235    /// use bounded_vec::BoundedVec;
236    /// use bounded_vec::witnesses;
237    /// let data: BoundedVec<_, 2, 8, witnesses::NonEmpty<2, 8>> =
238    ///     BoundedVec::<_, 2, 8, witnesses::NonEmpty<2, 8>>::from_vec(vec![1u8, 2]).unwrap();
239    /// ```
240    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    /// Returns the number of elements in the vector
262    ///
263    /// # Example
264    /// ```
265    /// use bounded_vec::BoundedVec;
266    /// use std::convert::TryInto;
267    ///
268    /// let data: BoundedVec<u8, 2, 4> = vec![1u8,2].try_into().unwrap();
269    /// assert_eq!(data.len(), 2);
270    /// ```
271    pub fn len(&self) -> usize {
272        self.inner.len()
273    }
274
275    /// Returns the first element of non-empty Vec
276    ///
277    /// # Example
278    /// ```
279    /// use bounded_vec::BoundedVec;
280    /// use std::convert::TryInto;
281    ///
282    /// let data: BoundedVec<_, 2, 8> = vec![1u8, 2].try_into().unwrap();
283    /// assert_eq!(*data.first(), 1);
284    /// ```
285    pub fn first(&self) -> &T {
286        #[allow(clippy::unwrap_used)]
287        self.inner.first().unwrap()
288    }
289
290    /// Returns the last element of non-empty Vec
291    ///
292    /// # Example
293    /// ```
294    /// use bounded_vec::BoundedVec;
295    /// use std::convert::TryInto;
296    ///
297    /// let data: BoundedVec<_, 2, 8> = vec![1u8, 2].try_into().unwrap();
298    /// assert_eq!(*data.last(), 2);
299    /// ```
300    pub fn last(&self) -> &T {
301        #[allow(clippy::unwrap_used)]
302        self.inner.last().unwrap()
303    }
304
305    /// Create a new `BoundedVec` by consuming `self` and mapping each element.
306    ///
307    /// This is useful as it keeps the knowledge that the length is >= U, <= L,
308    /// even through the old `BoundedVec` is consumed and turned into an iterator.
309    ///
310    /// # Example
311    ///
312    /// ```
313    /// use bounded_vec::BoundedVec;
314    /// let data: BoundedVec<u8, 2, 8> = [1u8,2].into();
315    /// let data = data.mapped(|x|x*2);
316    /// assert_eq!(data, [2u8,4].into());
317    /// ```
318    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    /// Create a new `BoundedVec` by mapping references to the elements of self
329    ///
330    /// This is useful as it keeps the knowledge that the length is >= U, <= L,
331    /// will still hold for new `BoundedVec`
332    ///
333    /// # Example
334    ///
335    /// ```
336    /// use bounded_vec::BoundedVec;
337    /// let data: BoundedVec<u8, 2, 8> = [1u8,2].into();
338    /// let data = data.mapped_ref(|x|x*2);
339    /// assert_eq!(data, [2u8,4].into());
340    /// ```
341    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    /// Create a new `BoundedVec` by consuming `self` and mapping each element
352    /// to a `Result`.
353    ///
354    /// This is useful as it keeps the knowledge that the length is preserved
355    /// even through the old `BoundedVec` is consumed and turned into an iterator.
356    ///
357    /// As this method consumes self, returning an error means that this
358    /// vec is dropped. I.e. this method behaves roughly like using a
359    /// chain of `into_iter()`, `map`, `collect::<Result<Vec<N>,E>>` and
360    /// then converting the `Vec` back to a `Vec1`.
361    ///
362    ///
363    /// # Errors
364    ///
365    /// Once any call to `map_fn` returns a error that error is directly
366    /// returned by this method.
367    ///
368    /// # Example
369    ///
370    /// ```
371    /// use bounded_vec::BoundedVec;
372    /// let data: BoundedVec<u8, 2, 8> = [1u8,2].into();
373    /// let data: Result<BoundedVec<u8, 2, 8>, _> = data.try_mapped(|x| Err("failed"));
374    /// assert_eq!(data, Err("failed"));
375    /// ```
376    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    /// Create a new `BoundedVec` by mapping references of `self` elements
393    /// to a `Result`.
394    ///
395    /// This is useful as it keeps the knowledge that the length is preserved
396    /// even through the old `BoundedVec` is consumed and turned into an iterator.
397    ///
398    /// # Errors
399    ///
400    /// Once any call to `map_fn` returns a error that error is directly
401    /// returned by this method.
402    ///
403    /// # Example
404    ///
405    /// ```
406    /// use bounded_vec::BoundedVec;
407    /// let data: BoundedVec<u8, 2, 8> = [1u8,2].into();
408    /// let data: Result<BoundedVec<u8, 2, 8>, _> = data.try_mapped_ref(|x| Err("failed"));
409    /// assert_eq!(data, Err("failed"));
410    /// ```
411    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    /// Returns the last and all the rest of the elements
428    pub fn split_last(&self) -> (&T, &[T]) {
429        #[allow(clippy::unwrap_used)]
430        self.inner.split_last().unwrap()
431    }
432
433    /// Return a new BoundedVec with indices included
434    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    /// Return a Some(BoundedVec) or None if `v` is empty
445    /// # Example
446    /// ```
447    /// use bounded_vec::BoundedVec;
448    /// use bounded_vec::OptBoundedVecToVec;
449    ///
450    /// let opt_bv_none = BoundedVec::<u8, 2, 8>::opt_empty_vec(vec![]).unwrap();
451    /// assert!(opt_bv_none.is_none());
452    /// assert_eq!(opt_bv_none.to_vec(), Vec::<u8>::new());
453    /// let opt_bv_some = BoundedVec::<u8, 2, 8>::opt_empty_vec(vec![0u8, 2]).unwrap();
454    /// assert!(opt_bv_some.is_some());
455    /// assert_eq!(opt_bv_some.to_vec(), vec![0u8, 2]);
456    /// ```
457    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
468/// A non-empty Vec with no effective upper-bound on its length
469pub type NonEmptyVec<T> = BoundedVec<T, 1, { usize::MAX }, witnesses::NonEmpty<1, { usize::MAX }>>;
470
471/// Possibly empty Vec with upper-bound on its length
472pub type EmptyBoundedVec<T, const U: usize> = BoundedVec<T, 0, U, witnesses::Empty<U>>;
473
474/// Non-empty Vec with bounded length
475pub 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
496// when feature(const_evaluatable_checked) is stable cover all array sizes (L..=U)
497impl<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
567/// Option<BoundedVec<T, _, _>> to Vec<T>
568pub trait OptBoundedVecToVec<T> {
569    /// Option<BoundedVec<T, _, _>> to Vec<T>
570    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    // direct impl to unify serde in one place instead of doing attribute on declaration and deserialize here
613    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        // we cannot use attributes, because the do not work with `const`, only numeric literals supported
651        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}