Seregon/StratoSDK

StratoSDK is a framework with a declarative approach similar to Flutter/React, written and designed entirely for Rust.

Rust/27.3 KB/No license
crates/strato-ui-core/src/keymap/context.rs
1use std::collections::{HashMap, HashSet};
2 
3#[derive(Clone, Debug, Default, Eq, PartialEq)]
4pub struct Context {
5 pub set: HashSet<&'static str>,
6 pub map: HashMap<&'static str, &'static str>,
7}
8 
9#[derive(Debug, Clone, Eq, PartialEq)]
10pub enum ContextPredicate {
11 Identifier(&'static str),
12 Equal(&'static str, &'static str),
13 NotEqual(&'static str, &'static str),
14 Not(Box<ContextPredicate>),
15 And(Box<ContextPredicate>, Box<ContextPredicate>),
16 Or(Box<ContextPredicate>, Box<ContextPredicate>),
17 Just(bool),
18}
19 
20pub mod macros {
21 /// Returns a context predicate identifier.
22 #[macro_export]
23 macro_rules! id {
24 ($val:literal) => {
25 $crate::keymap::ContextPredicate::Identifier($val)
26 };
27 ($val:expr) => {
28 $crate::keymap::ContextPredicate::Identifier($val)
29 };
30 }
31 pub use id;
32 
33 /// Returns a context predicate which checks whether the given context
34 /// key has a particular value.
35 #[macro_export]
36 macro_rules! eq {
37 ($a:literal, $b:literal) => {
38 $crate::keymap::ContextPredicate::Equal($a, $b)
39 };
40 }
41 pub use eq;
42 
43 /// Returns a context predicate which checks whether the given context
44 /// key does _not_ have a particular value.
45 #[macro_export]
46 macro_rules! ne {
47 ($a:literal, $b:literal) => {
48 $crate::keymap::ContextPredicate::NotEqual($a, $b)
49 };
50 }
51 pub use ne;
52 
53 impl std::ops::Not for ContextPredicate {
54 type Output = ContextPredicate;
55 
56 fn not(self) -> Self::Output {
57 ContextPredicate::Not(Box::new(self))
58 }
59 }
60 
61 impl std::ops::BitAnd for ContextPredicate {
62 type Output = ContextPredicate;
63 
64 fn bitand(self, rhs: Self) -> Self::Output {
65 ContextPredicate::And(Box::new(self), Box::new(rhs))
66 }
67 }
68 
69 impl std::ops::BitOr for ContextPredicate {
70 type Output = ContextPredicate;
71 
72 fn bitor(self, rhs: Self) -> Self::Output {
73 ContextPredicate::Or(Box::new(self), Box::new(rhs))
74 }
75 }
76 
77 /// Returns a context predicate which is always matched.
78 #[macro_export]
79 macro_rules! always {
80 () => {
81 $crate::keymap::ContextPredicate::Just(true)
82 };
83 }
84 pub use always;
85 
86 use super::ContextPredicate;
87}
88 
89impl Context {
90 pub fn extend(&mut self, other: Context) {
91 for v in other.set {
92 self.set.insert(v);
93 }
94 for (k, v) in other.map {
95 self.map.insert(k, v);
96 }
97 }
98}
99 
100impl ContextPredicate {
101 pub fn eval(&self, ctx: &Context) -> bool {
102 match self {
103 Self::Identifier(name) => ctx.set.contains(*name),
104 Self::Equal(left, right) => ctx
105 .map
106 .get(left)
107 .map(|value| value == right)
108 .unwrap_or(false),
109 Self::NotEqual(left, right) => ctx
110 .map
111 .get(left)
112 .map(|value| value != right)
113 .unwrap_or(true),
114 Self::Not(pred) => !pred.eval(ctx),
115 Self::And(left, right) => left.eval(ctx) && right.eval(ctx),
116 Self::Or(left, right) => left.eval(ctx) || right.eval(ctx),
117 Self::Just(val) => *val,
118 }
119 }
120}
121 
122#[cfg(test)]
123#[path = "context_test.rs"]
124mod tests;
125