generic_std/
lib.rs

1//! Standard generic traits.
2//!
3//! # Why
4//!
5//! Did you ever need a generic `Sequence` trait? Ever wanted a data structure
6//! that was generic over either `Rc` or `Arc`? An iterator that returns
7//! borrowed data?
8//!
9//! These are not usually thought to be possible in stable Rust due to lack of
10//! native support for higher-kinded types (HKTs). HKTs is a feature that would
11//! allow us to reason about, say, `Vec` without fully defining it with type
12//! arguments (`Vec<T>`). The classic example that is usually thought
13//! impossible is the streaming (or borrowing) iterator, where `next()` returns
14//! an item wih a lifetime bound by the iterator itself:
15//!
16//! ```compile_fail
17//! trait StreamingIterator {
18//!   type Item = &str;
19//!   fn next<'a>(&'a mut self) -> Option<&'a str> {
20//!     unimplemented!()
21//!   }
22//! }
23//! ```
24//!
25//! This does not compile because the reference `&str` must be declared with a
26//! lifetime, but we only have the lifetime for `self` in `next()` itself and
27//! not in the associated type declaration. Unlike `type` aliases, associated
28//! types (`type` in a trait) cannot have type arguments. That is, the
29//! following is not valid:
30//!
31//! ```compile_fail
32//! trait StreamingIterator {
33//!   type Item<'a> = &'a str;
34//!   fn next<'a>(&'a mut self) -> Option<&'a str> {
35//!     unimplemented!()
36//!   }
37//! }
38//! ```
39//!
40//! This is called an associated type constructor. For more information, see
41//! the
42//! [RFC](https://github.com/rust-lang/rfcs/blob/master/text/1598-generic_associated_types.md)
43//! and
44//! [Nicholas'](https://smallcultfollowing.com/babysteps/blog/2016/11/02/associated-type-constructors-part-1-basic-concepts-and-introduction/)
45//! ATC post series.
46//!
47//! However, it is possible to emulate this behaviour in stable Rust with more
48//! boilerplate. See the [`StreamingIterator`](trait.StreamingIterator.html)
49//! trait.
50//!
51//! # How
52//!
53//! This library implements multiple generic traits for `std` types using a
54//! variation of
55//! [Edmund Smith's](https://gist.github.com/edmundsmith/855fcf0cb35dd467c29a9350481f0ecf)
56//! method to emulate higher-kinded types. See the [plug](plug/index.html)
57//! module for details.
58//!
59//! # Limitations
60//!
61//! HKT for types seems to be complete using the plug method. That is, any
62//! functionality you could get with native HKT support for types, you can get
63//! with this method. Ergonomy is not great though, even if it works.
64//!
65//! There are limitations regarding HKT lifetimes due to the fact that is
66//! impossible to put bounds on HRTB lifetimes. That is, something like
67//! `for<'a: 'b>` is inexpressible. As a result some traits and impls may have
68//! more restrictive lifetime bounds than necessary.
69//!
70//! # Current Status
71//!
72//! This crate is highly experimental and many traits have limited
73//! functionality.
74
75pub mod plug;
76pub mod rc;
77pub mod reference;
78pub mod slice;
79pub mod sync;
80pub mod vec;
81
82#[cfg(test)]
83mod tests;
84
85use crate::plug::*;
86use std::ops::Deref;
87
88/// Trait for structs that can be constructed with a preallocated capacity.
89pub trait WithCapacity {
90    fn with_capacity(capacity: usize) -> Self;
91}
92
93/// Trait for collections that store elements in a linear sequence, allowing
94/// for linear traversal and indexing with an `usize`.
95///
96/// # Note
97///
98/// The `H1Iterator` bounds are not specific enough due to language
99/// limitations. The correct declaration for the trait and `H1Iterator` is:
100///
101/// ```compile_fail
102/// trait Sequence<'a, T>
103/// where
104///   T: 'a
105/// {
106///   type H1Iterator: for<'b> PlugLifetime<'b>
107///   where
108///     'a: 'b,
109///     <H1Iterator as PlugLifetime<'b>>::T: StreamingIterator;
110///   ...
111/// }
112/// ```
113///
114/// Because we can't declare `'a: 'b`, implementors must only allow
115/// `T: 'static`. In other words, we can't declare that all items outlive the
116/// iterator for any specific lifetime (so that stuff like `next()` returning a
117/// `&T` is valid if `T` contains references), so we must use a shotgun and
118/// prohibit `T` from containing any non-`'static` references.
119///
120/// Also, where clauses in associated types are not stable so we have to move
121/// `StreamingIterator` bound to the `iter()` declaration.
122pub trait Sequence<T> {
123    /// HKT iterator with a lifetime slot.
124    type H1Iterator: for<'a> PlugLifetime<'a>;
125
126    fn len(&self) -> usize;
127
128    fn is_empty(&self) -> bool {
129        self.len() == 0
130    }
131
132    fn contains<'a>(&'a self, x: &T) -> bool
133    where
134        T: PartialEq;
135
136    fn get(&self, index: usize) -> Option<&T>;
137
138    fn first(&self) -> Option<&T> {
139        self.get(0)
140    }
141
142    fn last(&self) -> Option<&T> {
143        self.get(self.len() - 1)
144    }
145
146    fn iter<'a>(&'a self) -> <Self::H1Iterator as PlugLifetime<'a>>::T
147    where
148        <Self::H1Iterator as PlugLifetime<'a>>::T: StreamingIterator;
149}
150
151/// Trait for mutable collections that store elements in a linear sequence,
152/// allowing for linear traversal and indexing with an `usize`.
153pub trait SequenceMut<T> {
154    fn capacity(&self) -> usize;
155
156    fn clear(&mut self);
157
158    fn reserve(&mut self, additional: usize);
159
160    fn reserve_exact(&mut self, additional: usize);
161
162    fn shrink_to_fit(&mut self);
163
164    fn push(&mut self, x: T);
165
166    fn pop(&mut self) -> Option<T>;
167
168    fn insert(&mut self, index: usize, x: T);
169
170    fn remove(&mut self, index: usize) -> T;
171}
172
173/// Trait for iterators that can return elements borrowed from itself.
174pub trait StreamingIterator {
175    /// HTK item with a lifetime slot.
176    type H1Item: for<'a> PlugLifetime<'a>;
177
178    fn next(&mut self) -> Option<<Self::H1Item as PlugLifetime>::T>;
179}
180
181impl<I> StreamingIterator for I
182where
183    I: Iterator,
184{
185    type H1Item = H0<I::Item>;
186
187    fn next(&mut self) -> Option<<Self::H1Item as PlugLifetime>::T> {
188        Iterator::next(self)
189    }
190}
191
192/// Trait for reference-counted boxes.
193pub trait Rcb<T>: Clone + Deref<Target = T> {
194    type Weak: WeakRcb<T>;
195
196    fn new(x: T) -> Self;
197
198    fn try_unwrap(this: Self) -> Result<T, Self>;
199
200    fn downgrade(this: &Self) -> Self::Weak;
201}
202
203/// Trait for weak pointers to reference-counted boxes.
204pub trait WeakRcb<T> {
205    type Strong: Rcb<T>;
206
207    fn upgrade(&self) -> Option<Self::Strong>;
208}