Crate flatk[][src]

Expand description

Flat layout abstraction toolkit.

This library defines low level primitives for organizing flat ordered data collections (like Vecs and slices) into meaningful structures without cloning the data.

More specifically, flatk provides a few core composable types intended for building more complex data structures out of existing data:

  • UniChunked: Subdivides a collection into a number of uniformly sized (at compile time or run-time) contiguous chunks. For example if we have a Vec of floats representing 3D positions, we may wish to interpret them as triplets:

    use flatk::Chunked3;
    
    let pos_data = vec![0.0, 0.0, 0.0, 1.0, 1.0, 1.0, 0.0, 1.0, 0.0];
    
    let pos = Chunked3::from_flat(pos_data);
    
    assert_eq!(pos[0], [0.0; 3]);
    assert_eq!(pos[1], [1.0; 3]);
    assert_eq!(pos[2], [0.0, 1.0, 0.0]);

    For dynamically determined chunks sizes, the type alias ChunkedN can be used instead. The previous example can then be reproduced as:

    use flatk::ChunkedN;
    
    let pos_data = vec![0.0, 0.0, 0.0, 1.0, 1.0, 1.0, 0.0, 1.0, 0.0];
    
    let pos = ChunkedN::from_flat_with_stride(3, pos_data);
    
    assert_eq!(pos[0], [0.0; 3]);
    assert_eq!(pos[1], [1.0; 3]);
    assert_eq!(pos[2], [0.0, 1.0, 0.0]);
  • Chunked: Subdivides a collection into a number of unstructured (non-uniformly sized) chunks. For example we may have a non-uniform grouping of nodes stored in a Vec, which can represent a directed graph:

    use flatk::Chunked;
     
    let neighbours = vec![1, 2, 0, 1, 0, 1, 2];
     
    let neigh = Chunked::from_sizes(vec![1,2,1,3], neighbours);
    
    assert_eq!(&neigh[0][..], &[1][..]);
    assert_eq!(&neigh[1][..], &[2, 0][..]);
    assert_eq!(&neigh[2][..], &[1][..]);
    assert_eq!(&neigh[3][..], &[0, 1, 2][..]);

    Here neigh defines the following graph:

    0<--->1<--->2
    ^     ^     ^
     \    |    /
      \   |   /
       \  |  /
        \ | /
         \|/
          3
  • Clumped: A hybrid between UniChunked and Chunked, this type aggregates references to uniformly spaced chunks where possible. This makes it preferable for collections with mostly uniformly spaced chunks.

    For example, polygons can be represented as indices into some global vertex array. Polygonal meshes are often made from a combination of triangles and quadrilaterals, so we can’t represent the vertex indices as a UniChunked vector, and it would be too wastefull to keep track of each chunk using a plain Chunked vector. Clumped, however, is perfect for this use case since it only stores an additional pair of offsets (usize integers) for each type of polygon. In code this may look like the following:

    use flatk::{Clumped, Get, View};
     
    // Indices into some vertex array (depicted below): 6 triangles followed by 2 quadrilaterals.
    let indices = vec![0,1,2, 2,1,3, 7,1,0, 3,5,10, 9,8,7, 4,6,5, 7,8,4,1, 1,4,5,3];
     
    let polys = Clumped::from_sizes_and_counts(vec![3,4], vec![6,2], indices);
    let polys_view = polys.view();
    
    assert_eq!(&polys_view.at(0)[..], &[0,1,2][..]);
    assert_eq!(&polys_view.at(1)[..], &[2,1,3][..]);
    assert_eq!(&polys_view.at(2)[..], &[7,1,0][..]);
    assert_eq!(&polys_view.at(3)[..], &[3,5,10][..]);
    assert_eq!(&polys_view.at(4)[..], &[9,8,7][..]);
    assert_eq!(&polys_view.at(5)[..], &[4,6,5][..]);
    assert_eq!(&polys_view.at(6)[..], &[7,8,4,1][..]);
    assert_eq!(&polys_view.at(7)[..], &[1,4,5,3][..]);

    These polygons could represent a mesh like below, where each number corresponds to a vertex index.

    0 ---- 2 ---- 3 --10
    |\     |     / \  |
    | \    |    /   \ |
    |  \   |   /     \|
    |   \  |  /       5
    |    \ | /       /|
    |     \|/       / |
    7 ---- 1       /  |
    |\      \     /   |
    | \      \   /    |
    |  \      \ /     |
    9 - 8 ---- 4 ---- 6
  • Select: An ordered selection (with replacement) of elements from a given random access collection. This is usually realized with a Vec<usize> representing indices into the original data collection.

    For example one may wish to select game pieces in a board game:

    use flatk::Select;
     
    let pieces = vec!["Pawn", "Knight", "Bishop", "Rook", "Queen", "King"];
     
    let white_pieces = Select::new(vec![3, 1, 2, 5, 4, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0], pieces.as_slice());
    let black_pieces = Select::new(vec![0, 0, 0, 0, 0, 0, 0, 0, 3, 1, 2, 5, 4, 2, 1, 3], pieces.as_slice());
    
    assert_eq!(white_pieces[0], "Rook");
    assert_eq!(white_pieces[4], "Queen");
    assert_eq!(black_pieces[0], "Pawn");
    assert_eq!(black_pieces[11], "King");
  • Subset: Similar to Select but Subset enforces an unordered selection without replacement.

    For example we can choose a hand from a deck of cards:

    use flatk::{Subset, Get, View};
    
    let rank = vec!["Ace", "2", "3", "4", "5", "6", "7", "8", "9", "10", "Jack", "Queen", "King"];
    let suit = vec!["Clubs", "Diamonds", "Hearts", "Spades"];
    
    // Natural handling of structure of arrays (SoA) style data.
    let deck: (Vec<_>, Vec<_>) = (
        rank.into_iter().cycle().take(52).collect(),
        suit.into_iter().cycle().take(52).collect()
    );
    
    let hand = Subset::from_indices(vec![4, 19, 23, 1, 0, 5], deck);
    let hand_view = hand.view();
    assert_eq!(hand_view.at(0), (&"Ace", &"Clubs"));
    assert_eq!(hand_view.at(1), (&"2", &"Diamonds"));
    assert_eq!(hand_view.at(2), (&"5", &"Clubs"));
    assert_eq!(hand_view.at(3), (&"6", &"Diamonds"));
    assert_eq!(hand_view.at(4), (&"7", &"Spades"));
    assert_eq!(hand_view.at(5), (&"Jack", &"Spades"));
  • Sparse: A sparse data assignment to another collection. Effectively this type attaches another data set to a Selection. See Sparse for examples.

