summaryrefslogtreecommitdiffstats
path: root/third_party/rust/serde_derive/src/internals/ctxt.rs
diff options
context:
space:
mode:
Diffstat (limited to 'third_party/rust/serde_derive/src/internals/ctxt.rs')
-rw-r--r--third_party/rust/serde_derive/src/internals/ctxt.rs68
1 files changed, 68 insertions, 0 deletions
diff --git a/third_party/rust/serde_derive/src/internals/ctxt.rs b/third_party/rust/serde_derive/src/internals/ctxt.rs
new file mode 100644
index 0000000000..a47bfa4102
--- /dev/null
+++ b/third_party/rust/serde_derive/src/internals/ctxt.rs
@@ -0,0 +1,68 @@
+use quote::ToTokens;
+use std::cell::RefCell;
+use std::fmt::Display;
+use std::thread;
+
+/// A type to collect errors together and format them.
+///
+/// Dropping this object will cause a panic. It must be consumed using `check`.
+///
+/// References can be shared since this type uses run-time exclusive mut checking.
+#[derive(Default)]
+pub struct Ctxt {
+ // The contents will be set to `None` during checking. This is so that checking can be
+ // enforced.
+ errors: RefCell<Option<Vec<syn::Error>>>,
+}
+
+impl Ctxt {
+ /// Create a new context object.
+ ///
+ /// This object contains no errors, but will still trigger a panic if it is not `check`ed.
+ pub fn new() -> Self {
+ Ctxt {
+ errors: RefCell::new(Some(Vec::new())),
+ }
+ }
+
+ /// Add an error to the context object with a tokenenizable object.
+ ///
+ /// The object is used for spanning in error messages.
+ pub fn error_spanned_by<A: ToTokens, T: Display>(&self, obj: A, msg: T) {
+ self.errors
+ .borrow_mut()
+ .as_mut()
+ .unwrap()
+ // Curb monomorphization from generating too many identical methods.
+ .push(syn::Error::new_spanned(obj.into_token_stream(), msg));
+ }
+
+ /// Add one of Syn's parse errors.
+ pub fn syn_error(&self, err: syn::Error) {
+ self.errors.borrow_mut().as_mut().unwrap().push(err);
+ }
+
+ /// Consume this object, producing a formatted error string if there are errors.
+ pub fn check(self) -> syn::Result<()> {
+ let mut errors = self.errors.borrow_mut().take().unwrap().into_iter();
+
+ let mut combined = match errors.next() {
+ Some(first) => first,
+ None => return Ok(()),
+ };
+
+ for rest in errors {
+ combined.combine(rest);
+ }
+
+ Err(combined)
+ }
+}
+
+impl Drop for Ctxt {
+ fn drop(&mut self) {
+ if !thread::panicking() && self.errors.borrow().is_some() {
+ panic!("forgot to check for errors");
+ }
+ }
+}