Macro v11::table[][src]

macro_rules! table {
    (
        $(#[$meta:meta])*
        [$domain:ident/$name:ident]
        $($args:tt)*
    ) => { ... };
    (
        $(#[$meta:meta])*
        pub [$domain:ident/$name:ident]
        $($args:tt)*
    ) => { ... };
}

This macro generates a column-based data table. (It is currently implemented using the procedural-masquerade hack.)

The general syntax for this macro is

table! {
    #[kind = "…"]
    // table attributes can go here
    pub [DOMAIN/name_of_table] {
        // column attributes can go here
        column_name_1: [Element1; ColumnType1],
        column_name_2: [Element2; ColumnType2],
        column_name_3: [Element3; ColumnType3],
        // …
    }
}

where each ColumnType is a TCol, and Element is a Storable <ColumnType as TCol>::Element.

pub can be elided for a private table.

DOMAIN is specified using the domain! macro.

Here are some example columns:

  • [i32; VecCol<i32>] (a column implemented with Vec<i32>)
  • [u8; SegCol<u8>] (a column of u8 stored in non-contiguous chunks)
  • [bool; BoolCol] (a column specialized for single bit storage)

(As a special convenience, VecCol, SegCol, and BoolCol are automatically used by the macro.)

Table and column names must be valid Rust identifiers that also match the regex [A-Za-z][A-Za-z_0-9]*.

Column elements must implement Storable. Column types must implement TCol.

It is recommended that the table name be plural and the column name be singular, eg in customers.name[id].

Using the Table


// Create a new domain. This is a single-level namespace
domain! { MY_DOMAIN }

// Generate code for a table.
table! {
    #[kind = "append"]
    pub [MY_DOMAIN/my_table] {
        my_int: [i32; VecCol<i32>],
    }
}

fn main() {
    // Every domain, table, and property should be registered
    // before creating the Universe.
    MY_DOMAIN::register();
    my_table::register();

    // Every member of MY_DOMAIN is initialized at this point.
    // The universe owns a `RwLock` for each table & property.
    let universe = &Universe::new(&[MY_DOMAIN]);

    // Lock the table for writing.
    let mut my_table = my_table::write(universe);
    my_table.push(my_table::Row {
        my_int: 42,
    });
}

Table kinds, Consistency, and Guarantees

The 'kind' of a table selects what functions are generated and what guarantees are upheld.

#[kind = "append"]

This is the simplest kind. Rows in an "append" table can not be removed. Consistency is thus trivially guaranteed.

#[kind = "sorted"]

Guarantees the table is sorted. You must implement Ord for $table::RowRef. If you put #[sort_key] on a column, it will do this for you. (The macro derives Eq, PartialEq, and PartialOrd on $table::RowRef, and those + Ord on $table::Row)

Rows can be added with merge, and removed with retain.

Sorted tables are good for joincore.

#[kind = "consistent"]

Rows in consistent tables can be used as foreign keys in other tables. The main guarantee of the public table is that it is kept consistent with such tables: the main row and references to it are deleted as a unit.

Since maintaining consistency requires locking other tables, you must call table.flush(universe, event) instead of letting the table drop.

#[kind = "bag"]

NYI. (Row order would be arbitrary and there would be no consistency guarantee.)

#[kind = "list"]

NYI. (Row order would remain intact, but there would be no consistency guarantee.)

#[kind = "indirect"]

NYI. (There would be a table of handles introducing a layer of indirection, but making it easy to implement certain guarantees.)

Using the generated table

A lock on the table must be obtained using $tablename::read(universe).

(FIXME: Link to v11::example)

Table Attributes

This works like so:

table! {
    #[kind = "…"]
    #[table_attribute_1]
    #[table_attribute_2]
    [DOMAIN/table] {
        …
    }
}

#[row_id = "usize"]

Sets what the (underlying) primitive is used for indexing the table. The default is usize. This is useful when this table is going to have foreign keys pointing at it.

#[row_derive(Foo, Bar)]

Puts #[derive(Foo, Bar)] on the generated Row and RowRef structs.

#[version = "0"]

A version number for the table. The default is 0. It is a u32.

#[add_tracker = "expression"]

Register a user tracker automatically when the table is initialized using the given expression. For example, #[add_tracker = "BirdWatch"]. You would then need to define BirdWatch and implement tracking::Tracker on it.

Can be repeated. The trackers from #[foreign] and #[foreign_auto] take care of themselves; using this on the trackers they define would duplicate it.

Column Attributes

table! {
    #[kind = "…"]
    pub [MY_DOMAIN/my_table] {
        #[column_attribute_1]
        #[column_attribute_2]
        my_int: [i32; VecCol<i32>],
    }
}

#[foreign]

The row's element must be another table's RowId. This generates a struct track_$COL_events, for which Tracker must be implemented, to react to structural events on the foreign table.

#[foreign_auto]

This automatically implements Tracker. Rows corresponding to deleted foreign rows will be removed. This requires #[index] or #[sort_key] on the local column.

#[index]

Creates an index of the column, using a BTreeMap. Indexed elements are immutable, and are duplicated.

#[sort_key]

Use the element's comparision order to derive Ord for RowRef.

Debugging Macro Output

If there is an error in the macro's output, it will give opaque errors and thus be impossible to debug... UNTIL NOW! Simply define the V11_MACRO_DUMP=* environment variable prior to compilation, and ALL table! macro output will be written to & loaded from a convenient file!! You can also obtain the output of a specific table using its name, like V11_MACRO_DUMP=hayo! V11_MACRO_DUMP_DIR can be used to write files to a specific directory! If you don't specify this environmental variable, that's OKAY, files are written to target/v11_dump by default!! It doesn't get ANY EASIER than HAYO-Corp!!!!

* Do not use if any separate tables have the same domain & name. Such duplicate table names may result in explosions. Do not compile multiple profiles with this feature enabled. Simultaneous cargo/rustc invokations are unsupported, and may result in explosions.

HAYO-Corp is not liable for any loss of life, liberty, property, or data consistency due to misuse of V11_MACRO_DUMP.