TeXitoi / keyberon

A rust crate to create a pure rust keyboard firmware.
MIT License
1.07k stars 78 forks source link

[RFC] Support both Layers as const-array and as slices #96

Open jedrzejboczar opened 2 years ago

jedrzejboczar commented 2 years ago

This is a quick proof-of-concept of a potential solution to https://github.com/TeXitoi/keyberon/issues/88.

Instead of having Layers as concrete type, it is a trait and is auto-implemented for both &'a [&'a [&'a [Action<T>]]] and [[[Action<T>; C]; R]; L]. This way it is possible to limit the number of type parameters passed. So one could use something like:

pub struct Keyboard<L: keyberon::layout::Layers + 'static> {
    layout: keyberon::layout::Layout<L>,
}

or if the CustomAction associated type has to limited (because e.g. we are adding handling of our actions):

pub struct Keyboard<L: keyberon::layout::Layers<CustomAction = MyAction> + 'static> {
    layout: keyberon::layout::Layout<L>,
}

The syntax for defining layers stays quite simple, either static LAYERS: LayersArray<2, 1, 2> = [...] or static LAYERS: LayersSlice = &[...] (but it's probably better to use the first one). We could even have some different aliases, like e.g.

pub type LayersXXX<const C: usize, const R: usize, T = core::convert::Infallible> = &'a [[[Action<T>; C]; R];

which would be more convenient for users.

From my initial tests the binary size does not increase, so it seems like everything gets optimized out properly, but I didn't do any strict testing, just running cargo size --release.

This was just a quick idea, it's open for discussion and would require code cleanup and renaming a few things. @riskable Please check if this approach would actually help to simplify your interface.

Ben-PH commented 1 year ago

Another issue could be the indirection. key-matrix polling could be considered a perf-sensitive hot-loop (latency, for example). Not too familiar with how it works in the embedded world, or if the indirection ultimately gets optimised away, but, having the layout known at compile time would allow the compiler to make some nice optimisations, no?

TeXitoi commented 1 year ago

Here, the types will be monomorphised at compile time, so it is a "zero cost abstraction", meaning that you'll get a code as fast as if you had implemented by hand on the two case. So it should not be an issue.

riskable commented 1 year ago

FYI: I like this solution :+1: