about summary refs log tree commit diff
path: root/tvix/nix-compat-derive/src/internal/ctx.rs
use std::cell::RefCell;
use std::fmt;
use std::thread::panicking;

use quote::ToTokens;

pub struct Context {
    errors: RefCell<Option<Vec<syn::Error>>>,
}

impl Context {
    pub fn new() -> Context {
        Context {
            errors: RefCell::new(Some(Vec::new())),
        }
    }

    pub fn syn_error(&self, error: syn::Error) {
        self.errors
            .borrow_mut()
            .as_mut()
            .take()
            .unwrap()
            .push(error);
    }

    pub fn error_spanned<T: ToTokens, D: fmt::Display>(&self, tokens: T, message: D) {
        self.syn_error(syn::Error::new_spanned(tokens, message));
    }

    pub fn check(&self) -> syn::Result<()> {
        let mut iter = self.errors.borrow_mut().take().unwrap().into_iter();
        let mut err = match iter.next() {
            None => return Ok(()),
            Some(err) => err,
        };
        for next_err in iter {
            err.combine(next_err);
        }
        Err(err)
    }
}

impl Drop for Context {
    fn drop(&mut self) {
        if self.errors.borrow().is_some() && !panicking() {
            panic!("Context dropped without checking errors");
        }
    }
}