Skip to content

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

Draft
jedrzejboczar wants to merge 3 commits into
TeXitoi:masterfrom
jedrzejboczar:layers-trait
Draft

[RFC] Support both Layers as const-array and as slices#96
jedrzejboczar wants to merge 3 commits into
TeXitoi:masterfrom
jedrzejboczar:layers-trait

Conversation

@jedrzejboczar
Copy link
Copy Markdown
Contributor

This is a quick proof-of-concept of a potential solution to #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.

Copy link
Copy Markdown
Owner

@TeXitoi TeXitoi left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK in the idea.

Comment thread src/layout.rs
type CustomAction;

/// Retrieve the action at given `layer` for key at `(row, col)`.
fn get_action(&self, layer: usize, row: u8, col: u8) -> Option<&Action<Self::CustomAction>>;
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe some coord type would improve code readability and remove col/row missmatches.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You mean something like struct Coords { row: u8, col: u8 } (as (u8, u8) and struct Coords(u8, u8) don't solve the problem)? Or maybe some wrapper types similar to stm32f0xx_hal::time::Hertz, like struct Row(u8), struct Col(u8)?

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I mean struct Coord { i: u8, j: u8 } but that's a refactor that might be out of scope of this PR.

Comment thread src/lib.rs

#[cfg(test)]
#[macro_use]
extern crate alloc;
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do you need this?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, I think I don't. I must have put it there when testing something (maybe using vec! somewhere) and it should be safe to remove.

@Ben-PH
Copy link
Copy Markdown

Ben-PH commented Sep 21, 2023

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
Copy link
Copy Markdown
Owner

TeXitoi commented Sep 21, 2023

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
Copy link
Copy Markdown
Contributor

FYI: I like this solution 👍

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants