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`] and [`IndexMatrix`] are generic with respect to two things:
7//! 1. **The choice of bit-set implementation.** By default, Indexical includes the [`bitvec`] crate and provides the [`bitset::bitvec::IndexSet`] type.
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, unchecked_shifts))]
14#![cfg_attr(docsrs, feature(doc_auto_cfg))]
15#![warn(missing_docs)]
16
17use self::pointer::PointerFamily;
18use index_vec::Idx;
19use std::hash::Hash;
20
21pub mod bitset;
22mod domain;
23pub mod map;
24mod matrix;
25pub mod pointer;
26mod set;
27#[cfg(test)]
28mod test_utils;
29pub mod vec;
30
31#[doc(hidden)]
32pub use index_vec as _index_vec;
33
34pub use domain::IndexedDomain;
35pub use matrix::IndexMatrix;
36pub use set::IndexSet;
37
38/// Coherence hack for the `ToIndex` trait.
39pub struct MarkerOwned;
40/// Coherence hack for the `ToIndex` trait.
41pub struct MarkerRef;
42/// Coherence hack for the `ToIndex` trait.
43pub struct MarkerIndex;
44
45/// Implicit conversions from elements to indexes.
46/// Commonly used in the [`IndexSet`] and [`IndexMatrix`] interfaces.
47///
48/// Note that we cannot use the [`Into`] trait because this conversion requires
49/// the [`IndexedDomain`] as input.
50///
51/// The `M` type parameter is a coherence hack to ensure the two blanket implementations
52/// do not conflict.
53pub trait ToIndex<T: IndexedValue, M> {
54    /// Converts `self` to an index over `T`.
55    fn to_index(self, domain: &IndexedDomain<T>) -> T::Index;
56}
57
58impl<T: IndexedValue> ToIndex<T, MarkerOwned> for T {
59    fn to_index(self, domain: &IndexedDomain<T>) -> T::Index {
60        domain.index(&self)
61    }
62}
63
64impl<T: IndexedValue> ToIndex<T, MarkerRef> for &T {
65    fn to_index(self, domain: &IndexedDomain<T>) -> T::Index {
66        domain.index(self)
67    }
68}
69
70impl<T: IndexedValue> ToIndex<T, MarkerIndex> for T::Index {
71    fn to_index(self, _domain: &IndexedDomain<T>) -> T::Index {
72        self
73    }
74}
75
76/// Links a type to its index.
77///
78/// Should be automatically implemented by the [`define_index_type`] macro.
79pub trait IndexedValue: Clone + PartialEq + Eq + Hash {
80    /// The index for `Self`.
81    type Index: Idx;
82}
83
84/// Creates a new index type and associates it with an object type.
85///
86/// This is a thin wrapper around [`index_vec::define_index_type`]. The only
87/// modification is the `for $TYPE` syntax that generates the [`IndexedValue`]
88/// implementation.
89#[macro_export]
90macro_rules! define_index_type {
91  (
92    $(#[$attrs:meta])*
93    $v:vis struct $type:ident for $target:ident $(<$($l:lifetime),*>)? = $raw:ident;
94    $($CONFIG_NAME:ident = $value:expr;)* $(;)?
95  ) => {
96    $crate::_index_vec::define_index_type! {
97      $(#[$attrs])*
98      $v struct $type = $raw;
99      $($CONFIG_NAME = $value;)*
100    }
101
102    impl $(<$($l),*>)? $crate::IndexedValue for $target $(<$($l),*>)? {
103      type Index = $type;
104    }
105  }
106}
107
108/// Generic interface for converting iterators into indexical collections.
109pub trait FromIndexicalIterator<'a, T: IndexedValue + 'a, P: PointerFamily<'a>, M, A>:
110    Sized
111{
112    /// Converts an iterator into a collection within the given domain.
113    fn from_indexical_iter(
114        iter: impl Iterator<Item = A>,
115        domain: &P::Pointer<IndexedDomain<T>>,
116    ) -> Self;
117}
118
119/// Extension trait that adds `collect_indexical` to all iterators.
120pub trait IndexicalIteratorExt<'a, T: IndexedValue + 'a, P: PointerFamily<'a>, M>:
121    Iterator + Sized
122{
123    /// Like [`Iterator::collect`], except also takes as input a `domain`.
124    fn collect_indexical<B>(self, domain: &P::Pointer<IndexedDomain<T>>) -> B
125    where
126        B: FromIndexicalIterator<'a, T, P, M, Self::Item>,
127    {
128        FromIndexicalIterator::from_indexical_iter(self, domain)
129    }
130}
131
132impl<'a, I: Iterator, T: IndexedValue + 'a, P: PointerFamily<'a>, M>
133    IndexicalIteratorExt<'a, T, P, M> for I
134{
135}