1use darling::{
2 FromDeriveInput, FromMeta,
3 ast::{Data, NestedMeta},
4 util::{Flag, Ignored},
5};
6use proc_macro2::TokenStream as TokenStream2;
7use syn::{DeriveInput, Generics, Ident, Variant, Visibility};
8
9use quote::quote;
10
11#[manyhow::manyhow]
17#[proc_macro_attribute]
18pub fn to_layer_message(attr: TokenStream2, input: TokenStream2) -> manyhow::Result<TokenStream2> {
19 let meta = NestedMeta::parse_meta_list(attr)?;
20
21 let ToLayerMessageAttr { multi } = ToLayerMessageAttr::from_list(&meta)?;
22
23 let is_multi = multi.is_present();
24
25 let derive_input = syn::parse2::<DeriveInput>(input)?;
26 let attrs = &derive_input.attrs;
27 let MessageEnum {
28 vis,
29 ident,
30 generics,
31 data,
32 } = MessageEnum::from_derive_input(&derive_input)?;
33
34 let (impl_gen, ty_gen, where_gen) = generics.split_for_impl();
35 let variants = data.take_enum().unwrap();
36
37 let (additional_variants, try_into_impl) = match is_multi {
38 true => {
39 let additional_variants = quote! {
40 AnchorChange{id: iced::window::Id, anchor: iced_layershell::reexport::Anchor},
41 SetInputRegion{ id: iced::window::Id, callback: iced_layershell::actions::ActionCallback },
42 AnchorSizeChange{id: iced::window::Id, anchor:iced_layershell::reexport::Anchor, size: (u32, u32)},
43 LayerChange{id: iced::window::Id, layer:iced_layershell::reexport::Layer},
44 MarginChange{id: iced::window::Id, margin: (i32, i32, i32, i32)},
45 SizeChange{id: iced::window::Id, size: (u32, u32)},
46 VirtualKeyboardPressed {
47 time: u32,
48 key: u32,
49 },
50 NewLayerShell { settings: iced_layershell::reexport::NewLayerShellSettings, id: iced::window::Id },
51 NewPopUp { settings: iced_layershell::actions::IcedNewPopupSettings, id: iced::window::Id },
52 NewMenu { settings: iced_layershell::actions::IcedNewMenuSettings, id: iced::window::Id },
53 RemoveWindow(iced::window::Id),
54 ForgetLastOutput,
55 };
56 let try_into_impl = quote! {
57 impl #impl_gen TryInto<iced_layershell::actions::LayershellCustomActionsWithId> for #ident #ty_gen #where_gen {
58 type Error = Self;
59
60 fn try_into(self) -> Result<iced_layershell::actions::LayershellCustomActionsWithId, Self::Error> {
61 use iced_layershell::actions::LayershellCustomActions;
62 use iced_layershell::actions::LayershellCustomActionsWithId;
63
64 match self {
65 Self::SetInputRegion{ id, callback } => Ok(LayershellCustomActionsWithId::new(Some(id), LayershellCustomActions::SetInputRegion(callback))),
66 Self::AnchorChange { id, anchor } => Ok(LayershellCustomActionsWithId::new(Some(id), LayershellCustomActions::AnchorChange(anchor))),
67 Self::AnchorSizeChange { id, anchor, size } => Ok(LayershellCustomActionsWithId::new(Some(id), LayershellCustomActions::AnchorSizeChange(anchor, size))),
68 Self::LayerChange { id, layer } => Ok(LayershellCustomActionsWithId::new(Some(id), LayershellCustomActions::LayerChange(layer))),
69 Self::MarginChange { id, margin } => Ok(LayershellCustomActionsWithId::new(Some(id), LayershellCustomActions::MarginChange(margin))),
70 Self::SizeChange { id, size } => Ok(LayershellCustomActionsWithId::new(Some(id), LayershellCustomActions::SizeChange(size))),
71 Self::VirtualKeyboardPressed { time, key } => Ok(LayershellCustomActionsWithId::new(
72 None,
73 LayershellCustomActions::VirtualKeyboardPressed { time, key })
74 ),
75 Self::NewLayerShell {settings, id } => Ok(LayershellCustomActionsWithId::new(None, LayershellCustomActions::NewLayerShell { settings, id })),
76 Self::NewPopUp { settings, id } => Ok(LayershellCustomActionsWithId::new(None, LayershellCustomActions::NewPopUp { settings, id })),
77 Self::NewMenu { settings, id } => Ok(LayershellCustomActionsWithId::new(None, LayershellCustomActions::NewMenu {settings, id })),
78 Self::RemoveWindow(id) => Ok(LayershellCustomActionsWithId::new(None, LayershellCustomActions::RemoveWindow(id))),
79 Self::ForgetLastOutput => Ok(LayershellCustomActionsWithId::new(None, LayershellCustomActions::ForgetLastOutput)),
80 _ => Err(self)
81 }
82 }
83 }
84 impl #ident #ty_gen #where_gen {
85 fn layershell_open(settings: iced_layershell::reexport::NewLayerShellSettings) -> (iced::window::Id, Self) {
86 let id = iced::window::Id::unique();
87 (
88 id,
89 Self::NewLayerShell { settings, id }
90 )
91
92 }
93 fn popup_open(settings: iced_layershell::actions::IcedNewPopupSettings) -> (iced::window::Id, Self) {
94 let id = iced::window::Id::unique();
95 (
96 id,
97 Self::NewPopUp { settings, id }
98 )
99
100 }
101 fn menu_open(settings: iced_layershell::actions::IcedNewMenuSettings) -> (iced::window::Id, Self) {
102 let id = iced::window::Id::unique();
103 (
104 id,
105 Self::NewMenu { settings, id }
106 )
107
108 }
109 }
110 };
111 (additional_variants, try_into_impl)
112 }
113 false => {
114 let additional_variants = quote! {
115 AnchorChange(iced_layershell::reexport::Anchor),
116 SetInputRegion(iced_layershell::actions::ActionCallback),
117 AnchorSizeChange(iced_layershell::reexport::Anchor, (u32, u32)),
118 LayerChange(iced_layershell::reexport::Layer),
119 MarginChange((i32, i32, i32, i32)),
120 SizeChange((u32, u32)),
121 VirtualKeyboardPressed {
122 time: u32,
123 key: u32,
124 },
125 };
126 let try_into_impl = quote! {
127 impl #impl_gen TryInto<iced_layershell::actions::LayershellCustomActions> for #ident #ty_gen #where_gen {
128 type Error = Self;
129
130 fn try_into(self) -> Result<iced_layershell::actions::LayershellCustomActions, Self::Error> {
131 use iced_layershell::actions::LayershellCustomActions;
132
133 match self {
134 Self::SetInputRegion(callback) => Ok(LayershellCustomActions::SetInputRegion(callback)),
135 Self::AnchorChange(anchor) => Ok(LayershellCustomActions::AnchorChange(anchor)),
136 Self::AnchorSizeChange(anchor, size) => Ok(LayershellCustomActions::AnchorSizeChange(anchor, size)),
137 Self::LayerChange(layer) => Ok(LayershellCustomActions::LayerChange(layer)),
138
139 Self::MarginChange(margin) => Ok(LayershellCustomActions::MarginChange(margin)),
140 Self::SizeChange(size) => Ok(LayershellCustomActions::SizeChange(size)),
141 Self::VirtualKeyboardPressed { time, key } => Ok(LayershellCustomActions::VirtualKeyboardPressed {
142 time,
143 key
144 }),
145 _ => Err(self)
146 }
147 }
148 }
149 };
150
151 (additional_variants, try_into_impl)
152 }
153 };
154
155 Ok(quote! {
156 #(#attrs)*
157 #vis enum #ident #ty_gen #where_gen {
158 #(#variants,)*
159 #additional_variants
160 }
161
162 #try_into_impl
163 })
164}
165
166#[derive(FromMeta)]
167struct ToLayerMessageAttr {
168 multi: Flag,
169}
170
171#[derive(FromDeriveInput)]
172#[darling(supports(enum_any))]
173struct MessageEnum {
174 vis: Visibility,
175 ident: Ident,
176 generics: Generics,
177 data: Data<Variant, Ignored>,
178}