@@ -12,6 +12,7 @@ use syn::{
12
12
} ;
13
13
14
14
use crate :: codegen:: generate_node_code;
15
+ use crate :: shader_nodes:: ShaderNodeType ;
15
16
16
17
#[ derive( Debug ) ]
17
18
pub ( crate ) struct Implementation {
@@ -45,6 +46,10 @@ pub(crate) struct NodeFnAttributes {
45
46
pub ( crate ) path : Option < Path > ,
46
47
pub ( crate ) skip_impl : bool ,
47
48
pub ( crate ) properties_string : Option < LitStr > ,
49
+ /// whether to `#[cfg]` gate the node implementation, defaults to None
50
+ pub ( crate ) cfg : Option < TokenStream2 > ,
51
+ /// if this node should get a gpu implementation, defaults to None
52
+ pub ( crate ) shader_node : Option < ShaderNodeType > ,
48
53
// Add more attributes as needed
49
54
}
50
55
@@ -184,15 +189,19 @@ impl Parse for NodeFnAttributes {
184
189
let mut path = None ;
185
190
let mut skip_impl = false ;
186
191
let mut properties_string = None ;
192
+ let mut cfg = None ;
193
+ let mut shader_node = None ;
187
194
188
195
let content = input;
189
196
// let content;
190
197
// syn::parenthesized!(content in input);
191
198
192
199
let nested = content. call ( Punctuated :: < Meta , Comma > :: parse_terminated) ?;
193
200
for meta in nested {
194
- match meta {
195
- Meta :: List ( meta) if meta. path . is_ident ( "category" ) => {
201
+ let name = meta. path ( ) . get_ident ( ) . ok_or_else ( || Error :: new_spanned ( meta. path ( ) , "Node macro expects a known Ident, not a path" ) ) ?;
202
+ match name. to_string ( ) . as_str ( ) {
203
+ "category" => {
204
+ let meta = meta. require_list ( ) ?;
196
205
if category. is_some ( ) {
197
206
return Err ( Error :: new_spanned ( meta, "Multiple 'category' attributes are not allowed" ) ) ;
198
207
}
@@ -201,14 +210,16 @@ impl Parse for NodeFnAttributes {
201
210
. map_err ( |_| Error :: new_spanned ( meta, "Expected a string literal for 'category', e.g., category(\" Value\" )" ) ) ?;
202
211
category = Some ( lit) ;
203
212
}
204
- Meta :: List ( meta) if meta. path . is_ident ( "name" ) => {
213
+ "name" => {
214
+ let meta = meta. require_list ( ) ?;
205
215
if display_name. is_some ( ) {
206
216
return Err ( Error :: new_spanned ( meta, "Multiple 'name' attributes are not allowed" ) ) ;
207
217
}
208
218
let parsed_name: LitStr = meta. parse_args ( ) . map_err ( |_| Error :: new_spanned ( meta, "Expected a string for 'name', e.g., name(\" Memoize\" )" ) ) ?;
209
219
display_name = Some ( parsed_name) ;
210
220
}
211
- Meta :: List ( meta) if meta. path . is_ident ( "path" ) => {
221
+ "path" => {
222
+ let meta = meta. require_list ( ) ?;
212
223
if path. is_some ( ) {
213
224
return Err ( Error :: new_spanned ( meta, "Multiple 'path' attributes are not allowed" ) ) ;
214
225
}
@@ -217,13 +228,15 @@ impl Parse for NodeFnAttributes {
217
228
. map_err ( |_| Error :: new_spanned ( meta, "Expected a valid path for 'path', e.g., path(crate::MemoizeNode)" ) ) ?;
218
229
path = Some ( parsed_path) ;
219
230
}
220
- Meta :: Path ( path) if path. is_ident ( "skip_impl" ) => {
231
+ "skip_impl" => {
232
+ let path = meta. require_path_only ( ) ?;
221
233
if skip_impl {
222
234
return Err ( Error :: new_spanned ( path, "Multiple 'skip_impl' attributes are not allowed" ) ) ;
223
235
}
224
236
skip_impl = true ;
225
237
}
226
- Meta :: List ( meta) if meta. path . is_ident ( "properties" ) => {
238
+ "properties" => {
239
+ let meta = meta. require_list ( ) ?;
227
240
if properties_string. is_some ( ) {
228
241
return Err ( Error :: new_spanned ( path, "Multiple 'properties_string' attributes are not allowed" ) ) ;
229
242
}
@@ -233,13 +246,27 @@ impl Parse for NodeFnAttributes {
233
246
234
247
properties_string = Some ( parsed_properties_string) ;
235
248
}
249
+ "cfg" => {
250
+ if cfg. is_some ( ) {
251
+ return Err ( Error :: new_spanned ( path, "Multiple 'feature' attributes are not allowed" ) ) ;
252
+ }
253
+ let meta = meta. require_list ( ) ?;
254
+ cfg = Some ( meta. tokens . clone ( ) ) ;
255
+ }
256
+ "shader_node" => {
257
+ if shader_node. is_some ( ) {
258
+ return Err ( Error :: new_spanned ( path, "Multiple 'feature' attributes are not allowed" ) ) ;
259
+ }
260
+ let meta = meta. require_list ( ) ?;
261
+ shader_node = Some ( syn:: parse2 ( meta. tokens . to_token_stream ( ) ) ?) ;
262
+ }
236
263
_ => {
237
264
return Err ( Error :: new_spanned (
238
265
meta,
239
266
indoc ! (
240
267
r#"
241
268
Unsupported attribute in `node`.
242
- Supported attributes are 'category', 'path' and 'name '.
269
+ Supported attributes are 'category', 'path' 'name', 'skip_impl', 'cfg' and 'properties '.
243
270
244
271
Example usage:
245
272
#[node_macro::node(category("Value"), name("Test Node"))]
@@ -256,6 +283,8 @@ impl Parse for NodeFnAttributes {
256
283
path,
257
284
skip_impl,
258
285
properties_string,
286
+ cfg,
287
+ shader_node,
259
288
} )
260
289
}
261
290
}
@@ -758,6 +787,8 @@ mod tests {
758
787
path : Some ( parse_quote ! ( graphene_core:: TestNode ) ) ,
759
788
skip_impl : true ,
760
789
properties_string : None ,
790
+ cfg : None ,
791
+ shader_node : None ,
761
792
} ,
762
793
fn_name : Ident :: new ( "add" , Span :: call_site ( ) ) ,
763
794
struct_name : Ident :: new ( "Add" , Span :: call_site ( ) ) ,
@@ -819,6 +850,8 @@ mod tests {
819
850
path : None ,
820
851
skip_impl : false ,
821
852
properties_string : None ,
853
+ cfg : None ,
854
+ shader_node : None ,
822
855
} ,
823
856
fn_name : Ident :: new ( "transform" , Span :: call_site ( ) ) ,
824
857
struct_name : Ident :: new ( "Transform" , Span :: call_site ( ) ) ,
@@ -891,6 +924,8 @@ mod tests {
891
924
path : None ,
892
925
skip_impl : false ,
893
926
properties_string : None ,
927
+ cfg : None ,
928
+ shader_node : None ,
894
929
} ,
895
930
fn_name : Ident :: new ( "circle" , Span :: call_site ( ) ) ,
896
931
struct_name : Ident :: new ( "Circle" , Span :: call_site ( ) ) ,
@@ -948,6 +983,8 @@ mod tests {
948
983
path : None ,
949
984
skip_impl : false ,
950
985
properties_string : None ,
986
+ cfg : None ,
987
+ shader_node : None ,
951
988
} ,
952
989
fn_name : Ident :: new ( "levels" , Span :: call_site ( ) ) ,
953
990
struct_name : Ident :: new ( "Levels" , Span :: call_site ( ) ) ,
@@ -1017,6 +1054,8 @@ mod tests {
1017
1054
path : Some ( parse_quote ! ( graphene_core:: TestNode ) ) ,
1018
1055
skip_impl : false ,
1019
1056
properties_string : None ,
1057
+ cfg : None ,
1058
+ shader_node : None ,
1020
1059
} ,
1021
1060
fn_name : Ident :: new ( "add" , Span :: call_site ( ) ) ,
1022
1061
struct_name : Ident :: new ( "Add" , Span :: call_site ( ) ) ,
@@ -1074,6 +1113,8 @@ mod tests {
1074
1113
path : None ,
1075
1114
skip_impl : false ,
1076
1115
properties_string : None ,
1116
+ cfg : None ,
1117
+ shader_node : None ,
1077
1118
} ,
1078
1119
fn_name : Ident :: new ( "load_image" , Span :: call_site ( ) ) ,
1079
1120
struct_name : Ident :: new ( "LoadImage" , Span :: call_site ( ) ) ,
@@ -1131,6 +1172,8 @@ mod tests {
1131
1172
path : None ,
1132
1173
skip_impl : false ,
1133
1174
properties_string : None ,
1175
+ cfg : None ,
1176
+ shader_node : None ,
1134
1177
} ,
1135
1178
fn_name : Ident :: new ( "custom_node" , Span :: call_site ( ) ) ,
1136
1179
struct_name : Ident :: new ( "CustomNode" , Span :: call_site ( ) ) ,
0 commit comments