borrow_bag/append.rs
1use handle::{new_handle, Handle, Skip, Take};
2use lookup::Lookup;
3
4/// Describes the result of appending `T` to the borrow-bag. This is useful in specifying the
5/// return type when creating/modifying a `BorrowBag` in a function.
6///
7/// ## Examples
8///
9/// ```rust
10/// # use borrow_bag::{Append, BorrowBag, Handle};
11/// #
12/// type SingleItemBag<T> = BorrowBag<(T, ())>;
13/// type SingleItemHandle<T> = Handle<T, <() as Append<T>>::Navigator>;
14///
15/// fn single_item_bag<T>(t: T) -> (SingleItemBag<T>, SingleItemHandle<T>) {
16/// BorrowBag::new().add(t)
17/// }
18/// #
19/// # let (bag, handle) = single_item_bag(1u8);
20/// # assert_eq!(*bag.borrow(handle), 1);
21/// ```
22pub trait Append<T> {
23 /// The resulting `BorrowBag` type parameter after adding an element of type `T`.
24 type Output: PrefixedWith<Self> + Lookup<T, Self::Navigator>;
25
26 /// A type describing how to borrow the `T` which is added.
27 ///
28 /// If the output type is `(X, (Y, (Z, ())))`, we're adding the `Z` and so our `Navigator` will
29 /// be `(Skip, (Skip, Take))`
30 type Navigator;
31
32 /// Append the element, returning a new collection and a handle to borrow the element back.
33 fn append(self, t: T) -> (Self::Output, Handle<T, Self::Navigator>);
34}
35
36impl<T, U, V> Append<T> for (U, V)
37where
38 V: Append<T>,
39{
40 // We're mid-list. Return the head and append to the tail.
41 type Output = (U, <V as Append<T>>::Output);
42
43 // We're mid-list. Skip this element and navigate again in the tail.
44 type Navigator = (Skip, <V as Append<T>>::Navigator);
45
46 fn append(self, t: T) -> (Self::Output, Handle<T, Self::Navigator>) {
47 let (u, v) = self;
48 ((u, v.append(t).0), new_handle())
49 }
50}
51
52impl<T> Append<T> for () {
53 // This is the end of the added elements. We insert our `T` before the end.
54 type Output = (T, ());
55
56 // We're adding our `T` here, so we take this element on navigation.
57 type Navigator = Take;
58
59 fn append(self, t: T) -> (Self::Output, Handle<T, Self::Navigator>) {
60 ((t, ()), new_handle())
61 }
62}
63
64/// Provides proof that the existing list elements don't move, which guarantees that existing
65/// `Handle` values continue to work.
66pub trait PrefixedWith<T>
67where
68 T: ?Sized,
69{
70}
71
72impl<U, V0, V1> PrefixedWith<(U, V0)> for (U, V1) where V1: PrefixedWith<V0> {}
73impl<U> PrefixedWith<()> for (U, ()) {}
74
75#[cfg(test)]
76mod tests {
77 use super::*;
78
79 #[test]
80 fn append_test() {
81 let (list, _): ((u8, ()), Handle<u8, Take>) = ().append(1u8);
82 let (list, _) = list.append(2u8);
83 let (list, _) = list.append(3u8);
84
85 assert_eq!(list.0, 1);
86 assert_eq!((list.1).0, 2);
87 assert_eq!(((list.1).1).0, 3);
88 }
89}