sized_chunks/lib.rs
1// This Source Code Form is subject to the terms of the Mozilla Public
2// License, v. 2.0. If a copy of the MPL was not distributed with this
3// file, You can obtain one at http://mozilla.org/MPL/2.0/.
4
5//! # Sized Chunks
6//!
7//! This crate contains three fixed size low level array like data structures,
8//! primarily intended for use in [immutable.rs], but fully supported as a
9//! standalone crate.
10//!
11//! Their sizing information is encoded in the type using the
12//! [`typenum`][typenum] crate, which you may want to take a look at before
13//! reading on, but usually all you need to know about it is that it provides
14//! types `U1` to `U128` to represent numbers, which the data types take as type
15//! parameters, eg. `SparseChunk<A, U32>` would give you a sparse array with
16//! room for 32 elements of type `A`. You can also omit the size, as they all
17//! default to a size of 64, so `SparseChunk<A>` would be a sparse array with a
18//! capacity of 64.
19//!
20//! All data structures always allocate the same amount of space, as determined
21//! by their capacity, regardless of how many elements they contain, and when
22//! they run out of space, they will panic.
23//!
24//! ## Data Structures
25//!
26//! | Type | Description | Push | Pop | Deref to `&[A]` |
27//! | ---- | ----------- | ---- | --- | --------------- |
28//! | [`Chunk`][Chunk] | Contiguous array | O(1)/O(n) | O(1) | Yes |
29//! | [`RingBuffer`][RingBuffer] | Non-contiguous array | O(1) | O(1) | No |
30//! | [`SparseChunk`][SparseChunk] | Sparse array | N/A | N/A | No |
31//!
32//! The [`Chunk`][Chunk] and [`RingBuffer`][RingBuffer] are very similar in
33//! practice, in that they both work like a plain array, except that you can
34//! push to either end with some expectation of performance. The difference is
35//! that [`RingBuffer`][RingBuffer] always allows you to do this in constant
36//! time, but in order to give that guarantee, it doesn't lay out its elements
37//! contiguously in memory, which means that you can't dereference it to a slice
38//! `&[A]`.
39//!
40//! [`Chunk`][Chunk], on the other hand, will shift its contents around when
41//! necessary to accommodate a push to a full side, but is able to guarantee a
42//! contiguous memory layout in this way, so it can always be dereferenced into
43//! a slice. Performance wise, repeated pushes to the same side will always run
44//! in constant time, but a push to one side followed by a push to the other
45//! side will cause the latter to run in linear time if there's no room (which
46//! there would only be if you've popped from that side).
47//!
48//! To choose between them, you can use the following rules:
49//! - I only ever want to push to the back: you don't need this crate, try
50//! [`ArrayVec`][ArrayVec].
51//! - I need to push to either side but probably not both on the same array: use
52//! [`Chunk`][Chunk].
53//! - I need to push to both sides and I don't need slices: use
54//! [`RingBuffer`][RingBuffer].
55//! - I need to push to both sides but I do need slices: use [`Chunk`][Chunk].
56//!
57//! Finally, [`SparseChunk`][SparseChunk] is a more efficient version of
58//! `Vec<Option<A>>`: each index is either inhabited or not, but instead of
59//! using the `Option` discriminant to decide which is which, it uses a compact
60//! bitmap. You can also think of `SparseChunk<A, N>` as a `BTreeMap<usize, A>`
61//! where the `usize` must be less than `N`, but without the performance
62//! overhead. Its API is also more consistent with a map than an array - there's
63//! no push, pop, append, etc, just insert, remove and lookup.
64//!
65//! # [`InlineArray`][InlineArray]
66//!
67//! Finally, there's [`InlineArray`][InlineArray], which is a simple vector that's
68//! sized to fit inside any `Sized` type that's big enough to hold a size counter
69//! and at least one instance of the array element type. This can be a useful
70//! optimisation when implementing a list like data structure with a nontrivial
71//! set of pointers in its full form, where you could plausibly fit several
72//! elements inside the space allocated for the pointers. `im::Vector` is a
73//! good example of that, and the use case for which [`InlineArray`][InlineArray]
74//! was implemented.
75//!
76//! # Feature Flags
77//!
78//! The following feature flags are available:
79//!
80//! | Feature | Description |
81//! | ------- | ----------- |
82//! | `arbitrary` | Provides [`Arbitrary`][Arbitrary] implementations from the [`arbitrary`][arbitrary_crate] crate. Requires the `std` flag. |
83//! | `refpool` | Provides [`PoolDefault`][PoolDefault] and [`PoolClone`][PoolClone] implemetations from the [`refpool`][refpool] crate. |
84//! | `ringbuffer` | Enables the [`RingBuffer`][RingBuffer] data structure. |
85//! | `std` | Without this flag (enabled by default), the crate will be `no_std`, and absent traits relating to `std::collections` and `std::io`. |
86//!
87//! [immutable.rs]: https://immutable.rs/
88//! [typenum]: https://docs.rs/typenum/
89//! [Chunk]: struct.Chunk.html
90//! [RingBuffer]: struct.RingBuffer.html
91//! [SparseChunk]: struct.SparseChunk.html
92//! [InlineArray]: struct.InlineArray.html
93//! [ArrayVec]: https://docs.rs/arrayvec/
94//! [Arbitrary]: https://docs.rs/arbitrary/latest/arbitrary/trait.Arbitrary.html
95//! [arbitrary_crate]: https://docs.rs/arbitrary
96//! [refpool]: https://docs.rs/refpool
97//! [PoolDefault]: https://docs.rs/refpool/latest/refpool/trait.PoolDefault.html
98//! [PoolClone]: https://docs.rs/refpool/latest/refpool/trait.PoolClone.html
99
100#![forbid(rust_2018_idioms)]
101#![deny(nonstandard_style)]
102#![warn(unreachable_pub, missing_docs)]
103#![cfg_attr(test, deny(warnings))]
104#![cfg_attr(not(any(feature = "std", test)), no_std)]
105// Jeremy Francis Corbyn, clippy devs need to calm down 🤦♀️
106#![allow(clippy::suspicious_op_assign_impl, clippy::suspicious_arithmetic_impl)]
107
108pub mod inline_array;
109pub mod sized_chunk;
110pub mod sparse_chunk;
111
112#[cfg(test)]
113mod tests;
114
115#[cfg(feature = "arbitrary")]
116mod arbitrary;
117
118pub use crate::inline_array::InlineArray;
119pub use crate::sized_chunk::Chunk;
120pub use crate::sparse_chunk::SparseChunk;
121
122#[cfg(feature = "ringbuffer")]
123pub mod ring_buffer;
124#[cfg(feature = "ringbuffer")]
125pub use crate::ring_buffer::RingBuffer;