viffy
viffy (vee-fee) is an Ergonomic SIMD library + automata generator for SoA databases.
Database generator
A small SoA database generator is also provided, there is basic support for some relational linkage between objects.
On your build.rs you can quickly implement the generator by adding viffy as a build-dependency:
Cargo.toml:
[build-dependencies]
viffy = { git = }
build.rs:
src/db.txt:
@global = {
seed = u32
}
CarType = {
@serde = scenario
@size = 4096
velocity = f32
speed = f32
traction = f32
}
src/db.rs:
include!;
src/main.rs:
Syntax
Object = {
<property> = <type>
}
Special properties can be defined with the @ prefix:
@size: Define the size (in integer quantities) of the object.@serde: Define the default serialization and deserialization target for this object (unless overriden in a given property).@relation: Define this as a relation as opposed to an object.@first: First object member of the relation, for exampleCountry.@firstName: Canonical name of the first member of the relation, for example,owner.@second: Second object member of the relation, for exampleProvince.@secondName: Canonical name of the second member of the relation, for example,province.@global: A group defined asglobalwill have it's members be accessed via theget_global_memberandset_global_memberfunctions. Only one member exists at a time, as opposed to the SoA paradigm present on other objects.@adjacency: Marks this group as an adjacency descriptor, only a triangular N by M matrix will be generated, no members shall be added to this group@adjType: The base type to use for this adjacency descriptor.@unilateral: Generate a relation that can be (i,j) != (j,i)@bilateral: Generate a relation such that (i,j) == (j,i)@erasable: Group is erasable as opposed to a fixed size, implementation uses a freelist to keep track of "dead" objects.
In the cases given above for @first and @second, we define something akin to a ProvinceOwnership relation, which has one possible key (first key), and many possible links (second key).
If the property name starts with [borrow], the functions will be generated such as the property is regarded to be more efficient being borrowed than being copied (such as arrays).
The generated world containers guarantee immutable access, that is, a &mut World isn't required to change a given property within the world, this property allows to independently modify containers, and - optionally, allow to use mutexes to detect data races in debug builds. It is also primordial to allow near-zero-cost reads and writes without compromising code readability.
The main functions for non-borrowed members:
set_object_property(&self, id: ObjectId, v: T);: Sets the given object, notice howWorlddoesn't need to be mutable.get_object_property(&self, id: ObjectId) -> T;: Gets the given objectfor_each_object(&self, f: F);: Iterate over all objects.for_each_mut_object(&self, f: F);: Iterate over all objects (mutably).parallel_for_each_object(&self, f: F);: Iterate over all objects but in parallel (usesRayon).ranged_parallel_for_each_object(&self, steps: usize, at_step: usize, f: F);: Iterate over all objects but only the ones in range, and divide them in pairs ofsteps, in parallel (usesRayon).vector_serial_for_each_object(&self, f: F);: Iterate over all objects, however, insert every one of them in serial, such as that the item list is populated with [n0, n0, n0, n0]vector_parallel_for_each_object(&self, f: F);: Iterate over all objects, however, insert every one of them in parallel, such as the item list is populated with [n0, n1, n2, n3]iter_object(&self);: Returns an iterator to all objects.parallel_iter_object(&self);: Returns a parallel iterator to all objects.
The main functions for borrowed members:
get_object_property<F>(&self, id: ObjectId, f: F) -> T;: Gets the given object, and performs a mutable operation upon it, becauseftakes a closure with a reference to said object.
Main functions of adjacencies:
pub fn set_province_adjacency_for_province(&self, id: ProvinceId, v: ProvinceId);: Set as adjacent.
pub fn clear_province_adjacency_for_province(&self, id: ProvinceId, v: ProvinceId);: Clear adjacency.
pub fn get_province_adjacency_for_province(&self, id: ProvinceId, v: ProvinceId) -> bool;: Query adjacency.
pub fn for_each_province_adjacency_in_province<F: FnMut(&Self, ProvinceId)>(&self, id: ProvinceId, mut f: F);: Iterate over adjacencies in a province (with the lambda called over the adjacent objects).