Skip to content

Commit

Permalink
Flatten variants in enums
Browse files Browse the repository at this point in the history
  • Loading branch information
mertwole committed Aug 25, 2024
1 parent fe39700 commit 9cb6fa4
Show file tree
Hide file tree
Showing 2 changed files with 66 additions and 18 deletions.
18 changes: 12 additions & 6 deletions app/input_mapping_common/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,17 +1,23 @@
use ratatui::crossterm::event::{Event, KeyCode};

pub trait InputMappingT: Sized {
fn get_mapping(&self) -> InputMapping<Self>;
fn get_mapping() -> InputMapping;

fn map_event(&self, event: Event) -> Option<Self>;
fn map_event(event: Event) -> Option<Self>;
}

pub struct InputMapping<M: InputMappingT> {
pub mapping: Vec<MappingEntry<M>>,
pub struct InputMapping {
pub mapping: Vec<MappingEntry>,
}

pub struct MappingEntry<M: InputMappingT> {
impl InputMapping {
pub fn merge(mut self, mut other: InputMapping) -> Self {
self.mapping.append(&mut other.mapping);
self
}
}

pub struct MappingEntry {
pub key: KeyCode,
pub description: String,
pub event: M,
}
66 changes: 54 additions & 12 deletions app/input_mapping_derive/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,22 +17,21 @@ pub fn derive_mapping(input: proc_macro::TokenStream) -> proc_macro::TokenStream

// TODO: Add check that mappings don't overlap.
fn generate_trait_impl(item_enum: ItemEnum) -> TokenStream {
let mapping_entries = item_enum
let (unit, to_be_flattened): (Vec<_>, Vec<_>) = item_enum
.variants
.iter()
.filter(|variant| matches!(variant.fields, Fields::Unit))
.map(generate_mapping_entry);
.into_iter()
.partition(|variant| matches!(variant.fields, Fields::Unit));

let mapping_entries = unit.into_iter().map(generate_mapping_entry);

let mapping_constructors = mapping_entries.clone().map(|entry| {
let key = entry.key;
let description = entry.description;
let event = entry.event;

quote! {
::input_mapping_common::MappingEntry {
key: ::ratatui::crossterm::event::KeyCode::Char(#key),
description: (#description).to_string(),
event: Self:: #event
}
}
});
Expand All @@ -42,29 +41,72 @@ fn generate_trait_impl(item_enum: ItemEnum) -> TokenStream {
let event = entry.event;

quote! {
() if event.is_key_pressed(::ratatui::crossterm::event::KeyCode::Char(#key)) => ::std::option::Option::Some(Self:: #event)
() if event.is_key_pressed(::ratatui::crossterm::event::KeyCode::Char(#key)) =>
::std::option::Option::Some(Self:: #event)
}
});

let get_mapping_flattening = to_be_flattened.iter().map(|variant| {
let field_ty = match &variant.fields {
Fields::Unnamed(fields) => {
let fields = &fields.unnamed;
if fields.len() != 1 {
panic!("Multiple unnamed fields are not supported");
}
&fields.first().expect("fields.len() checked to be = 1").ty
}
Fields::Unit => panic!("Unit fields have been filtered above"),
Fields::Named(_) => panic!("Named variant fields are not supported"),
};

quote! {
.merge(#field_ty ::get_mapping())
}
});

let map_event_flattening = to_be_flattened.iter().map(|variant| {
let field_ty = match &variant.fields {
Fields::Unnamed(fields) => {
let fields = &fields.unnamed;
if fields.len() != 1 {
panic!("Multiple unnamed fields are not supported");
}
&fields.first().expect("fields.len() checked to be = 1").ty
}
Fields::Unit => panic!("Unit fields have been filtered above"),
Fields::Named(_) => panic!("Named variant fields are not supported"),
};

let ident = &variant.ident;

quote! {
.or_else(|| {
#field_ty ::map_event(event).map(Self:: #ident)
})
}
});

let ident = item_enum.ident;

quote! {
impl ::input_mapping_common::InputMappingT for #ident {
fn get_mapping(&self) -> ::input_mapping_common::InputMapping<Self> {
fn get_mapping() -> ::input_mapping_common::InputMapping {
::input_mapping_common::InputMapping {
// TODO: Concat flattened
mapping: vec![
#(#mapping_constructors,)*
]
}

#(#get_mapping_flattening)*
}

fn map_event(&self, event: ::ratatui::crossterm::event::Event) -> ::std::option::Option<Self> {
// TODO: Concat flattened
fn map_event(event: ::ratatui::crossterm::event::Event) -> ::std::option::Option<Self> {
match () {
#(#mapping_matchers,)*
_ => None,
}

#(#map_event_flattening)*
}
}
}
Expand All @@ -76,7 +118,7 @@ struct MappingEntry {
event: TokenStream,
}

fn generate_mapping_entry(variant: &Variant) -> MappingEntry {
fn generate_mapping_entry(variant: Variant) -> MappingEntry {
let mut key: Option<TokenStream> = None;
let mut description: Option<TokenStream> = None;

Expand Down

0 comments on commit 9cb6fa4

Please sign in to comment.