Indexing

Due to the nature of type composition and the indexing mechanism in Rust, it is not always possible to use the Index and IndexMut traits for indexing into the flatk collection types. To facilitate indexing, flatk defines two traits for indexing: Get and Isolate, which fill the roles of Index and IndexMut respectively. These traits work mainly on viewed collections (what is returned by calling .view() and .view_mut()). Isolate can also work with collections that own their data, however it is not recommended since methods provided by Isolate are destructive (they consume self).

Modules

Type aliases for many constants.

Macros

A simple macro constructing U# types given an expression.

Zip multiple iterators.

Structs

A partitioning of the collection S into distinct chunks.

A special iterator capable of iterating over a Chunked type.

A generic version of the Chunks iterator used by slices. This is used by uniformly (but not statically) chunked collections.

A collection of clumped offsets into another collection.

Iterator over ranges of offset values.

An iterator over offset values.

A collection of offsets into another collection. This newtype is intended to verify basic invariants about offsets into another collection, namely that the collection is monotonically increasing and non-empty.

Iterator over ranges of offsets.

A Set that is a non-contiguous, unordered and possibly duplicated selection of some larger collection. S can be any borrowed collection type that implements Set. Note that it doesn’t make much sense to have a Select type own the data that it selects from, although it’s possible to create one.

A Sparse data set S where the sparsity pattern is given by I as select indices into a larger range.

A type of range whose size is determined at compile time. This represents a range [start..start + N::value()]. This aids UniChunked types when indexing.

A wraper for a zip iterator that unwraps its contents into a custom struct.

A Set that is a non-contiguous subset of some larger collection. B can be any borrowed collection type that implements the Set, and RemovePrefix traits. For iteration of subsets, the underlying type must also implement SplitFirst and SplitAt traits.

Wrapper around typenum types to prevent downstream trait implementations.

