@@ -3,8 +3,8 @@ use std::cell::RefCell;
3
3
use crate :: internals:: * ;
4
4
use proc_macro2:: Span ;
5
5
use proc_macro2:: TokenStream ;
6
- use quote:: quote_spanned;
7
- use quote :: { quote , ToTokens } ;
6
+ use quote:: { quote , quote_spanned, ToTokens } ;
7
+ use syn :: parse :: Parse ;
8
8
use syn:: parse:: ParseStream ;
9
9
use syn:: punctuated:: Punctuated ;
10
10
use syn:: spanned:: Spanned as _;
@@ -72,6 +72,8 @@ pub(crate) struct TypeAttr {
72
72
pub ( crate ) parse : ParseKind ,
73
73
/// `#[rune(item = <path>)]`.
74
74
pub ( crate ) item : Option < syn:: Path > ,
75
+ /// Protocols to "derive"
76
+ pub ( crate ) protocols : Vec < TypeProtocol > ,
75
77
/// Parsed documentation.
76
78
pub ( crate ) docs : Vec < syn:: Expr > ,
77
79
}
@@ -111,6 +113,60 @@ pub(crate) struct FieldProtocol {
111
113
custom : Option < syn:: Path > ,
112
114
}
113
115
116
+ pub ( crate ) struct TypeProtocol {
117
+ protocol : syn:: Ident ,
118
+ handler : Option < syn:: Path > ,
119
+ }
120
+
121
+ impl TypeProtocol {
122
+ pub fn expand ( & self ) -> TokenStream {
123
+ if let Some ( handler) = & self . handler {
124
+ let protocol = & self . protocol ;
125
+ return quote_spanned ! { protocol. span( ) =>
126
+ module. associated_function( rune:: runtime:: Protocol :: #protocol, #handler) ?;
127
+ } ;
128
+ }
129
+ match self . protocol . to_string ( ) . as_str ( ) {
130
+ "ADD" => quote_spanned ! { self . protocol. span( ) =>
131
+ module. associated_function( rune:: runtime:: Protocol :: ADD , |this: Self , other: Self | this + other) ?;
132
+ } ,
133
+ "STRING_DISPLAY" => quote_spanned ! { self . protocol. span( ) =>
134
+ module. associated_function( rune:: runtime:: Protocol :: STRING_DISPLAY , |this: & Self , buf: & mut String | {
135
+ use :: std:: fmt:: Write as _;
136
+ :: std:: write!( buf, "{this}" )
137
+ } ) ?;
138
+ } ,
139
+ "STRING_DEBUG" => quote_spanned ! { self . protocol. span( ) =>
140
+ module. associated_function( rune:: runtime:: Protocol :: STRING_DISPLAY , |this: & Self , buf: & mut String | {
141
+ use :: std:: fmt:: Write as _;
142
+ :: std:: write!( buf, "{this:?}" )
143
+ } ) ?;
144
+ } ,
145
+ _ => syn:: Error :: new_spanned (
146
+ & self . protocol ,
147
+ format ! (
148
+ "`{}` is not a protocol supported for automatic generation on a type" ,
149
+ self . protocol
150
+ ) ,
151
+ )
152
+ . to_compile_error ( ) ,
153
+ }
154
+ }
155
+ }
156
+
157
+ impl Parse for TypeProtocol {
158
+ fn parse ( input : ParseStream ) -> syn:: Result < Self > {
159
+ Ok ( Self {
160
+ protocol : input. parse ( ) ?,
161
+ handler : if input. parse :: < Token ! [ =] > ( ) . is_ok ( ) {
162
+ Some ( input. parse ( ) ?)
163
+ } else {
164
+ None
165
+ } ,
166
+ } )
167
+ }
168
+ }
169
+
114
170
#[ derive( Default ) ]
115
171
pub ( crate ) struct Context {
116
172
pub ( crate ) errors : RefCell < Vec < syn:: Error > > ,
@@ -145,7 +201,7 @@ impl Context {
145
201
self . errors . borrow_mut ( ) . push ( error)
146
202
}
147
203
148
- /// Get a field identifier.
204
+ /// Get a field identifier.FunctionMetaKind
149
205
pub ( crate ) fn field_ident < ' a > ( & self , field : & ' a syn:: Field ) -> Result < & ' a syn:: Ident , ( ) > {
150
206
let Some ( ident) = & field. ident else {
151
207
self . error ( syn:: Error :: new_spanned (
@@ -441,6 +497,12 @@ impl Context {
441
497
// Parse `#[rune(install_with = <path>)]`
442
498
meta. input . parse :: < Token ! [ =] > ( ) ?;
443
499
attr. install_with = Some ( parse_path_compat ( meta. input ) ?) ;
500
+ } else if meta. path == PROTOCOLS {
501
+ // Parse `#[rune(protocols(<protocol>,*))]`
502
+ let protocols;
503
+ syn:: parenthesized!( protocols in meta. input) ;
504
+ attr. protocols
505
+ . extend ( protocols. parse_terminated ( TypeProtocol :: parse, Token ! [ , ] ) ?) ;
444
506
} else {
445
507
return Err ( syn:: Error :: new_spanned (
446
508
& meta. path ,
0 commit comments