2 releases
0.1.1 | Jun 27, 2024 |
---|---|
0.1.0 | Jun 26, 2024 |
#366 in Embedded development
14KB
118 lines
fieldset
This library tracks field modifications as data. It is intended to provide a bounded-space alternative to event listeners, designed for but not restricted to usage in embedded systems.
It works by deriving a FieldType
, a FieldSetter
trait and multiple FieldSet
types from a struct.
- The
FieldType
is an enum where each variant corresponds to each field of the structure. - The
FieldSetter
trait consists of one setter method for each field. - The
FieldSet
types implement theFieldSetter
trait and provide an iterator interface where each item is aFieldType
instance corresponding to modified fields.
Subsystems can use the FieldSetter
interface to "modify" fields of the original parameter structure
and then the FieldSet
can be iterated upon to notify other subsystems that the fields were modified.
This allows for implementing event-driven architectures by batching modifications and then notifying afterwards.
There are multiple FieldSetter
implementations with different tradeoffs regarding iteration and backup storage.
OptFieldSet
is backed by a derived struct where each field is converted to anOption
. Each iteration goes through all fields and is therefore suitable for smaller structures or frequent modifications.BitFieldSet
is backed by an iteration array ofFieldType
with length equal to the number of fields, and abitfield
that tracks which fields have been modified. Iteration is optimal and only goes through exactly as many fields as were modified. Has the drawback that each field can only be modified once before iteration and subsequent modifications are ignored. This is often a good compromise.PerfFieldSet
is backed by an array ofFieldType
of length equal to the number of fields and a complementary array that tracks which fields have been modified and their current position in the iteration array. Iteration is optimal and only goes through exactly as many fields as were modified. Fields can be modified multiple times and only the latest modification applies. Has the drawback of the extra space needed to track the multiple modifications.
The library currently requires the usage of the nightly impl_trait_in_assoc_type
feature.
Example
#![feature(impl_trait_in_assoc_type)]
use fieldset::{FieldSetter, FieldSet};
#[derive(Default, FieldSet)]
struct SubModel {
a: f32,
b: u32
}
#[derive(Default, FieldSet)]
struct DomainModel {
#[fieldset]
sub: SubModel,
c: f32
}
fn sub_modifier(mut model: impl SubModelFieldSetter, i: u32) {
model.b().set(i);
}
fn modifier(mut model: impl DomainModelFieldSetter, i: u32) {
model.c().set(i as f32);
sub_modifier(model.sub(), i);
}
fn example() {
let mut model = DomainModel::default();
for i in 0..10 {
let mut field_set = DomainModelPerfFieldSet::default();
modifier(&mut field_set, i);
let mut iter = field_set.into_iter();
for field_change in iter.clone() {
model.apply(field_change);
}
assert_eq!(iter.next(), Some(DomainModelFieldType::C(i as f32)));
assert_eq!(iter.next(), Some(DomainModelFieldType::Sub(SubModelFieldType::B(i))));
assert_eq!(model.c, i as f32);
assert_eq!(model.sub.b, i);
}
}
Dependencies
~0.7–1.2MB
~23K SLoC