2 releases

0.0.1 Jun 20, 2024
0.0.0 May 2, 2024

#10 in #matter

MIT/Apache

41KB
716 lines

Blok logo

Traits for graphlike 3D arrays. (Work in progress.)

How it works

Blok can be used to build arrays of "blocks". It can also be used to define the relationships between different blocks, by using "connections" to procedurally link their properties.

  1. Add blok to your project:
$ cargo add blok
use blok::{ Block, Stack, Layout, layout, Alignment, connect::* };
  1. Define a Block type. This is the element/particle for the matrix.
/// Simple implementation of a Block type.
#[derive(Clone)]
struct MyBlock {
    /// Data for block.
    data: String,
    /// Store "connections" as a collection of data from other blocks.
    connections: Vec<String>
} impl MyBlock {
    /// How u maek blok.
    fn new(data: &String) -> Self {
        MyBlock { data: data.to_owned(), connections: Vec::new() }
    }
}
impl Block for MyBlock {

    /// Encapsulate any arguments for the constructor into a single type.
    type ConstructionInstructions = String;
    /// Boilerplate, sorry.
    type Constructor = fn(&String) -> Self;
    /// Encapsulate any arguments for the connector into a single type.
    type ConnectionInstructions = ();

    /// Define the constructor for a non-data "void" block (placeholders & spacers).
    fn void() -> Self {
        MyBlock {
            data: String::new(),
            connections: Vec::new()
        }
    }

    /// Define the test to check for "void" blocks (placeholders & spacers).
    fn is_void(&self) -> bool {
        match self.data.as_str() {
            "" => true,
            _ => false
        }
    }

    /// Define the block-to-block connection procedure.
    fn connect(&mut self, other: &mut Self, _instr: &()) {
        self.connections.push(other.data.clone())
    }
}
  1. Define a Stack type (a 3-D array of Blocks).
/// Stack type represents a matrix of Blocks.
#[derive(Clone)]
struct MyStack {
    /// Stores the shape of the matrix as vectors of layer row lengths.
    layouts: Vec<Layout>,
    /// Stores the actual blocks together in memory.
    blocks: Vec<MyBlock>
}
impl Stack<MyBlock> for MyStack {
    /// Define the default constructor within the Stack implementation.
    fn new() -> Self {
        MyStack { layouts: vec![], blocks: vec![] }
    }

    // Boilerplate. "Derive" macro TBD.
    fn layouts(&self) -> &Vec<Layout> { &self.layouts }
    fn layouts_mut(&mut self) -> &mut Vec<Layout> { &mut self.layouts }
    fn blocks(&self) -> &Vec<MyBlock> { &self.blocks }
    fn blocks_mut(&mut self) -> &mut Vec<MyBlock> { &mut self.blocks }
}
  1. Build a Stack from Layers of Blocks.
fn main() {
    let mut pyramid = MyStack::new();
    let mut bottom = Layer::new();
    bottom.populate_with_clones(layout![3; 3], &MyBlock::new(&"bottom".to_string()));
    pyramid.stack(bottom);

    let mut middle = Layer::new();
    middle.populate_with_clones(layout![2; 2], &MyBlock::new(&"middle".to_string()));
    pyramid.stack(middle);

    let mut top = Layer::new();
    top.add_block(MyBlock::new(&"top".to_string()));
    pyramid.stack(top);

    ...

  1. Connect the Stack to make its Blocks aware of one another.
    ...

    connect::autoconnect_stack_uniformly(&mut pyramid, Alignment::dense, vec![(); 10]);

    // Do something with the connected pyramid.
}

Future directions

I'm developing this crate to support another project I am working on, and decided to split it off since it could be used more generally and may come in handy elsewhere.
Current tasks can be tracked in TODO.md.

Dependencies

~0.8–1.5MB
~30K SLoC