diff options
Diffstat (limited to 'embassy-executor-macros/src/util')
| -rw-r--r-- | embassy-executor-macros/src/util/ctxt.rs | 73 | ||||
| -rw-r--r-- | embassy-executor-macros/src/util/mod.rs | 1 |
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 | |||
| 4 | use std::cell::RefCell; | ||
| 5 | use std::fmt::Display; | ||
| 6 | use std::thread; | ||
| 7 | |||
| 8 | use proc_macro2::TokenStream; | ||
| 9 | use quote::{quote, ToTokens}; | ||
| 10 | use 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)] | ||
| 18 | pub 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 | |||
| 24 | impl 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 | |||
| 62 | fn 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 | |||
| 67 | impl 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; | |||
