aboutsummaryrefslogtreecommitdiff
path: root/embassy-executor-macros/src/util
diff options
context:
space:
mode:
Diffstat (limited to 'embassy-executor-macros/src/util')
-rw-r--r--embassy-executor-macros/src/util/ctxt.rs73
-rw-r--r--embassy-executor-macros/src/util/mod.rs1
2 files changed, 74 insertions, 0 deletions
diff --git a/embassy-executor-macros/src/util/ctxt.rs b/embassy-executor-macros/src/util/ctxt.rs
new file mode 100644
index 000000000..74c872c3c
--- /dev/null
+++ b/embassy-executor-macros/src/util/ctxt.rs
@@ -0,0 +1,73 @@
1// nifty utility borrowed from serde :)
2// https://github.com/serde-rs/serde/blob/master/serde_derive/src/internals/ctxt.rs
3
4use std::cell::RefCell;
5use std::fmt::Display;
6use std::thread;
7
8use proc_macro2::TokenStream;
9use quote::{quote, ToTokens};
10use syn;
11
12/// A type to collect errors together and format them.
13///
14/// Dropping this object will cause a panic. It must be consumed using `check`.
15///
16/// References can be shared since this type uses run-time exclusive mut checking.
17#[derive(Default)]
18pub struct Ctxt {
19 // The contents will be set to `None` during checking. This is so that checking can be
20 // enforced.
21 errors: RefCell<Option<Vec<syn::Error>>>,
22}
23
24impl Ctxt {
25 /// Create a new context object.
26 ///
27 /// This object contains no errors, but will still trigger a panic if it is not `check`ed.
28 pub fn new() -> Self {
29 Ctxt {
30 errors: RefCell::new(Some(Vec::new())),
31 }
32 }
33
34 /// Add an error to the context object with a tokenenizable object.
35 ///
36 /// The object is used for spanning in error messages.
37 pub fn error_spanned_by<A: ToTokens, T: Display>(&self, obj: A, msg: T) {
38 self.errors
39 .borrow_mut()
40 .as_mut()
41 .unwrap()
42 // Curb monomorphization from generating too many identical methods.
43 .push(syn::Error::new_spanned(obj.into_token_stream(), msg));
44 }
45
46 /// Add one of Syn's parse errors.
47 #[allow(unused)]
48 pub fn syn_error(&self, err: syn::Error) {
49 self.errors.borrow_mut().as_mut().unwrap().push(err);
50 }
51
52 /// Consume this object, producing a formatted error string if there are errors.
53 pub fn check(self) -> Result<(), TokenStream> {
54 let errors = self.errors.borrow_mut().take().unwrap();
55 match errors.len() {
56 0 => Ok(()),
57 _ => Err(to_compile_errors(errors)),
58 }
59 }
60}
61
62fn to_compile_errors(errors: Vec<syn::Error>) -> proc_macro2::TokenStream {
63 let compile_errors = errors.iter().map(syn::Error::to_compile_error);
64 quote!(#(#compile_errors)*)
65}
66
67impl Drop for Ctxt {
68 fn drop(&mut self) {
69 if !thread::panicking() && self.errors.borrow().is_some() {
70 panic!("forgot to check for errors");
71 }
72 }
73}
diff --git a/embassy-executor-macros/src/util/mod.rs b/embassy-executor-macros/src/util/mod.rs
new file mode 100644
index 000000000..28702809e
--- /dev/null
+++ b/embassy-executor-macros/src/util/mod.rs
@@ -0,0 +1 @@
pub mod ctxt;