serde_derive/internals/
ctxt.rs

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