Skip to content

Commit cf3fe4f

Browse files
committed
Try out a different approach
1 parent 2ddc236 commit cf3fe4f

File tree

9 files changed

+298
-181
lines changed

9 files changed

+298
-181
lines changed

gateway-addon-rust-codegen/.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
/target
2+
Cargo.lock
3+
/.idea
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
imports_granularity = "Crate"
2+
format_code_in_doc_comments = true

gateway-addon-rust-codegen/src/lib.rs

Lines changed: 114 additions & 89 deletions
Original file line numberDiff line numberDiff line change
@@ -1,118 +1,143 @@
1-
use proc_macro::{self, TokenStream};
1+
use proc_macro::TokenStream;
2+
use proc_macro2::TokenStream as TokenStream2;
23
use quote::quote;
34
use std::str::FromStr;
4-
use syn::{parse::Parser, parse_macro_input, DeriveInput};
5+
use syn::DeriveInput;
56

7+
/// Use this on a struct to generate a built adapter around it, including useful impls.
8+
///
9+
/// # Examples
10+
/// ```
11+
/// # use gateway_addon_rust::prelude::*;
12+
/// # use async_trait::async_trait;
13+
/// #[adapter]
14+
/// struct ExampleAdapter { foo: i32 }
15+
///
16+
/// #[async_trait]
17+
/// impl Adapter for BuiltExampleAdapter {
18+
/// async fn on_unload(&mut self) -> Result<(), String> {
19+
/// println!("Foo: {}", self.foo);
20+
/// Ok(())
21+
/// }
22+
/// }
23+
/// ```
24+
/// will expand to
25+
/// ```
26+
/// # use gateway_addon_rust::{prelude::*, adapter::AdapterHandleWrapper};
27+
/// # use std::ops::{Deref, DerefMut};
28+
/// # use async_trait::async_trait;
29+
/// struct ExampleAdapter { foo: i32 }
30+
///
31+
/// struct BuiltExampleAdapter{
32+
/// data: ExampleAdapter,
33+
/// adapter_handle: AdapterHandle
34+
/// }
35+
///
36+
/// impl AdapterHandleWrapper for BuiltExampleAdapter {
37+
/// fn adapter_handle(&self) -> &AdapterHandle {
38+
/// &self.adapter_handle
39+
/// }
40+
/// fn adapter_handle_mut(&mut self) -> &mut AdapterHandle {
41+
/// &mut self.adapter_handle
42+
/// }
43+
/// }
44+
///
45+
/// impl BuildAdapter for ExampleAdapter {
46+
/// type BuiltAdapter = BuiltExampleAdapter;
47+
/// fn build(data: Self, adapter_handle: AdapterHandle) -> Self::BuiltAdapter {
48+
/// BuiltExampleAdapter { data, adapter_handle }
49+
/// }
50+
/// }
51+
///
52+
/// impl Deref for BuiltExampleAdapter {
53+
/// type Target = ExampleAdapter;
54+
/// fn deref(&self) -> &Self::Target {
55+
/// &self.data
56+
/// }
57+
/// }
58+
///
59+
/// impl DerefMut for BuiltExampleAdapter {
60+
/// fn deref_mut(&mut self) -> &mut Self::Target {
61+
/// &mut self.data
62+
/// }
63+
/// }
64+
///
65+
/// #[async_trait]
66+
/// impl Adapter for BuiltExampleAdapter {
67+
/// // ...
68+
/// }
69+
/// ```
670
#[proc_macro_attribute]
771
pub fn adapter(_args: TokenStream, input: TokenStream) -> TokenStream {
8-
alter_struct(input, "adapter", "Adapter")
72+
apply_macro(input, "adapter", "Adapter")
973
}
1074

1175
#[proc_macro_attribute]
1276
pub fn device(_args: TokenStream, input: TokenStream) -> TokenStream {
13-
alter_struct(input, "device", "Device")
77+
apply_macro(input, "device", "Device")
1478
}
1579

