From 74ce5279543380a0995e5dd75b608959dd65a6d0 Mon Sep 17 00:00:00 2001 From: Thompson Leonard Date: Sat, 13 Sep 2025 12:12:22 +0300 Subject: [PATCH 1/3] Add trait DuelChannel --- components/src/channels.rs | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/components/src/channels.rs b/components/src/channels.rs index 84875ff..652a2c1 100644 --- a/components/src/channels.rs +++ b/components/src/channels.rs @@ -1,6 +1,17 @@ -pub trait Channel: std::marker::Copy { - fn set(&self, value: T) -> Self; +use std::marker::Copy; + +pub trait Channel: Copy { fn get(&self) -> T; + fn set(&self, value: T) -> Self; +} + +pub trait DuelChannel: Copy + Channel + Channel { + fn duel_get(&self) -> A { + self.get() + } + fn duel_set(&self, value: B) -> Self { + self.set(value) + } } #[cfg(test)] From 217b0e8bf424007f7aa26484c77696e5bd737c98 Mon Sep 17 00:00:00 2001 From: Thompson Leonard Date: Sat, 13 Sep 2025 13:41:51 +0300 Subject: [PATCH 2/3] Add implementation for trait DuelChannel in derive Channels --- Cargo.lock | 16 ++++++++++++++++ components_macros/Cargo.toml | 3 ++- components_macros/src/lib.rs | 21 ++++++++++++++++----- 3 files changed, 34 insertions(+), 6 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index bb8cb05..3d249f9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -13,11 +13,27 @@ dependencies = [ name = "components_macros" version = "0.1.0" dependencies = [ + "itertools", "proc-macro2", "quote", "syn", ] +[[package]] +name = "either" +version = "1.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" + +[[package]] +name = "itertools" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b192c782037fadd9cfa75548310488aabdbf3d2da73885b31bd0abd03351285" +dependencies = [ + "either", +] + [[package]] name = "proc-macro2" version = "1.0.101" diff --git a/components_macros/Cargo.toml b/components_macros/Cargo.toml index d390b9f..2f9f63b 100644 --- a/components_macros/Cargo.toml +++ b/components_macros/Cargo.toml @@ -8,6 +8,7 @@ proc-macro = true name = "components_macros" [dependencies] +itertools = "0.14.0" proc-macro2 = "1.0.101" quote = "1.0.40" -syn = "2.0.106" +syn = { version = "2.0.106", features = ["extra-traits"] } diff --git a/components_macros/src/lib.rs b/components_macros/src/lib.rs index 3284391..1f94d0a 100644 --- a/components_macros/src/lib.rs +++ b/components_macros/src/lib.rs @@ -3,6 +3,7 @@ extern crate proc_macro; use proc_macro2::{TokenStream, Span}; use quote::quote; use syn::{Data, DeriveInput}; +use itertools::Itertools; #[proc_macro_derive(Channels)] pub fn channels(input: proc_macro::TokenStream) -> proc_macro::TokenStream { @@ -22,22 +23,32 @@ fn channels_inner(ast: &DeriveInput) -> syn::Result { _ => return Err(non_struct_error()), }; - let generated_code = fields.iter().map(|f| (f.clone().ident.expect("struct fields have names"), f.ty.clone())).map(|(field, ty)| { + let fields = fields.iter().map(|f| (f.clone().ident.expect("struct fields have names"), f.ty.clone())); + let channel_impls = fields.clone().map(|(field, ty)| { quote! { impl #impl_generics ::components::__private::Channel<#ty> for #name #ty_generics #where_clause { + fn get(&self) -> #ty { + self.#field + } fn set(&self, value: #ty) -> Self { let mut clone = *self; clone.#field = value; clone } - fn get(&self) -> #ty { - self.#field - } } } }); + let duel_channel_impls = fields.clone().cartesian_product(fields) + .map(|(a, b)| (a.1, b.1)) + .filter(|(a, b)| a != b) + .map(|(ty_a, ty_b)| { + quote! { + impl #impl_generics ::components::__private::DuelChannel<#ty_a, #ty_b> for #name #ty_generics #where_clause {} + } + }); Ok(quote! { - #(#generated_code)* + #(#channel_impls)* + #(#duel_channel_impls)* }) } From 4825d8f6ed8a85ba0b619ef5ebb86510b357cf70 Mon Sep 17 00:00:00 2001 From: Thompson Leonard Date: Sat, 13 Sep 2025 13:47:19 +0300 Subject: [PATCH 3/3] Make DuelChannel accessible to components_macros and add tests for it --- components/src/channels.rs | 17 +++++++++++++++++ components/src/lib.rs | 1 + components/tests/macros.rs | 16 ++++++++++++++++ 3 files changed, 34 insertions(+) diff --git a/components/src/channels.rs b/components/src/channels.rs index 652a2c1..6116f38 100644 --- a/components/src/channels.rs +++ b/components/src/channels.rs @@ -33,6 +33,21 @@ mod tests { assert_eq!(channel.event, new_event); } + #[test] + fn test_duel_get() { + let channel = get_test_channel(); + let event: Event = channel.duel_get(); + assert_eq!(event, channel.event); + } + + #[test] + fn test_duel_set() { + let channel = get_test_channel(); + let new_event = Event::Exit; + let channel = channel.duel_set(new_event); + assert_eq!(channel.event, new_event); + } + fn get_test_channel() -> EventChannel { EventChannel { event: Event::Keyboard, @@ -55,6 +70,8 @@ mod tests { } } + impl DuelChannel for EventChannel {} + #[derive(Debug, Clone, Copy, PartialEq, Eq)] enum Event { Keyboard, diff --git a/components/src/lib.rs b/components/src/lib.rs index fbcbf71..15a5792 100644 --- a/components/src/lib.rs +++ b/components/src/lib.rs @@ -4,6 +4,7 @@ pub mod channels; #[doc(hidden)] pub mod __private { pub use crate::channels::Channel; + pub use crate::channels::DuelChannel; } #[cfg(feature = "macros")] diff --git a/components/tests/macros.rs b/components/tests/macros.rs index f86d207..2d7dac9 100644 --- a/components/tests/macros.rs +++ b/components/tests/macros.rs @@ -1,4 +1,5 @@ use components::channels::Channel; +use components::channels::DuelChannel; use components::Channels; #[test] @@ -16,6 +17,21 @@ fn test_derive_channels_set() { assert_eq!(channel.position, new_position); } +#[test] +fn test_derive_duel_channels_get() { + let channel = get_test_channel(); + let color: Rgb = channel.duel_get(); + assert_eq!(color, channel.color); +} + +#[test] +fn test_derive_duel_channels_set() { + let channel = get_test_channel(); + let new_position = (-5, 20); + let channel = channel.duel_set(new_position); + assert_eq!(channel.position, new_position); +} + fn get_test_channel() -> GraphicsChannel { let color = Rgb { red: 255,