1
+ ///
2
+ /// Check for `async-trait`-like patterns in the block, and instrument the
3
+ /// future instead of the wrapper.
4
+ ///
5
+ /// Instrumenting the `async fn` is not as straight forward as expected because
6
+ /// `async_trait` rewrites `async fn` into a normal `fn` which returns
7
+ /// `Pin<Box<dyn Future + Send + 'async_trait>>`, and this stops the macro from
8
+ /// distinguishing `async fn` from `fn`.
9
+ ///
10
+ /// The following logic and code is from the `async-trait` probes from
11
+ /// [tokio-tracing][tokio-logic].
12
+ /// The Tokio logic is required for detecting the `async fn` that is already
13
+ /// transformed to `fn -> Pin<Box<dyn Future + Send + 'async_trait>>` by
14
+ /// `async-trait`.
15
+ /// We have to distinguish this case from `fn -> impl Future` that is written
16
+ /// by the user because for the latter, we instrument it like normal `fn`
17
+ /// instead of `async fn`.
18
+ ///
19
+ /// The reason why we elaborate `async fn` into `fn -> impl Future`:
20
+ /// For an `async fn foo()`, we have to instrument the
21
+ /// `Span::enter_with_local_parent()` in the first call to `foo()`, but not in
22
+ /// the `poll()` or `.await`, because it's the only chance that
23
+ /// local parent is present in that context.
24
+ ///
25
+ /// []tokio-logic]: https://github.com/tokio-rs/tracing/blob/6a61897a5e834988ad9ac709e28c93c4dbf29116/tracing-attributes/src/expand.rs
26
+ use bae:: FromAttributes ;
1
27
#[ allow( unused_imports) ]
2
28
use proc_macro_error:: { abort, abort_call_site} ;
3
29
use syn:: {
@@ -7,31 +33,94 @@ use syn::{
7
33
Expr , ItemFn ,
8
34
} ;
9
35
10
- use crate :: trace:: parse:: Ast ;
11
-
12
- pub fn analyze ( ast : Ast ) -> Model {
13
- let mut item = ast;
14
- let attrs = & mut item. attrs ;
15
- for index in ( 0 ..attrs. len ( ) ) . rev ( ) {
16
- if let Some ( ident) = attrs[ index] . path . get_ident ( ) {
17
- if ident. to_string ( ) . as_str ( ) == "precondition" {
18
- let attr = attrs. remove ( index) ;
19
- let _span = attr. tokens . span ( ) ;
20
-
21
- // if let Ok(arg) = syn::parse2::<AttributeArgument>(attr.tokens) {
22
- // preconditions.push(arg.expr);
23
- // } else {
24
- // // ../tests/trace/ui/err/precondition-is-not-an-expression.rs
25
- // abort!(
26
- // span,
27
- // "expected an expression as argument";
28
- // help = "example syntax: `#[precondition(argument % 2 == 0)]`")
29
- // }
30
- }
31
- }
36
+ use crate :: trace:: validate:: Ast ;
37
+
38
+ // - `Model.event: syn::LitStr,` // String`
39
+ // - `Model.enter_on_poll: syn::LitBool,` // boolean
40
+ // - `Model.black_box: syn::LitBool,` // boolean: see upstream issue #122
41
+ // - `Model.parent: syn::LitStr,` // String: see upstream issue #117
42
+ // - `Model.recorder: syn::Ident,` // see upstream issue #117
43
+ // - `Model.scope: syn::Ident,` // minitrace::Local or minitrace::Threads
44
+ //
45
+ // impl Default for Model {
46
+ //
47
+ // fn default() -> Self {
48
+ // Ok(Model {
49
+ // event: todo!(),
50
+ // enter_on_poll: todo!(),
51
+ // black_box: todo!(),
52
+ // parent: todo!(),
53
+ // recorder: todo!(),
54
+ // scope: todo!(),
55
+ // vars: v,
56
+ // })
57
+ // }
58
+
59
+ #[ derive(
60
+ Debug ,
61
+ Eq ,
62
+ PartialEq ,
63
+ // This will add two functions:
64
+ // ```
65
+ // fn from_attributes(attrs: &[syn::Attribute]) -> Result<Trace, syn::Error>
66
+ // fn try_from_attributes(attrs: &[syn::Attribute]) -> Result<Option<Trace>, syn::Error>
67
+ // ```
68
+ //
69
+ // `try_from_attributes(...)` returns `Ok(None)` if the attribute is missing,
70
+ // `Ok(Some(_))` if its there and is valid, `Err(_)` otherwise.
71
+ FromAttributes ,
72
+ ) ]
73
+ pub struct Trace {
74
+ // Anything that implements `syn::parse::Parse` is supported.
75
+ name : syn:: LitStr ,
76
+ scope : syn:: Type , // Local or Thread
77
+
78
+ // Fields wrapped in `Option` are optional and default to `None` if
79
+ // not specified in the attribute.
80
+ enter_on_poll : Option < syn:: LitBool > ,
81
+ black_box : Option < syn:: LitBool > ,
82
+ recorder : Option < syn:: Ident > ,
83
+ parent : Option < syn:: LitStr > ,
84
+
85
+ // A "switch" is something that doesn't take arguments.
86
+ // All fields with type `Option<()>` are considered switches.
87
+ // They default to `None`.
88
+ async_trait : Option < ( ) > ,
89
+ }
90
+
91
+ pub fn analyze ( meta : crate :: trace:: validate:: TraceAttr , item : syn:: ItemFn ) -> Model {
92
+ let mut itemfn = item;
93
+ let attribute = Trace :: from_attributes ( & meta. attrs ) . unwrap ( ) ;
94
+ eprintln ! ( "{:?}" , attribute) ;
95
+ // let attrs = &mut itemfn.attrs;
96
+
97
+ // attrs.iter().enumerate().for_each(|(i, a)| {
98
+ // //
99
+ // if let Some(ident) = a.path.get_ident() {
100
+ // if ident.to_string().as_str() == "precondition" {
101
+ // // Mark item as being subject to async_trait manipulation
102
+ // }
103
+ // }
104
+ // });
105
+
106
+ // for index in (0..attrs.len()).rev() {
107
+ // if let Some(ident) = attrs[index].path.get_ident() {
108
+ // if ident.to_string().as_str() == "precondition" {
109
+ // let attr = attrs.remove(index);
110
+ // let _span = attr.tokens.span();
111
+ // }
112
+ // }
113
+ // }
114
+
115
+ Model {
116
+ attribute,
117
+ item : itemfn,
32
118
}
119
+ }
33
120
34
- Model { item }
121
+ pub struct Model {
122
+ pub attribute : Trace ,
123
+ pub item : syn:: ItemFn ,
35
124
}
36
125
37
126
#[ allow( dead_code) ]
@@ -50,11 +139,6 @@ impl Parse for AttributeArgument {
50
139
}
51
140
}
52
141
53
- pub struct Model {
54
- // pub preconditions: Vec<Expr>,
55
- pub item : ItemFn ,
56
- }
57
-
58
142
#[ cfg( test) ]
59
143
mod tests {
60
144
use syn:: { parse_quote, Attribute } ;
@@ -63,10 +147,13 @@ mod tests {
63
147
64
148
#[ test]
65
149
fn can_extract_precondition ( ) {
66
- let model = analyze ( parse_quote ! (
67
- #[ precondition( x) ]
68
- fn f( x: bool ) { }
69
- ) ) ;
150
+ let model = analyze (
151
+ parse_quote ! ( ) ,
152
+ parse_quote ! (
153
+ #[ precondition( x) ]
154
+ fn f( x: bool ) { }
155
+ ) ,
156
+ ) ;
70
157
71
158
let _expected: & [ Expr ] = & [ parse_quote ! ( x) ] ;
72
159
// assert_eq!(expected, model.preconditions);
@@ -76,12 +163,15 @@ mod tests {
76
163
77
164
#[ test]
78
165
fn non_dsl_attributes_are_preserved ( ) {
79
- let model = analyze ( parse_quote ! (
80
- #[ a]
81
- #[ precondition( x) ]
82
- #[ b]
83
- fn f( x: bool ) { }
84
- ) ) ;
166
+ let model = analyze (
167
+ parse_quote ! ( ) ,
168
+ parse_quote ! (
169
+ #[ a]
170
+ #[ precondition( x) ]
171
+ #[ b]
172
+ fn f( x: bool ) { }
173
+ ) ,
174
+ ) ;
85
175
86
176
let expected: & [ Attribute ] = & [ parse_quote ! ( #[ a] ) , parse_quote ! ( #[ b] ) ] ;
87
177
assert_eq ! ( expected, model. item. attrs) ;
0 commit comments