pipecircuit 0.0.18

Correct. Robust. Fast. Portable. Pick four.
Documentation
//! [`WarpTable`]: bounded, primary-indexed columnar storage.
//!
//! [`WarpTable`] reserves its declared capacity at construction, stores each
//! row field in an aligned dense column, and keeps primary lookup synchronized
//! with swap-remove relocation. [`WarpTableRow`] derives that physical storage
//! from an ordinary logical row type. Unless a caller-owned primary type is
//! declared, insertion returns a generated [`WarpId<Row>`].
//! An identity-only collection may derive [`WarpTableRow`] for an empty named
//! struct. It retains the primary ID and dense index without allocating a
//! placeholder column.
//!
//! Fields marked `#[index(secondary)]` receive independent equality indexes;
//! fields marked `#[index(range)]` receive bit-sliced numeric range indexes.
//! Both may be declared on one field. Lookups return opaque `Selection`
//! values. Selections compose before row access, so unions, intersections,
//! exclusions, and unions excluding overlap neither scan nor copy logical
//! rows. Calling `Selection::rows` resolves the final membership into flat
//! generated row references containing `id` beside every field declared by
//! the logical row.
//!
//! The optional `Brand` parameter names one stable-membership universe. The
//! row type is the convenient default; distinct stores of the same row type
//! can supply distinct zero-sized brands so Rust rejects cross-store algebra.
//!
//! Opt-in [`observed`] storage maintains owned projections for remote full
//! copies, filtered readers, and counts, with bounded coalescing and replicas.
//! Unobserved tables retain their ordinary storage and mutation surface.
//!
//! # Example
//!
//! ```
//! # #[cfg(feature = "secondary-indexes")]
//! # mod example {
//! use core::num::NonZeroU32;
//! use pipecircuit::storage::warp_table::{
//!     Capacity, WarpTableRow, WarpTable, WarpTableInsertOutcome,
//!     MutableSelectionForEachOutcome,
//! };
//!
//! #[derive(WarpTableRow)]
//! struct Pet {
//!     name: &'static str,
//!     #[index(secondary, range)]
//!     age: u8,
//!     #[index(secondary)]
//!     species: u8,
//! }
//!
//! enum Shelter {}
//!
//! # pub fn run() -> Result<(), &'static str> {
//! let Some(maximum_rows) = NonZeroU32::new(3) else {
//!     return Err("zero capacity");
//! };
//! let capacity = Capacity::new(maximum_rows);
//! let Ok(mut pets) = WarpTable::<Pet, Shelter>::try_new(capacity) else {
//!     return Err("pet storage unavailable");
//! };
//!
//! let WarpTableInsertOutcome::Inserted { id: luna_id, .. } =
//!     pets.insert(Pet { name: "Luna", age: 5, species: 1 }) else {
//!     return Err("Luna could not be inserted");
//! };
//! let WarpTableInsertOutcome::Inserted { .. } =
//!     pets.insert(Pet { name: "Milo", age: 5, species: 2 }) else {
//!     return Err("Milo could not be inserted");
//! };
//! let WarpTableInsertOutcome::Inserted { .. } =
//!     pets.insert(Pet { name: "Suki", age: 7, species: 1 }) else {
//!     return Err("Suki could not be inserted");
//! };
//!
//! let documented_ages = pets.query().find_age(5)
//!     .or(|q| q.find_age(7));
//! let school_age_cats = pets.query().find_age_in(5..=7)
//!     .map_err(|_| "age range index inconsistent")?
//!     .and(|q| q.find_species(1));
//! let five_year_old_cats = pets.query().find_species(1)
//!     .and(|q| q.find_age(5));
//! let five_year_old_non_dogs = pets.query().find_age(5)
//!     .and_not(|q| q.find_species(2));
//! let cats_or_five_year_olds_but_not_both = pets.query().find_species(1)
//!     .xor(|q| q.find_age(5));
//! let cats = pets.query().find_species(1);
//! let dogs = pets.query().find_species(2);
//! assert_eq!(documented_ages.len(), 3);
//! assert_eq!(school_age_cats.len(), 2);
//! assert_eq!(five_year_old_cats.len(), 1);
//! assert_eq!(five_year_old_non_dogs.len(), 1);
//! assert_eq!(cats_or_five_year_olds_but_not_both.len(), 2);
//! assert!(cats.is_disjoint(&dogs));
//!
//! let mut matches = five_year_old_cats.rows();
//! let Some(pet) = matches.next() else {
//!     return Err("matching pet unavailable");
//! };
//! assert_eq!(*pet.id, luna_id);
//! assert_eq!((pet.name, pet.age, pet.species), (&"Luna", &5, &1));
//! assert!(matches.next().is_none());
//! assert_eq!(
//!     pets.query_mut().find_species(1)
//!         .and(|q| q.find_age(5))
//!         .for_each(|mut pet| {
//!             let _ = pet.set_age(8);
//!         }),
//!     MutableSelectionForEachOutcome::Updated { rows: 1 },
//! );
//! assert_eq!(pets.query().find_age(8).len(), 1);
//! # Ok(())
//! # }
//! # }
//! # #[cfg(feature = "secondary-indexes")]
//! # fn main() -> Result<(), &'static str> { example::run() }
//! # #[cfg(not(feature = "secondary-indexes"))]
//! # fn main() {}
//! ```

