1#[cfg(feature = "serde")]
2use serde::{Deserialize, Serialize};
3use std::convert::{TryFrom, TryInto};
4use std::slice::{Iter, IterMut};
5use std::vec;
6use thiserror::Error;
7
8#[derive(PartialEq, Eq, Debug, Clone, Hash, PartialOrd, Ord)]
10#[cfg_attr(feature = "serde", derive(Serialize, Deserialize), serde(transparent))]
11pub struct BoundedVec<T, const L: usize, const U: usize>
12{
16 inner: Vec<T>,
17}
18
19#[derive(Error, PartialEq, Eq, Debug, Clone)]
27pub enum BoundedVecOutOfBounds {
28 #[error("Lower bound violation: got {got} (expected >= {lower_bound})")]
30 LowerBoundError {
31 lower_bound: usize,
33 got: usize,
35 },
36 #[error("Upper bound violation: got {got} (expected <= {upper_bound})")]
38 UpperBoundError {
39 upper_bound: usize,
41 got: usize,
43 },
44}
45
46impl<T, const L: usize, const U: usize> BoundedVec<T, L, U> {
47 pub fn from_vec(items: Vec<T>) -> Result<Self, BoundedVecOutOfBounds> {
55 assert!(L > 0);
58 let len = items.len();
59 if len < L {
60 Err(BoundedVecOutOfBounds::LowerBoundError {
61 lower_bound: L,
62 got: len,
63 })
64 } else if len > U {
65 Err(BoundedVecOutOfBounds::UpperBoundError {
66 upper_bound: U,
67 got: len,
68 })
69 } else {
70 Ok(BoundedVec { inner: items })
71 }
72 }
73
74 pub fn as_vec(&self) -> &Vec<T> {
85 &self.inner
86 }
87
88 pub fn to_vec(self) -> Vec<T> {
99 self.into()
100 }
101
102 pub fn len(&self) -> usize {
113 self.inner.len()
114 }
115
116 pub fn is_empty(&self) -> bool {
127 false
128 }
129
130 pub fn as_slice(&self) -> &[T] {
141 self.inner.as_slice()
142 }
143
144 pub fn first(&self) -> &T {
155 #[allow(clippy::unwrap_used)]
156 self.inner.first().unwrap()
157 }
158
159 pub fn last(&self) -> &T {
170 #[allow(clippy::unwrap_used)]
171 self.inner.last().unwrap()
172 }
173
174 pub fn mapped<F, N>(self, map_fn: F) -> BoundedVec<N, L, U>
188 where
189 F: FnMut(T) -> N,
190 {
191 BoundedVec {
192 inner: self.inner.into_iter().map(map_fn).collect::<Vec<_>>(),
193 }
194 }
195
196 pub fn mapped_ref<F, N>(&self, map_fn: F) -> BoundedVec<N, L, U>
210 where
211 F: FnMut(&T) -> N,
212 {
213 BoundedVec {
214 inner: self.inner.iter().map(map_fn).collect::<Vec<_>>(),
215 }
216 }
217
218 pub fn try_mapped<F, N, E>(self, map_fn: F) -> Result<BoundedVec<N, L, U>, E>
244 where
245 F: FnMut(T) -> Result<N, E>,
246 {
247 let mut map_fn = map_fn;
248 let mut out = Vec::with_capacity(self.len());
249 for element in self.inner.into_iter() {
250 out.push(map_fn(element)?);
251 }
252 #[allow(clippy::unwrap_used)]
253 Ok(BoundedVec::from_vec(out).unwrap())
254 }
255
256 pub fn try_mapped_ref<F, N, E>(&self, map_fn: F) -> Result<BoundedVec<N, L, U>, E>
276 where
277 F: FnMut(&T) -> Result<N, E>,
278 {
279 let mut map_fn = map_fn;
280 let mut out = Vec::with_capacity(self.len());
281 for element in self.inner.iter() {
282 out.push(map_fn(element)?);
283 }
284 #[allow(clippy::unwrap_used)]
285 Ok(BoundedVec::from_vec(out).unwrap())
286 }
287
288 pub fn get(&self, index: usize) -> Option<&T> {
299 self.inner.get(index)
300 }
301
302 pub fn iter(&self) -> Iter<T> {
304 self.inner.iter()
305 }
306
307 pub fn iter_mut(&mut self) -> IterMut<T> {
309 self.inner.iter_mut()
310 }
311
312 pub fn split_last(&self) -> (&T, &[T]) {
314 #[allow(clippy::unwrap_used)]
315 self.inner.split_last().unwrap()
316 }
317
318 pub fn enumerated(self) -> BoundedVec<(usize, T), L, U> {
320 #[allow(clippy::unwrap_used)]
321 self.inner
322 .into_iter()
323 .enumerate()
324 .collect::<Vec<(usize, T)>>()
325 .try_into()
326 .unwrap()
327 }
328
329 pub fn opt_empty_vec(v: Vec<T>) -> Result<Option<BoundedVec<T, L, U>>, BoundedVecOutOfBounds> {
343 if v.is_empty() {
344 Ok(None)
345 } else {
346 Ok(Some(BoundedVec::from_vec(v)?))
347 }
348 }
349}
350
351pub type NonEmptyVec<T> = BoundedVec<T, 1, { usize::MAX }>;
353
354impl<T, const L: usize, const U: usize> TryFrom<Vec<T>> for BoundedVec<T, L, U> {
355 type Error = BoundedVecOutOfBounds;
356
357 fn try_from(value: Vec<T>) -> Result<Self, Self::Error> {
358 BoundedVec::from_vec(value)
359 }
360}
361
362impl<T, const L: usize, const U: usize> From<[T; L]> for BoundedVec<T, L, U> {
364 fn from(arr: [T; L]) -> Self {
365 BoundedVec { inner: arr.into() }
366 }
367}
368
369impl<T, const L: usize, const U: usize> From<BoundedVec<T, L, U>> for Vec<T> {
370 fn from(v: BoundedVec<T, L, U>) -> Self {
371 v.inner
372 }
373}
374
375impl<T, const L: usize, const U: usize> IntoIterator for BoundedVec<T, L, U> {
376 type Item = T;
377 type IntoIter = vec::IntoIter<T>;
378
379 fn into_iter(self) -> Self::IntoIter {
380 self.inner.into_iter()
381 }
382}
383
384impl<'a, T, const L: usize, const U: usize> IntoIterator for &'a BoundedVec<T, L, U> {
385 type Item = &'a T;
386 type IntoIter = core::slice::Iter<'a, T>;
387
388 fn into_iter(self) -> Self::IntoIter {
389 (&self.inner).iter()
390 }
391}
392
393impl<'a, T, const L: usize, const U: usize> IntoIterator for &'a mut BoundedVec<T, L, U> {
394 type Item = &'a mut T;
395 type IntoIter = core::slice::IterMut<'a, T>;
396
397 fn into_iter(self) -> Self::IntoIter {
398 (&mut self.inner).iter_mut()
399 }
400}
401
402impl<T, const L: usize, const U: usize> AsRef<Vec<T>> for BoundedVec<T, L, U> {
403 fn as_ref(&self) -> &Vec<T> {
404 &self.inner
405 }
406}
407
408impl<T, const L: usize, const U: usize> AsRef<[T]> for BoundedVec<T, L, U> {
409 fn as_ref(&self) -> &[T] {
410 self.inner.as_ref()
411 }
412}
413
414impl<T, const L: usize, const U: usize> AsMut<Vec<T>> for BoundedVec<T, L, U> {
415 fn as_mut(&mut self) -> &mut Vec<T> {
416 self.inner.as_mut()
417 }
418}
419
420impl<T, const L: usize, const U: usize> AsMut<[T]> for BoundedVec<T, L, U> {
421 fn as_mut(&mut self) -> &mut [T] {
422 self.inner.as_mut()
423 }
424}
425
426pub trait OptBoundedVecToVec<T> {
428 fn to_vec(self) -> Vec<T>;
430}
431
432impl<T, const L: usize, const U: usize> OptBoundedVecToVec<T> for Option<BoundedVec<T, L, U>> {
433 fn to_vec(self) -> Vec<T> {
434 self.map(|bv| bv.into()).unwrap_or_default()
435 }
436}
437
438#[allow(clippy::unwrap_used)]
439#[cfg(feature = "arbitrary")]
440mod arbitrary {
441
442 use super::*;
443 use proptest::collection::vec;
444 use proptest::prelude::Arbitrary;
445 use proptest::prelude::*;
446 use proptest::strategy::BoxedStrategy;
447
448 impl<T: Arbitrary, const L: usize, const U: usize> Arbitrary for BoundedVec<T, L, U>
449 where
450 T::Strategy: 'static,
451 {
452 type Strategy = BoxedStrategy<Self>;
453 type Parameters = ();
454
455 fn arbitrary_with(_args: Self::Parameters) -> Self::Strategy {
456 vec(any::<T>(), L..=U)
457 .prop_map(|items| BoundedVec::from_vec(items).unwrap())
458 .boxed()
459 }
460 }
461}
462
463#[allow(clippy::unwrap_used)]
464#[cfg(test)]
465mod tests {
466 use std::convert::TryInto;
467
468 use super::*;
469
470 #[test]
471 fn from_vec() {
472 assert!(BoundedVec::<u8, 2, 8>::from_vec(vec![1, 2]).is_ok());
473 assert!(BoundedVec::<u8, 2, 8>::from_vec(vec![]).is_err());
474 assert!(BoundedVec::<u8, 3, 8>::from_vec(vec![1, 2]).is_err());
475 assert!(BoundedVec::<u8, 1, 2>::from_vec(vec![1, 2, 3]).is_err());
476 }
477
478 #[test]
479 fn is_empty() {
480 let data: BoundedVec<_, 2, 8> = vec![1u8, 2].try_into().unwrap();
481 assert!(!data.is_empty());
482 }
483
484 #[test]
485 fn as_vec() {
486 let data: BoundedVec<_, 2, 8> = vec![1u8, 2].try_into().unwrap();
487 assert_eq!(data.as_vec(), &vec![1u8, 2]);
488 }
489
490 #[test]
491 fn as_slice() {
492 let data: BoundedVec<_, 2, 8> = vec![1u8, 2].try_into().unwrap();
493 assert_eq!(data.as_slice(), &[1u8, 2]);
494 }
495
496 #[test]
497 fn len() {
498 let data: BoundedVec<_, 2, 8> = vec![1u8, 2].try_into().unwrap();
499 assert_eq!(data.len(), 2);
500 }
501
502 #[test]
503 fn first() {
504 let data: BoundedVec<_, 2, 8> = vec![1u8, 2].try_into().unwrap();
505 assert_eq!(data.first(), &1u8);
506 }
507
508 #[test]
509 fn last() {
510 let data: BoundedVec<_, 2, 8> = vec![1u8, 2].try_into().unwrap();
511 assert_eq!(data.last(), &2u8);
512 }
513
514 #[test]
515 fn mapped() {
516 let data: BoundedVec<u8, 2, 8> = [1u8, 2].into();
517 let data = data.mapped(|x| x * 2);
518 assert_eq!(data, [2u8, 4].into());
519 }
520
521 #[test]
522 fn mapped_ref() {
523 let data: BoundedVec<u8, 2, 8> = [1u8, 2].into();
524 let data = data.mapped_ref(|x| x * 2);
525 assert_eq!(data, [2u8, 4].into());
526 }
527
528 #[test]
529 fn get() {
530 let data: BoundedVec<_, 2, 8> = vec![1u8, 2].try_into().unwrap();
531 assert_eq!(data.get(1).unwrap(), &2u8);
532 assert!(data.get(3).is_none());
533 }
534
535 #[test]
536 fn try_mapped() {
537 let data: BoundedVec<u8, 2, 8> = [1u8, 2].into();
538 let data = data.try_mapped(|x| 100u8.checked_div(x).ok_or("error"));
539 assert_eq!(data, Ok([100u8, 50].into()));
540 }
541
542 #[test]
543 fn try_mapped_error() {
544 let data: BoundedVec<u8, 2, 8> = [0u8, 2].into();
545 let data = data.try_mapped(|x| 100u8.checked_div(x).ok_or("error"));
546 assert_eq!(data, Err("error"));
547 }
548
549 #[test]
550 fn try_mapped_ref() {
551 let data: BoundedVec<u8, 2, 8> = [1u8, 2].into();
552 let data = data.try_mapped_ref(|x| 100u8.checked_div(*x).ok_or("error"));
553 assert_eq!(data, Ok([100u8, 50].into()));
554 }
555
556 #[test]
557 fn try_mapped_ref_error() {
558 let data: BoundedVec<u8, 2, 8> = [0u8, 2].into();
559 let data = data.try_mapped_ref(|x| 100u8.checked_div(*x).ok_or("error"));
560 assert_eq!(data, Err("error"));
561 }
562
563 #[test]
564 fn split_last() {
565 let data: BoundedVec<_, 2, 8> = vec![1u8, 2].try_into().unwrap();
566 assert_eq!(data.split_last(), (&2u8, [1u8].as_ref()));
567 let data1: BoundedVec<_, 1, 8> = vec![1u8].try_into().unwrap();
568 assert_eq!(data1.split_last(), (&1u8, Vec::new().as_ref()));
569 }
570
571 #[test]
572 fn enumerated() {
573 let data: BoundedVec<_, 2, 8> = vec![1u8, 2].try_into().unwrap();
574 let expected: BoundedVec<_, 2, 8> = vec![(0, 1u8), (1, 2)].try_into().unwrap();
575 assert_eq!(data.enumerated(), expected);
576 }
577
578 #[test]
579 fn into_iter() {
580 let mut vec = vec![1u8, 2];
581 let mut data: BoundedVec<_, 2, 8> = vec.clone().try_into().unwrap();
582 assert_eq!(data.clone().into_iter().collect::<Vec<u8>>(), vec);
583 assert_eq!(
584 data.iter().collect::<Vec<&u8>>(),
585 vec.iter().collect::<Vec<&u8>>()
586 );
587 assert_eq!(
588 data.iter_mut().collect::<Vec<&mut u8>>(),
589 vec.iter_mut().collect::<Vec<&mut u8>>()
590 );
591 }
592}
593
594#[cfg(feature = "arbitrary")]
595#[cfg(test)]
596#[allow(clippy::len_zero)]
597mod arb_tests {
598
599 use super::*;
600 use proptest::prelude::*;
601
602 proptest! {
603
604 #[test]
605 fn bounded_vec_length_bounded(v: BoundedVec<u8, 1, 2>) {
606 prop_assert!(1 <= v.len() && v.len() <= 2);
607 }
608 }
609}