use std::sync::{ atomic::{ AtomicBool, Ordering, }, Arc, LazyLock, Mutex, }; use fend_core::{ evaluate_with_interrupt, Context, Interrupt, }; use mlua::prelude::*; use crate::lenses::{ Cache, Entries, Entry, Lense }; static CTX: LazyLock> = LazyLock::new(|| { let mut ctx = Context::new(); ctx.use_coulomb_and_farad(); Mutex::new(ctx) }); #[derive(Default)] pub struct Calculator { should_interrupt: AtomicBool, } impl Lense for Calculator { const NAME: &str = "Calculator"; fn init() -> std::sync::Arc { Arc::new(Calculator::default()) } #[inline] fn set_cache(&self, _: Cache) {} #[inline] fn get_cache(&self) -> Cache { Cache::Stale } #[inline] fn set_interrupt(&self, interrupt: bool) { self.should_interrupt.store(interrupt, Ordering::Relaxed); } #[inline] fn get_interrupt(&self) -> bool { self.should_interrupt.load(Ordering::Relaxed) } fn entries(&self, _: &Lua, input: String) -> Result { let result = match evaluate_with_interrupt( input.trim(), &mut CTX.lock().expect("Failed to acquire Fend context lock"), self, ) { Ok(result) => { result.get_main_result().to_string() } Err(err) => { err } }; Ok(if result.is_empty() { Entries::None } else { Entries::Single(Entry { message: result, exec: None, }) }) } #[inline] fn filter(&self, entries: Entries, _: String) -> Entries { entries } } impl Interrupt for Calculator { fn should_interrupt(&self) -> bool { self.should_interrupt.load(Ordering::Relaxed) } }