use rhai::{Dynamic, Engine, EvalAltResult, Map, Position};
use std::fmt;
use std::sync::{Arc, RwLock};
#[derive(Debug, Clone)]
pub struct StateMap {
inner: Arc<RwLock<Map>>,
}
impl StateMap {
pub fn new() -> Self {
Self {
inner: Arc::new(RwLock::new(Map::new())),
}
}
}
impl Default for StateMap {
fn default() -> Self {
Self::new()
}
}
impl fmt::Display for StateMap {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let map = self.inner.read().unwrap();
write!(f, "{:?}", *map)
}
}
#[derive(Debug, Clone)]
pub struct StateNotAvailable;
impl fmt::Display for StateNotAvailable {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "state (unavailable in parallel mode)")
}
}
#[allow(dependency_on_unit_never_type_fallback)]
pub fn register(engine: &mut Engine) {
engine.register_type::<StateMap>();
engine
.register_indexer_get(|state: &mut StateMap, key: &str| -> Dynamic {
let map = state.inner.read().unwrap();
map.get(key).cloned().unwrap_or(Dynamic::UNIT)
})
.register_indexer_set(|state: &mut StateMap, key: &str, value: Dynamic| {
let mut map = state.inner.write().unwrap();
map.insert(key.into(), value);
});
engine
.register_fn("contains", |state: &mut StateMap, key: &str| -> bool {
let map = state.inner.read().unwrap();
map.contains_key(key)
})
.register_fn("get", |state: &mut StateMap, key: &str| -> Dynamic {
let map = state.inner.read().unwrap();
map.get(key).cloned().unwrap_or(Dynamic::UNIT)
})
.register_fn("set", |state: &mut StateMap, key: &str, value: Dynamic| {
let mut map = state.inner.write().unwrap();
map.insert(key.into(), value);
})
.register_fn("len", |state: &mut StateMap| -> i64 {
let map = state.inner.read().unwrap();
map.len() as i64
})
.register_fn("is_empty", |state: &mut StateMap| -> bool {
let map = state.inner.read().unwrap();
map.is_empty()
})
.register_fn("keys", |state: &mut StateMap| -> Vec<Dynamic> {
let map = state.inner.read().unwrap();
map.keys().map(|k| Dynamic::from(k.to_string())).collect()
})
.register_fn("values", |state: &mut StateMap| -> Vec<Dynamic> {
let map = state.inner.read().unwrap();
map.values().cloned().collect()
})
.register_fn("clear", |state: &mut StateMap| {
let mut map = state.inner.write().unwrap();
map.clear()
})
.register_fn("remove", |state: &mut StateMap, key: &str| -> Dynamic {
let mut map = state.inner.write().unwrap();
map.remove(key).unwrap_or(Dynamic::UNIT)
})
.register_fn("mixin", |state: &mut StateMap, other: Map| {
let mut map = state.inner.write().unwrap();
for (k, v) in other {
map.insert(k, v);
}
})
.register_fn("+", |state: StateMap, other: Map| -> StateMap {
let new_state = StateMap::new();
{
let src = state.inner.read().unwrap();
let mut dst = new_state.inner.write().unwrap();
for (k, v) in src.iter() {
dst.insert(k.clone(), v.clone());
}
for (k, v) in other {
dst.insert(k, v);
}
}
new_state
})
.register_fn("+=", |state: &mut StateMap, other: Map| {
let mut map = state.inner.write().unwrap();
for (k, v) in other {
map.insert(k, v);
}
})
.register_fn("fill_with", |state: &mut StateMap, other: Map| {
let mut map = state.inner.write().unwrap();
*map = other;
});
engine.register_fn("to_map", |state: &mut StateMap| -> Map {
let map = state.inner.read().unwrap();
map.clone()
});
engine.register_type::<StateNotAvailable>();
engine
.register_indexer_get(
|_state: &mut StateNotAvailable, _key: &str| -> Result<Dynamic, Box<EvalAltResult>> {
Err(EvalAltResult::ErrorRuntime(
"'state' is not available in --parallel mode. Rerun without --parallel if you need shared mutable state; use track_* helpers for parallel-safe aggregation."
.into(),
Position::NONE,
)
.into())
},
)
.register_indexer_set(
|_state: &mut StateNotAvailable,
_key: &str,
_value: Dynamic|
-> Result<(), Box<EvalAltResult>> {
Err(EvalAltResult::ErrorRuntime(
"'state' is not available in --parallel mode. Rerun without --parallel if you need shared mutable state; use track_* helpers for parallel-safe aggregation."
.into(),
Position::NONE,
)
.into())
},
)
.register_fn(
"contains",
|_state: &mut StateNotAvailable, _key: &str| -> Result<bool, Box<EvalAltResult>> {
Err(EvalAltResult::ErrorRuntime(
"'state' is not available in --parallel mode. Rerun without --parallel if you need shared mutable state; use track_* helpers for parallel-safe aggregation."
.into(),
Position::NONE,
)
.into())
},
)
.register_fn(
"len",
|_state: &mut StateNotAvailable| -> Result<i64, Box<EvalAltResult>> {
Err(EvalAltResult::ErrorRuntime(
"'state' is not available in --parallel mode. Rerun without --parallel if you need shared mutable state; use track_* helpers for parallel-safe aggregation."
.into(),
Position::NONE,
)
.into())
},
)
.register_fn(
"is_empty",
|_state: &mut StateNotAvailable| -> Result<bool, Box<EvalAltResult>> {
Err(EvalAltResult::ErrorRuntime(
"'state' is not available in --parallel mode. Rerun without --parallel if you need shared mutable state; use track_* helpers for parallel-safe aggregation."
.into(),
Position::NONE,
)
.into())
},
)
.register_fn(
"keys",
|_state: &mut StateNotAvailable| -> Result<Vec<Dynamic>, Box<EvalAltResult>> {
Err(EvalAltResult::ErrorRuntime(
"'state' is not available in --parallel mode. Rerun without --parallel if you need shared mutable state; use track_* helpers for parallel-safe aggregation."
.into(),
Position::NONE,
)
.into())
},
)
.register_fn(
"clear",
|_state: &mut StateNotAvailable| -> Result<(), Box<EvalAltResult>> {
Err(EvalAltResult::ErrorRuntime(
"'state' is not available in --parallel mode. Rerun without --parallel if you need shared mutable state; use track_* helpers for parallel-safe aggregation."
.into(),
Position::NONE,
)
.into())
},
)
.register_fn(
"get",
|_state: &mut StateNotAvailable, _key: &str| -> Result<Dynamic, Box<EvalAltResult>> {
Err(EvalAltResult::ErrorRuntime(
"'state' is not available in --parallel mode. Rerun without --parallel if you need shared mutable state; use track_* helpers for parallel-safe aggregation."
.into(),
Position::NONE,
)
.into())
},
)
.register_fn(
"insert",
|_state: &mut StateNotAvailable,
_key: &str,
_value: Dynamic|
-> Result<(), Box<EvalAltResult>> {
Err(EvalAltResult::ErrorRuntime(
"'state' is not available in --parallel mode. Rerun without --parallel if you need shared mutable state; use track_* helpers for parallel-safe aggregation."
.into(),
Position::NONE,
)
.into())
},
);
}