16-
fn alter_struct(input: TokenStream, name_snail_case: &str, name_camel_case: &str) -> TokenStream {
17-
let trait_handle_wrapper = proc_macro2::TokenStream::from_str(&format!(
80+
fn apply_macro(input: TokenStream, name_snail_case: &str, name_camel_case: &str) -> TokenStream {
81+
if let Ok(ast) = syn::parse2::<DeriveInput>(input.into()) {
82+
alter_struct(ast, name_snail_case, name_camel_case).into()
83+
} else {
84+
panic!("`{}` has to be used with structs", name_snail_case)
85+
}
86+
}
87+
88+
fn alter_struct(ast: DeriveInput, name_snail_case: &str, name_camel_case: &str) -> TokenStream2 {
89+
let trait_handle_wrapper = TokenStream2::from_str(&format!(
1890
"gateway_addon_rust::{}::{}HandleWrapper",
1991
name_snail_case, name_camel_case
2092
))
2193
.unwrap();
22-
let struct_handle = proc_macro2::TokenStream::from_str(&format!(
94+
let trait_build = TokenStream2::from_str(&format!(
95+
"gateway_addon_rust::{}::Build{}",
96+
name_snail_case, name_camel_case
97+
))
98+
.unwrap();
99+
let struct_built = TokenStream2::from_str(&format!("Built{}", name_camel_case)).unwrap();
100+
let struct_handle = TokenStream2::from_str(&format!(
23101
"gateway_addon_rust::{}::{}Handle",
24102
name_snail_case, name_camel_case
25103
))
26104
.unwrap();
27-
let fn_handle =
28-
proc_macro2::TokenStream::from_str(&format!("{}_handle", name_snail_case)).unwrap();
29-
let fn_handle_mut =
30-
proc_macro2::TokenStream::from_str(&format!("{}_handle_mut", name_snail_case)).unwrap();
105+
let fn_handle = TokenStream2::from_str(&format!("{}_handle", name_snail_case)).unwrap();
106+
let fn_handle_mut = TokenStream2::from_str(&format!("{}_handle_mut", name_snail_case)).unwrap();
31107

32-
let mut ast = parse_macro_input!(input as DeriveInput);
33-
if let syn::Data::Struct(ref mut struct_data) = &mut ast.data {
34-
let struct_name = ast.ident.clone();
35-
let field_name = field_name(struct_data, name_snail_case);
36-
add_struct_field(struct_data, &field_name, struct_handle.clone());
108+
let struct_name = ast.ident.clone();
109+
let struct_built_name = TokenStream2::from_str(&format!("Built{}", struct_name)).unwrap();
37110

38-
quote! {
39-
#ast
40-
impl #trait_handle_wrapper for #struct_name {
41-
fn #fn_handle(&self) -> &#struct_handle {
42-
&self.#field_name
43-
}
44-
fn #fn_handle_mut(&mut self) -> &mut #struct_handle {
45-
&mut self.#field_name
46-
}
111+
quote! {
112+
#ast
113+
impl #trait_build for #struct_name {
114+
type #struct_built = #struct_built_name;
115+
fn build(data: Self, #fn_handle: #struct_handle) -> Self::#struct_built {
116+
#struct_built_name { data, #fn_handle }
47117
}
48-
impl std::ops::Deref for #struct_name {
49-
type Target = #struct_handle;
50-
fn deref(&self) -> &Self::Target {
51-
&self.#field_name
52-
}
118+
}
119+
struct #struct_built_name {
120+
data: #struct_name,
121+
#fn_handle: #struct_handle,
122+
}
123+
impl #trait_handle_wrapper for #struct_built_name {
124+
fn #fn_handle(&self) -> &#struct_handle {
125+
&self.#fn_handle
53126
}
54-
impl std::ops::DerefMut for #struct_name {
55-
fn deref_mut(&mut self) -> &mut Self::Target {
56-
&mut self.#field_name
57-
}
127+
fn #fn_handle_mut(&mut self) -> &mut #struct_handle {
128+
&mut self.#fn_handle
58129
}
59130
}
60-
.into()
61-
} else {
62-
panic!("`{}` has to be used with structs", name_snail_case)
63-
}
64-
}
65-
66-
fn field_name(struct_data: &mut syn::DataStruct, identifier: &str) -> syn::Member {
67-
match &mut struct_data.fields {
68-
syn::Fields::Named(_) => syn::Member::Named(syn::Ident::new(
69-
&format!("{}_handle", identifier),
70-
proc_macro2::Span::call_site(),
71-
)),
72-
syn::Fields::Unnamed(fields) => syn::Member::Unnamed(syn::Index {
73-
index: fields.unnamed.len() as _,
74-
span: proc_macro2::Span::call_site(),
75-
}),
76-
syn::Fields::Unit => syn::Member::Unnamed(syn::Index {
77-
index: 0,
78-
span: proc_macro2::Span::call_site(),
79-
}),
80-
}
81-
}
82-
83-
fn add_struct_field(
84-
struct_data: &mut syn::DataStruct,
85-
field_name: &syn::Member,
86-
field_type: proc_macro2::TokenStream,
87-
) {
88-
match &mut struct_data.fields {
89-
syn::Fields::Named(fields) => {
90-
fields.named.push(
91-
syn::Field::parse_named
92-
.parse2(quote! { #field_name: #field_type })
93-
.unwrap(),
94-
);
95-
}
96-
syn::Fields::Unnamed(fields) => {
97-
fields.unnamed.push(
98-
syn::Field::parse_unnamed
99-
.parse2(quote! { #field_type })
100-
.unwrap(),
101-
);
131+
impl std::ops::Deref for #struct_built_name {
132+
type Target = #struct_name;
133+
fn deref(&self) -> &Self::Target {
134+
&self.data
135+
}
102136
}
103-
syn::Fields::Unit => {
104-
let mut fields = syn::punctuated::Punctuated::new();
105-
fields.push(
106-
syn::Field::parse_unnamed
107-
.parse2(quote! { #field_type })
108-
.unwrap(),
109-
);
110-
struct_data.fields = syn::Fields::Unnamed(syn::FieldsUnnamed {
111-
paren_token: syn::token::Paren {
112-
span: proc_macro2::Span::call_site(),
113-
},
114-
unnamed: fields,
115-
});
137+
impl std::ops::DerefMut for #struct_built_name {
138+
fn deref_mut(&mut self) -> &mut Self::Target {
139+
&mut self.data
140+
}
116141
}
117142
}
118143
}

src/adapter/adapter_message_handler.rs

Lines changed: 6 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,7 @@ impl MessageHandler for dyn Adapter {
9090
#[cfg(test)]
9191
mod tests {
9292
use crate::{
93-
adapter::tests::{add_mock_device, MockAdapter},
93+
adapter::tests::{add_mock_device, BuiltMockAdapter},
9494
message_handler::MessageHandler,
9595
plugin::tests::{add_mock_adapter, plugin},
9696
Plugin,
@@ -138,9 +138,8 @@ mod tests {
138138

139139
{
140140
let mut adapter = adapter.lock().await;
141-
let adapter = adapter.downcast_mut::<MockAdapter>().unwrap();
141+
let adapter = adapter.downcast_mut::<BuiltMockAdapter>().unwrap();
142142
adapter
143-
.adapter_helper
144143
.expect_on_remove_device()
145144
.withf(move |device_id| device_id == DEVICE_ID)
146145
.times(1)
@@ -172,9 +171,8 @@ mod tests {
172171
adapter
173172
.lock()
174173
.await
175-
.downcast_mut::<MockAdapter>()
174+
.downcast_mut::<BuiltMockAdapter>()
176175
.unwrap()
177-
.adapter_helper
178176
.expect_on_unload()
179177
.times(1)
180178
.returning(|| Ok(()));
@@ -211,9 +209,8 @@ mod tests {
211209

212210
{
213211
let mut adapter = adapter.lock().await;
214-
let adapter = adapter.downcast_mut::<MockAdapter>().unwrap();
212+
let adapter = adapter.downcast_mut::<BuiltMockAdapter>().unwrap();
215213
adapter
216-
.adapter_helper
217214
.expect_on_start_pairing()
218215
.withf(move |t| t.as_secs() == timeout as u64)
219216
.times(1)
@@ -236,9 +233,8 @@ mod tests {
236233

237234
{
238235
let mut adapter = adapter.lock().await;
239-
let adapter = adapter.downcast_mut::<MockAdapter>().unwrap();
236+
let adapter = adapter.downcast_mut::<BuiltMockAdapter>().unwrap();
240237
adapter
241-
.adapter_helper
242238
.expect_on_cancel_pairing()
243239
.times(1)
244240
.returning(|| Ok(()));
@@ -275,9 +271,8 @@ mod tests {
275271

276272
{
277273
let mut adapter = adapter.lock().await;
278-
let adapter = adapter.downcast_mut::<MockAdapter>().unwrap();
274+
let adapter = adapter.downcast_mut::<BuiltMockAdapter>().unwrap();
279275
adapter
280-
.adapter_helper
281276
.expect_on_device_saved()
282277
.withf(move |id, description| id == DEVICE_ID && description == &device_description)
283278
.times(1)

0 commit comments

Comments
 (0)