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
use handle::{new_handle, Handle, Skip, Take};
use lookup::Lookup;
/// Describes the result of appending `T` to the borrow-bag. This is useful in specifying the
/// return type when creating/modifying a `BorrowBag` in a function.
///
/// ## Examples
///
/// ```rust
/// # use borrow_bag::{Append, BorrowBag, Handle};
/// #
/// type SingleItemBag<T> = BorrowBag<(T, ())>;
/// type SingleItemHandle<T> = Handle<T, <() as Append<T>>::Navigator>;
///
/// fn single_item_bag<T>(t: T) -> (SingleItemBag<T>, SingleItemHandle<T>) {
/// BorrowBag::new().add(t)
/// }
/// #
/// # let (bag, handle) = single_item_bag(1u8);
/// # assert_eq!(*bag.borrow(handle), 1);
/// ```
pub trait Append<T> {
/// The resulting `BorrowBag` type parameter after adding an element of type `T`.
type Output: PrefixedWith<Self> + Lookup<T, Self::Navigator>;
/// A type describing how to borrow the `T` which is added.
///
/// If the output type is `(X, (Y, (Z, ())))`, we're adding the `Z` and so our `Navigator` will
/// be `(Skip, (Skip, Take))`
type Navigator;
/// Append the element, returning a new collection and a handle to borrow the element back.
fn append(self, t: T) -> (Self::Output, Handle<T, Self::Navigator>);
}
impl<T, U, V> Append<T> for (U, V)
where
V: Append<T>,
{
// We're mid-list. Return the head and append to the tail.
type Output = (U, <V as Append<T>>::Output);
// We're mid-list. Skip this element and navigate again in the tail.
type Navigator = (Skip, <V as Append<T>>::Navigator);
fn append(self, t: T) -> (Self::Output, Handle<T, Self::Navigator>) {
let (u, v) = self;
((u, v.append(t).0), new_handle())
}
}
impl<T> Append<T> for () {
// This is the end of the added elements. We insert our `T` before the end.
type Output = (T, ());
// We're adding our `T` here, so we take this element on navigation.
type Navigator = Take;
fn append(self, t: T) -> (Self::Output, Handle<T, Self::Navigator>) {
((t, ()), new_handle())
}
}
/// Provides proof that the existing list elements don't move, which guarantees that existing
/// `Handle` values continue to work.
pub trait PrefixedWith<T>
where
T: ?Sized,
{
}
impl<U, V0, V1> PrefixedWith<(U, V0)> for (U, V1) where V1: PrefixedWith<V0> {}
impl<U> PrefixedWith<()> for (U, ()) {}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn append_test() {
let (list, _): ((u8, ()), Handle<u8, Take>) = ().append(1u8);
let (list, _) = list.append(2u8);
let (list, _) = list.append(3u8);
assert_eq!(list.0, 1);
assert_eq!((list.1).0, 2);
assert_eq!(((list.1).1).0, 3);
}
}