aboutsummaryrefslogtreecommitdiff
path: root/.config/awesome/quarrel/native/src/lenses/calculator.rs
blob: 36f980595b7b5fbcaf1e6b3358e7d89c13484f93 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
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<Mutex<Context>> = 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<Self> {
        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<Entries, anyhow::Error> {
        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)
    }
}