Skip to main content

indexical/
lib.rs

1#![doc = include_str!("../README.md")]
2//! ## Design
3//! The key idea is that the [`IndexedDomain`] is shared pervasively
4//! across all Indexical types. All types can then use the [`IndexedDomain`] to convert between indexes and objects, usually via the [`ToIndex`] trait.
5//!
6//! [`IndexSet`](set::IndexSet) and [`IndexMatrix`](matrix::IndexMatrix) are generic with respect to two things:
7//! 1. **The choice of bit-set implementation.** By default, Indexical includes the [`bitvec`] crate and re-exports the [`bitset::bitvec`] module from root.
8//!    You can provide your own bit-set implementation via the [`bitset::BitSet`] trait.
9//! 2. **The choice of domain pointer.** By default, Indexical uses the [`Rc`](std::rc::Rc) pointer via the [`RcFamily`](pointer::RcFamily) type.
10//!    You can choose to use the [`ArcFamily`](pointer::ArcFamily) if you need concurrency, or the [`RefFamily`](pointer::RefFamily) if you want to avoid reference-counting.
11
12#![cfg_attr(feature = "rustc", feature(rustc_private))]
13#![cfg_attr(feature = "simd", feature(portable_simd))]
14#![warn(missing_docs, clippy::pedantic)]
15
16use self::pointer::PointerFamily;
17use index_vec::Idx;
18use std::hash::Hash;
19
20pub mod bitset;
21mod domain;
22pub mod map;
23pub mod matrix;
24pub mod pointer;
25pub mod set;
26#[cfg(test)]
27mod test_utils;
28pub mod vec;
29
30#[doc(hidden)]
31pub use index_vec as _index_vec;
32
33#[cfg(all(
34    feature = "bitvec",
35    not(any(feature = "rustc", feature = "simd", feature = "roaring"))
36))]
37pub use bitset::bitvec::{
38    ArcIndexMatrix, ArcIndexSet, RcIndexMatrix, RcIndexSet, RefIndexMatrix, RefIndexSet,
39};
40#[cfg(all(
41    feature = "roaring",
42    not(any(feature = "rustc", feature = "simd", feature = "bitvec"))
43))]
44pub use bitset::roaring::{
45    ArcIndexMatrix, ArcIndexSet, RcIndexMatrix, RcIndexSet, RefIndexMatrix, RefIndexSet,
46};
47#[cfg(all(
48    feature = "rustc",
49    not(any(feature = "bitvec", feature = "simd", feature = "roaring"))
50))]
51pub use bitset::rustc::{
52    ArcIndexMatrix, ArcIndexSet, RcIndexMatrix, RcIndexSet, RefIndexMatrix, RefIndexSet,
53};
54#[cfg(all(
55    feature = "simd",
56    not(any(feature = "bitvec", feature = "rustc", feature = "roaring"))
57))]
58pub use bitset::simd::{
59    ArcIndexMatrix, ArcIndexSet, RcIndexMatrix, RcIndexSet, RefIndexMatrix, RefIndexSet,
60};
61
62pub use domain::IndexedDomain;
63pub use vec::{ArcIndexVec, RcIndexVec, RefIndexVec};
64
65/// Coherence hack for the `ToIndex` trait.
66pub struct MarkerOwned;
67/// Coherence hack for the `ToIndex` trait.
68pub struct MarkerRef;
69/// Coherence hack for the `ToIndex` trait.
70pub struct MarkerIndex;
71
72/// Implicit conversions from elements to indexes.
73/// Commonly used in the [`IndexSet`](set::IndexSet) and [`IndexMatrix`](matrix::IndexMatrix) interfaces.
74///
75/// Note that we cannot use the [`Into`] trait because this conversion requires
76/// the [`IndexedDomain`] as input.
77///
78/// The `M` type parameter is a coherence hack to ensure the blanket implementations
79/// do not conflict.
80pub trait ToIndex<T: IndexedValue, M> {
81    /// Converts `self` to an index over `T`.
82    fn to_index(self, domain: &IndexedDomain<T>) -> T::Index;
83}
84
85impl<T: IndexedValue> ToIndex<T, MarkerOwned> for T {
86    fn to_index(self, domain: &IndexedDomain<T>) -> T::Index {
87        domain.index(&self)
88    }
89}
90
91impl<T: IndexedValue> ToIndex<T, MarkerRef> for &T {
92    fn to_index(self, domain: &IndexedDomain<T>) -> T::Index {
93        domain.index(self)
94    }
95}
96
97impl<T: IndexedValue> ToIndex<T, MarkerIndex> for T::Index {
98    fn to_index(self, _domain: &IndexedDomain<T>) -> T::Index {
99        self
100    }
101}
102
103/// Links a type to its index.
104///
105/// Should be automatically implemented by the [`define_index_type`] macro.
106pub trait IndexedValue: Clone + PartialEq + Eq + Hash {
107    /// The index for `Self`.
108    type Index: Idx;
109}
110
111/// Creates a new index type and associates it with an object type.
112///
113/// This is a thin wrapper around [`index_vec::define_index_type`]. The only
114/// modification is the `for $TYPE` syntax that generates the [`IndexedValue`]
115/// implementation.
116#[macro_export]
117macro_rules! define_index_type {
118  (
119    $(#[$attrs:meta])*
120    $v:vis struct $type:ident for $target:ident $(<$($l:lifetime),*>)? = $raw:ident;
121    $($CONFIG_NAME:ident = $value:expr;)* $(;)?
122  ) => {
123    $crate::_index_vec::define_index_type! {
124      $(#[$attrs])*
125      $v struct $type = $raw;
126      $($CONFIG_NAME = $value;)*
127    }
128
129    impl $(<$($l),*>)? $crate::IndexedValue for $target $(<$($l),*>)? {
130      type Index = $type;
131    }
132  }
133}
134
135/// Generic interface for converting iterators into indexical collections.
136pub trait FromIndexicalIterator<'a, T: IndexedValue + 'a, P: PointerFamily<'a>, M, A>:
137    Sized
138{
139    /// Converts an iterator into a collection within the given domain.
140    fn from_indexical_iter(
141        iter: impl Iterator<Item = A>,
142        domain: &P::Pointer<IndexedDomain<T>>,
143    ) -> Self;
144}
145
146/// Extension trait that adds `collect_indexical` to all iterators.
147pub trait IndexicalIteratorExt<'a, T: IndexedValue + 'a, P: PointerFamily<'a>, M>:
148    Iterator + Sized
149{
150    /// Like [`Iterator::collect`], except also takes as input a `domain`.
151    fn collect_indexical<B>(self, domain: &P::Pointer<IndexedDomain<T>>) -> B
152    where
153        B: FromIndexicalIterator<'a, T, P, M, Self::Item>,
154    {
155        FromIndexicalIterator::from_indexical_iter(self, domain)
156    }
157}
158
159impl<'a, I: Iterator, T: IndexedValue + 'a, P: PointerFamily<'a>, M>
160    IndexicalIteratorExt<'a, T, P, M> for I
161{
162}