sqnc/lib.rs
1//! Traits and adaptors for sequences.
2//!
3//! This crate defines traits and adaptors that allow for generalized handling of
4//! sequential data. For the purposes of this crate, a "sequence" is a linear
5//! collection of a known (at runtime) number of items. The `Sequence` and
6//! `MutSequence` traits are the random access equivalent of
7//! [`std::iter::Iterator`].
8//!
9//! The [`traits`] defined in this crate are implemented for the following
10//! external types:
11//!
12//! * [`slice`]
13//! * [`array`]
14//! * [`std::ops::Range<usize>`][`std::ops::Range`]
15//! * [`std::collections::VecDeque`] (requires feature `alloc`),
16//! * [`ndarray::Array1`] (requires feature `ndarray`),
17//!
18//! There are deliberately no implementations for types like [`Vec`] and
19//! [`Box<T>`][`std::boxed::Box`], where `T` implements [`Sequence`], in favor
20//! of automatic dereferencing to a [`slice`] and `T`, respectively, or the
21//! wrapping functions [`Sequence::as_sqnc`] and [`wrap`], which are detailed
22//! [below](#ownership-and-automagic-dereferencing).
23//!
24//! # Examples
25//!
26//! We bring the sequence traits into scope:
27//!
28//! ```
29//! use sqnc::{Sequence, MutSequence};
30//! ```
31//!
32//! Now we can use [`std::ops::Range<usize>`][`std::ops::Range`] as a [`Sequence`]:
33//!
34//! ```
35//! # use sqnc::{Sequence, MutSequence};
36//! let x = 4..8;
37//! assert_eq!(x.get(1), Some(5));
38//! assert_eq!(x.first(), Some(4));
39//! ```
40//!
41//! Similarly for [`[usize]`][`slice`], using Fully Qualified Syntax to
42//! disambiguate from the inherent implementation of [`slice`]:
43//!
44//! ```
45//! # use sqnc::{Sequence, MutSequence};
46//! let x: &[usize] = &[4, 5, 6, 7];
47//! assert_eq!(Sequence::get(x, 1), Some(&5));
48//! assert_eq!(Sequence::first(x), Some(&4));
49//! ```
50//!
51//! # Adaptors
52//!
53//! The [`Sequence`] trait provides several adaptors similar to [`Iterator`].
54//! All adaptors are free of allocation. Instead the adaptors keep hold of (a
55//! reference to) the original sequences.
56//!
57//! [`Sequence::copied()`] returns a sequence that copies all of
58//! its elements:
59//!
60//! ```
61//! # use sqnc::{Sequence, MutSequence};
62//! let x = [4, 5, 6, 7];
63//! let y = x.copied();
64//! assert_eq!(y.get(1), Some(5));
65//! ```
66//!
67//! And [`Sequence::map()`] applies the provided map to every element:
68//!
69//! ```
70//! # use sqnc::{Sequence, MutSequence};
71//! let x = [4, 5, 6, 7];
72//! // Using Fully Qualified Syntax to disambiguate from `array::map()`.
73//! let y = Sequence::map(x, |v| v + 2);
74//! assert!(y.iter().eq(6..10));
75//! ```
76//!
77//! Like the adaptors provided by [`Iterator`] these adaptors apply lazily. For
78//! example, [`Sequence::map()`] applies the map upon element access. If the
79//! map is expensive, all elements are going to be accessed more than once, and
80//! one can afford allocation, then it is probably more efficient to store the
81//! mapped sequence in a [`Vec`]. The previous example rewritten such that `y`
82//! is cached:
83//!
84//! ```
85//! # use sqnc::{Sequence, MutSequence};
86//! let x = [4, 5, 6, 7];
87//! let y: Vec<_> = x.iter().map(|v| v + 2).collect();
88//! ```
89//!
90//! The adaptors take ownership of its arguments. To retain ownership, the
91//! methods [`Sequence::as_sqnc()`] and [`MutSequence::as_mut_sqnc()`] can be
92//! used to obtain a sequence that references the sequence. Example:
93//!
94//! ```
95//! # use sqnc::{Sequence, MutSequence};
96//! let x = [4, 5, 6, 7];
97//! let y = x.as_sqnc().copied();
98//! assert_eq!(x.get(1), Some(&5));
99//! assert_eq!(y.get(1), Some(5));
100//! ```
101//!
102//! Given a sequence of indices [`Sequence::select()`] returns a selection of a
103//! sequence:
104//!
105//! ```
106//! # use sqnc::{Sequence, MutSequence};
107//! let x = *b"cdelst!";
108//! let y = x.select([4, 2, 3, 2, 0, 5, 2, 1, 6].copied()).unwrap();
109//! assert!(y.iter().eq(b"selected!"));
110//!
111//! assert!(x.select([4, 8, 0].copied()).is_none()); // Index `8` is out of bounds.
112//! ```
113//!
114//! A mutation to a selection propagates to the original sequence:
115//!
116//! ```
117//! # use sqnc::{Sequence, MutSequence};
118//! let mut x = ['a', 'b', 'c', 'd'];
119//! let mut y = x.as_mut_sqnc().select(1..3).unwrap();
120//! *y.get_mut(0).unwrap() = 'e';
121//! *y.get_mut(1).unwrap() = 'f';
122//! assert!(x.iter().copied().eq(['a', 'e', 'f', 'd']));
123//! ```
124//!
125//! Two sequences of the same element type can by concatenated using
126//! [`Sequence::concat()`]:
127//!
128//! ```
129//! # use sqnc::{Sequence, MutSequence};
130//! let mut x = ['a', 'b'];
131//! let mut y = ['c', 'd'];
132//! let mut z = x.as_mut_sqnc().concat(y.as_mut_sqnc()).unwrap();
133//! *z.get_mut(0).unwrap() = 'e';
134//! *z.get_mut(3).unwrap() = 'f';
135//! assert_eq!(x, ['e', 'b']);
136//! assert_eq!(y, ['c', 'f']);
137//! ```
138//!
139//! # Ownership and automagic dereferencing
140//!
141//! If a type does not implement [`Sequence`] directly, but does dereference to
142//! a type that implements [`Sequence`], then it is not possible to use
143//! adaptors directly, or in general: call functions that take ownership of an
144//! argument and require the argument to implement [`Sequence`]. For example,
145//! [`Vec`] does not implement [`Sequence`], so we can't call
146//! [`Sequence::copied()`] on a [`Vec`]:
147//!
148//! ```compile_fail
149//! # use sqnc::{Sequence, MutSequence};
150//! let x = vec![4, 5, 6, 7];
151//! let y = x.copied(); // `Vec` does not implement `Sequence`
152//! ```
153//!
154//! To help with this situation there is [`sqnc::wrap<S, N>(S) -> impl
155//! Sequence`][`wrap()`] which wraps a type `S` that, after dereferencing `N`
156//! times, implements [`Sequence`]:
157//!
158//! ```
159//! # use sqnc::{Sequence, MutSequence};
160//! let x = vec![4, 5, 6, 7];
161//! let y = sqnc::wrap(x).copied();
162//! assert_eq!(y.get(1), Some(5));
163//! ```
164//!
165//! The dereference depth `N` is automatically inferred by Rust, provided that
166//! there is exactly one `N` that satisfies the condition.
167//!
168//! See [`wrap()`] for more details.
169//!
170//! # Implementation details
171//!
172//! As of Rust 1.65 the Generic Associated Types feature is stable. We could've
173//! defined the item type of a [`Sequence`] with generic lifetime as follows
174//!
175//! ```
176//! trait Sequence {
177//! type Item<'a>;
178//! }
179//! ```
180//!
181//! Unfortunately this leads to [problems][GAT to be stable in Rust 1.65:
182//! implied static requirement] when trying to impose a bound on
183//! `Sequence::Item`. Until this is resorted, we use the third workaround
184//! described in [The Better Alternative to Lifetime GATs] for the item and
185//! iterator types of a [`Sequence`].
186//!
187//! [GAT to be stable in Rust 1.65: implied static requirement]: https://web.archive.org/web/20221030153327/https://blog.rust-lang.org/2022/10/28/gats-stabilization.html#implied-static-requirement-from-higher-ranked-trait-bounds
188//! [The Better Alternative to Lifetime GATs]: https://web.archive.org/web/20221022065950/https://sabrinajewson.org/blog/the-better-alternative-to-lifetime-gats
189//! [`Vec`]: `std::vec::Vec`
190
191#![no_std]
192
193// We have to include `std` here to let `cargo doc` resolve the
194// `std::collections::VecDeque` link in the documentation above.
195#[cfg(doc)]
196extern crate std;
197
198// Modules.
199
200mod concat;
201mod copied;
202pub mod derive;
203mod map;
204mod repeat;
205mod rev;
206mod select;
207pub mod traits;
208mod wrapper;
209mod zip;
210
211// Aliases.
212
213pub use concat::Concat;
214pub use copied::{Cloned, Copied};
215pub use map::Map;
216pub use repeat::Repeat;
217pub use rev::Rev;
218pub use select::Select;
219pub use traits::*;
220pub use wrapper::{wrap, Wrapper};
221pub use zip::Zip;
222
223// Implementations for foreign types.
224
225mod impl_array;
226mod impl_range;
227mod impl_slice;
228
229#[cfg(feature = "alloc")]
230mod impl_vec_deque;
231
232#[cfg(feature = "ndarray")]
233mod impl_ndarray;