1 use quote::ToTokens; 2 use std::cell::RefCell; 3 use std::fmt::Display; 4 use std::thread; 5 6 /// A type to collect errors together and format them. 7 /// 8 /// Dropping this object will cause a panic. It must be consumed using `check`. 9 /// 10 /// References can be shared since this type uses run-time exclusive mut checking. 11 #[derive(Default)] 12 pub struct Ctxt { 13 // The contents will be set to `None` during checking. This is so that checking can be 14 // enforced. 15 errors: RefCell<Option<Vec<syn::Error>>>, 16 } 17 18 impl Ctxt { 19 /// Create a new context object. 20 /// 21 /// This object contains no errors, but will still trigger a panic if it is not `check`ed. new() -> Self22 pub fn new() -> Self { 23 Ctxt { 24 errors: RefCell::new(Some(Vec::new())), 25 } 26 } 27 28 /// Add an error to the context object with a tokenenizable object. 29 /// 30 /// The object is used for spanning in error messages. error_spanned_by<A: ToTokens, T: Display>(&self, obj: A, msg: T)31 pub fn error_spanned_by<A: ToTokens, T: Display>(&self, obj: A, msg: T) { 32 self.errors 33 .borrow_mut() 34 .as_mut() 35 .unwrap() 36 // Curb monomorphization from generating too many identical methods. 37 .push(syn::Error::new_spanned(obj.into_token_stream(), msg)); 38 } 39 40 /// Add one of Syn's parse errors. syn_error(&self, err: syn::Error)41 pub fn syn_error(&self, err: syn::Error) { 42 self.errors.borrow_mut().as_mut().unwrap().push(err); 43 } 44 45 /// Consume this object, producing a formatted error string if there are errors. check(self) -> syn::Result<()>46 pub fn check(self) -> syn::Result<()> { 47 let mut errors = self.errors.borrow_mut().take().unwrap().into_iter(); 48 49 let mut combined = match errors.next() { 50 Some(first) => first, 51 None => return Ok(()), 52 }; 53 54 for rest in errors { 55 combined.combine(rest); 56 } 57 58 Err(combined) 59 } 60 } 61 62 impl Drop for Ctxt { drop(&mut self)63 fn drop(&mut self) { 64 if !thread::panicking() && self.errors.borrow().is_some() { 65 panic!("forgot to check for errors"); 66 } 67 } 68 } 69