Iterator over offset value and size pairs representing unclumped chunks.

Iterator over offsets and size pairs representing unclumped chunks.

Iterator over unclumped chunk sizes.

UniChunked Assigns a stride N to the specified collection.

Generic static sized chunk iterater appropriate for any lightweight view type collection.

IntoIter for Chunked.

Enums

Traits

A wrapper trait for sequences of immutable indices.

A wrapper trait for sequences of mutable indices.

A definition of a bounded range.

This trait is used to produce the chunk size of a collection if it contains uniformly chunked elements.

Clone self into a potentially different collection.

Clone the structure of a set replacing its storage with a new one.

A helper trait for constructing placeholder sets for use in std::mem::replace.

A marker trait to identify types whose range indices give a dynamically sized type even if the range index is given as a StaticRange.

An index trait for collection types. Here 'i indicates the lifetime of the input while 'o indicates that of the output.

A helper trait analogous to SliceIndex from the standard library.

Manipulate a non-empty collection of offsets.

A helper trait to identify valid types for Range bounds for use as Sets.

This trait generalizes the method chunks available on slices in the standard library. Collections that can be chunked by a runtime stride should implement this behaviour such that they can be composed with ChunkedN types.

An analog to the ToOwned trait from std that works for chunked views. As the name suggests, this version of ToOwned takes self by value.

In contrast to IntoOwned, this trait produces a clone with owned data, but potentially borrowed structure of the collection.

Parallel version of IntoChunkIterator.

Iterate over chunks whose size is determined at compile time.

Convert a collection into its underlying representation, effectively stripping any organizational info.

Since we cannot alias mutable references, in order to index a mutable view of elements, we must consume the original mutable reference. Since we can’t use slices for general composable collections, its impossible to match against a &mut self in the getter function to be able to use it with owned collections, so we opt to have an interface that is designed specifically for mutably borrowed collections. For composable collections, this is better described by a subview operator, which is precisely what this trait represents. Incidentally this can also work for owned collections, which is why it’s called Isolate instead of SubView.

A helper trait like GetIndex but for Isolate types.

Map the storage type into another given a conversion function.

Abstraction for pushing elements of type T onto a collection.

A helper trait used to help implement the Subset. This trait allows abstract collections to remove a number of elements from the beginning, which is what we need for subsets.

A trait that allows the container to allocate additional space without changing any of the data. The container should allocate space for at least n additional elements.

A trait defining a raw buffer of data. This data is typed but not annotated so it can represent anything. For example a buffer of floats can represent a set of vertex colours or vertex positions.

A helper trait to split a set into two sets at a given index. This trait is used to implement iteration over ChunkedViews.

Split out the first element of a collection.

A helper trait to split owned sets into two sets at a given index. This trait is used to implement iteration over Chunkeds.

Split off a number of elements from the beginning of the collection where the number is determined at compile time.

A marker trait to indicate a collection type that can be chunked. More precisely this is a type that can be composed with types in this crate.

Get an immutable reference to the underlying storage type.

Convert the storage type into another using the Into trait.

Get a mutable reference to the underlying storage type.

Truncate the collection to be a specified length.

An iterator whose items are random-accessible efficiently

A trait intended to be implemented on collection types to define the type of a statically sized chunk in this collection. This trait is required for composing with UniChunked.

The marker trait for compile time unsigned integers.

A marker trait to indicate an owned collection type. This is to distinguish them from borrowed types, which is essential to resolve implementation collisions.

A trait defining a collection that can be accessed via an immutable (shared) view. This type of view can be cloned and copied.

A convenience trait to allow generic implementations to call an iterator over the view. This is necessary because the View trait has an explicit lifetime parameter, which makes it difficult or impossible to use in generic functions. For instance it becomes difficult/impossible to impose constraints like Set on View::Type.

A trait defining a collection that can be accessed via a mutable (unique) view.

A marker trait to indicate a viewed collection type. Note that collections can be partially viewed, but only completely viewed collections are marked by Viewed.

Type Definitions

Define aliases for common uniform chunked types.

Clumped is a variation of Chunked that compactly represents equidistant offsets as “clumps”, hence the name.

A view of a Clumped collection.

A borrowed selection.

A borrowed view of a sparse collection.

A borrowed subset.

Derive Macros