#[cfg(feature = "secondary-indexes")]
pub use pipecircuit_macros::RangeIndexKey;
pub use pipecircuit_macros::WarpTableRow;

#[doc(hidden)]
pub mod __private {
    pub use super::inconsistency::invariant_violation;
    #[cfg(feature = "secondary-indexes")]
    pub use super::query::{
        bind_detached_range_lookup, bind_detached_secondary_lookup, bind_every_row_ordering,
        bind_mutable_range_lookup, bind_mutable_secondary_lookup, bind_range_lookup,
        bind_range_ordering, bind_secondary_lookup, own_secondary_membership,
    };
    #[cfg(feature = "secondary-indexes")]
    pub use super::secondary_index::{
        PreparedRangeIndexInsert, PreparedRangeIndexMove, PreparedRangeIndexRemove,
        PreparedSecondaryIndexInsert, PreparedSecondaryIndexMove, PreparedSecondaryIndexRemove,
        PreparedSlotSetInsert, PreparedStableSlotInsert, PreparedStableSlotRemove, RangeIndex,
        RangeIndexCreationError, RangeIndexInconsistency, RangeIndexInsertError,
        RangeIndexInsertOutcome, RangeIndexMembership, RangeIndexMoveError, RangeIndexMoveOutcome,
        RangeIndexOrderingDirection, RangeIndexOrderingLevel, RangeIndexRemoveError,
        RangeIndexRemoveOutcome, SecondaryIndex, SecondaryIndexCommitRemoveOutcome,
        SecondaryIndexCreationError, SecondaryIndexInconsistency, SecondaryIndexInsertError,
        SecondaryIndexInsertOutcome, SecondaryIndexMembership, SecondaryIndexMoveError,
        SecondaryIndexMoveOutcome, SecondaryIndexPrepareRemoveOutcome, SecondaryIndexRemoveError,
        SecondaryIndexRemoveOutcome, SecondaryIndexRemoveResult, SlotSet, SlotSetInsertError,
        SlotSetInsertOutcome, SlotSetRemoveOutcome, SlotSetSlots, StableSlot,
        StableSlotInsertError, StableSlotRemoveOutcome, StableSlotResolutions,
        StableSlotResolveOutcome, StableSlotResolver, StableSlotRowRelocation, StableSlots,
        StableSlotsCreationError, StableSlotsInconsistency,
    };
    pub use super::unique_index::{
        PreparedUniqueIndexInsert, PreparedUniqueIndexRemove, PreparedUniqueIndexReplace,
        UniqueIndex, UniqueIndexInsertOutcome, UniqueIndexRemoveOutcome, UniqueIndexReplaceOutcome,
    };
    pub use super::update::{bind_unique_update, bind_unique_update_with};
    pub use alloc::{collections::TryReserveError, vec::Vec};
}

pub mod observed;

mod creation;
mod dense_key_index;
mod entry;
mod get;
mod id;
mod inconsistency;
mod insert;
mod query;
mod remove;
mod replace;
mod row;
mod rows;
#[cfg(feature = "secondary-indexes")]
mod secondary_index;
mod unique_index;
mod update;
mod upsert;

