tex_parser/ast/
input_context.rs

1// SPDX-License-Identifier: LGPL-2.1-or-later
2// See Notices.txt for copyright information
3
4use super::Pos;
5use std::{cell::Cell, mem};
6
7#[derive(Clone, Copy)]
8#[repr(C)]
9pub struct InputContext<'a> {
10    pub file_name: &'a str,
11    pub input: &'a str,
12}
13
14thread_local! {
15    static INPUT_CONTEXT: Cell<Option<InputContext<'static>>> = Cell::new(None);
16}
17
18impl Pos {
19    pub fn get_input_context<R, F: for<'input> FnOnce(Option<InputContext<'input>>) -> R>(
20        f: F,
21    ) -> R {
22        let input: Option<InputContext> = INPUT_CONTEXT.with(|c| c.get());
23        f(input)
24    }
25    pub fn call_with_input_context<'input, R, F: FnOnce() -> R>(
26        input: InputContext<'input>,
27        f: F,
28    ) -> R {
29        struct RestoreOnDrop {
30            old_context: Option<InputContext<'static>>,
31        }
32
33        struct PanicOnDrop {}
34
35        impl Drop for PanicOnDrop {
36            fn drop(&mut self) {
37                panic!(
38                    "restoring old context failed -- aborting via double-panic to prevent memory unsafety"
39                );
40            }
41        }
42
43        impl Drop for RestoreOnDrop {
44            fn drop(&mut self) {
45                let v = PanicOnDrop {};
46                INPUT_CONTEXT.with(|context| context.set(self.old_context));
47                mem::forget(v);
48            }
49        }
50
51        let restore_on_drop = unsafe {
52            INPUT_CONTEXT.with(|context| RestoreOnDrop {
53                old_context: context.replace(Some(mem::transmute::<
54                    InputContext<'input>,
55                    InputContext<'static>,
56                >(input))),
57            })
58        };
59        let retval = f();
60        drop(restore_on_drop);
61        retval
62    }
63}