1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
//! This crate provides a set of traits that can be used to abstract over
//! various collection types. In particular, it supports traits for fallible
//! operations (such as [`TryExtend`]) which are useful for supporting
//! fixed-capacity containers, such as `heapless::Vec` or `tinyvec::Array`.

#![no_std]

#[cfg(feature = "alloc")]
extern crate alloc;

/// Collection types implement all of the traits in this crate.
pub trait Collection<T>:
    AsRef<[T]> + AsMut<[T]> + Default + Length + Truncate + TryExtend<T> + TryPush<T>
{
}

/// Obtain the length of a collection.
pub trait Length {
    /// Get the length of this collection.
    fn len(&self) -> usize;

    /// Is the collection empty?
    fn is_empty(&self) -> bool {
        self.len() == 0
    }
}

/// Truncate the collection to the provided length.
pub trait Truncate {
    /// Truncate this buffer to the given number of elements.
    ///
    /// If `len` is bigger than the current number of elements (or the total
    /// capacity of the buffer) no changes are made to the contents.
    fn truncate(&mut self, len: usize);
}

/// Fallible equivalent of [`core::iter::Extend`] - extends a collection
/// with the contents of an iterator, but with the option to return an error
/// in the event the container's capacity has been exceeded.
///
/// [`core::iter::Extend`]: https://doc.rust-lang.org/core/iter/trait.Extend.html
pub trait TryExtend<A> {
    /// Error type.
    type Error;

    /// Try to extend the collection from the given iterator.
    fn try_extend<T>(&mut self, iter: &mut T) -> Result<(), Self::Error>
    where
        T: Iterator<Item = A>;

    /// Try to extend the collection from the given slice.
    fn try_extend_from_slice(&mut self, slice: &[A]) -> Result<(), Self::Error>
    where
        A: Clone,
    {
        self.try_extend(&mut slice.iter().cloned())
    }
}

/// Try to build a collection type from an [`Iterator`].
///
/// Fallible in the event the capacity of the underlying container type is
/// exceeded.
pub trait TryFromIterator<A>: Sized {
    /// Error type.
    type Error;

    /// Try to create a new collection from the given iterator, potentially
    /// returning an error if the underlying collection's capacity is exceeded.
    fn try_from_iter<T>(iter: &mut T) -> Result<Self, Self::Error>
    where
        T: Iterator<Item = A>;
}

impl<A, C: Default + TryExtend<A>> TryFromIterator<A> for C {
    type Error = <Self as TryExtend<A>>::Error;

    fn try_from_iter<T>(iter: &mut T) -> Result<Self, Self::Error>
    where
        T: Iterator<Item = A>,
    {
        let mut collection = Self::default();
        collection.try_extend(iter)?;
        Ok(collection)
    }
}

/// Try to push an element onto a collection
pub trait TryPush<T> {
    /// Try to push an element onto a collection.
    ///
    /// Returns the original element if it's full.
    fn try_push(&mut self, item: T) -> Result<(), T>;
}

/// [`TryCollect`] is an extension to [`Iterator`] which allows for performing
/// a fallible collection into a collection type.
pub trait TryCollect<A> {
    fn try_collect<B>(&mut self) -> Result<B, B::Error>
    where
        B: TryFromIterator<A>;
}

impl<A, T> TryCollect<A> for T
where
    T: Iterator<Item = A>,
{
    fn try_collect<B>(&mut self) -> Result<B, B::Error>
    where
        B: TryFromIterator<A>,
    {
        B::try_from_iter(self)
    }
}

#[cfg(feature = "alloc")]
mod vec_impls {
    use super::{Length, Truncate, TryExtend};
    use alloc::vec::Vec;
    use core::convert::Infallible;

    impl<T> Length for Vec<T> {
        fn len(&self) -> usize {
            Vec::len(self)
        }
    }

    impl<T> Truncate for Vec<T> {
        fn truncate(&mut self, len: usize) {
            Vec::truncate(self, len);
        }
    }

    impl<A> TryExtend<A> for Vec<A> {
        type Error = Infallible;

        fn try_extend<T: IntoIterator<Item = A>>(&mut self, iter: T) -> Result<(), Infallible> {
            Vec::extend(self, iter);
            Ok(())
        }
    }
}