pub use creation::{Capacity, WarpTableCreationError};
use dense_key_index::DenseKeyIndex;
pub use entry::{WarpTableEntry, WarpTableVacantEntry, WarpTableVacantInsertOutcome};
pub use get::{WarpTableGetAtOutcome, WarpTableGetOutcome, WarpTableUniqueGetOutcome};
pub use id::{WarpId, integer_index_word, sequential_index_word};
pub use inconsistency::WarpTableInconsistency;
pub use insert::{WarpTableInsertAllOutcome, WarpTableInsertOutcome, WarpTableInsertWithIdOutcome};
#[cfg(feature = "secondary-indexes")]
#[doc(hidden)]
pub use query::SelectionOperand;
#[cfg(feature = "secondary-indexes")]
#[doc(hidden)]
pub use query::{
    DetachedRangeIndexLookupOutcome, DetachedSecondaryIndexLookupOutcome, DetachedSelection,
    MutableSelectionOperand,
};
#[cfg(feature = "secondary-indexes")]
pub use query::{
    MutableRangeIndexLookupOutcome, MutableSecondaryIndexLookupOutcome, MutableSelection,
    MutableSelectionForEachOutcome, MutableSelectionRemoveFirstOutcome, OrderedRowLimit,
    OrderedSelection, OrderedSelectionComparingRows, OrderedSelectionFirstCuttingTiesOutcome,
    OrderedSelectionFirstKeepingTiesOutcome, RangeIndexLookupOutcome, RangeIndexOrdering,
    SecondaryIndexLookupOutcome, Selection, SelectionMembershipInconsistency, SelectionRows,
};
pub use remove::{WarpTableRemoveOutcome, WarpTableRowRelocation};
pub use replace::WarpTableReplaceOutcome;
pub use row::{
    IndexKey, WarpTableRow, WarpTableRowGetError, WarpTableRowGetOutcome, WarpTableRowReplaceError,
    WarpTableRowReplaceOutcome,
};
pub use rows::WarpTableRows;
#[cfg(feature = "secondary-indexes")]
pub use secondary_index::SecondaryIndexInconsistency;
#[cfg(feature = "secondary-indexes")]
pub use secondary_index::{
    RangeIndexBounds, RangeIndexCreationError, RangeIndexInconsistency, RangeIndexInsertFailure,
    RangeIndexKey, RangeIndexLookupError, RangeIndexMoveFailure, RangeIndexOrderingError,
    RangeIndexRemoveFailure, SecondaryIndexInsertFailure, SecondaryIndexMoveFailure,
    SecondaryIndexRemoveFailure, StableMembershipInsertFailure,
};
pub use unique_index::{
    UniqueIndexCreationError, UniqueIndexInconsistency, UniqueIndexInsertError,
    UniqueIndexLookupError, UniqueIndexLookupOutcome, UniqueIndexRemoveError,
    UniqueIndexReplaceError,
};
pub use update::{
    WarpTableUniqueUpdateOutcome, WarpTableUniqueUpdateWithError, WarpTableUniqueUpdateWithOutcome,
    WarpTableUpdateOutcome, WarpTableUpdateWithOutcome,
};
pub use upsert::WarpTableUpsertOutcome;

pub mod persistent;

pub struct WarpTable<Row: WarpTableRow, Brand = Row> {
    capacity: Capacity,
    maximum_rows: usize,
    len: usize,
    next_id: Option<core::num::NonZeroU64>,
    ids: __private::Vec<Row::Id>,
    columns: Row::Columns,
    indexes: Row::Indexes,
    primary_index: DenseKeyIndex,
    brand: core::marker::PhantomData<fn() -> Brand>,
}

impl<Row: WarpTableRow, Brand> WarpTable<Row, Brand> {
    pub const fn capacity(&self) -> Capacity {
        self.capacity
    }

    pub const fn len(&self) -> usize {
        self.len
    }

    pub const fn is_empty(&self) -> bool {
        self.len == 0
    }

    pub fn ids(&self) -> &[Row::Id] {
        &self.ids
    }

    /// Borrows the physical columns for read-only, column-oriented traversal.
    ///
    /// Mutation remains behind indexed operations so an ID cannot be
    /// changed without keeping the index synchronized.
    pub const fn columns(&self) -> &Row::Columns {
        &self.columns
    }

    #[doc(hidden)]
    pub const fn __indexes(&self) -> &Row::Indexes {
        &self.indexes
    }
}

#[cfg(test)]
mod derive_tests;
#[cfg(test)]
mod tests;