use std::collections::{HashMap, HashSet};
use mm1_address::subnet::NetMask;
use crate::actor_key::ActorKey;
pub(crate) trait EffectiveActorConfig {
fn netmask(&self) -> NetMask;
fn inbox_size(&self) -> usize;
fn runtime_key(&self) -> Option<&str>;
fn message_tap_key(&self) -> Option<&str>;
}
#[derive(Debug, Clone, Default, serde::Serialize, serde::Deserialize)]
pub(crate) struct ActorConfigNode {
#[serde(flatten, default)]
config: ActorConfig<String>,
#[serde(rename = "/", default)]
sub: HashMap<String, Self>,
}
#[derive(Debug, Clone, Default, serde::Serialize, serde::Deserialize)]
pub(crate) struct ActorConfig<S> {
runtime: Option<S>,
message_tap: Option<S>,
netmask: Option<NetMask>,
inbox_size: Option<usize>,
}
impl ActorConfigNode {
pub(crate) fn select(&self, actor_key: &ActorKey) -> impl EffectiveActorConfig + '_ {
let mut out = ActorConfig {
runtime: self.config.runtime.as_deref(),
message_tap: self.config.message_tap.as_deref(),
netmask: self.config.netmask,
inbox_size: self.config.inbox_size,
};
let mut node = self;
for p in actor_key.path() {
let Some(n) = node.sub.get(p).or_else(|| node.sub.get("_")) else {
break
};
out.runtime = n.config.runtime.as_deref().or(out.runtime);
out.netmask = n.config.netmask.or(out.netmask);
out.inbox_size = n.config.inbox_size.or(out.inbox_size);
out.message_tap = n.config.message_tap.as_deref().or(out.message_tap);
node = n;
}
out
}
pub(crate) fn ensure_runtime_keys_are_valid(
&self,
available_keys: &HashSet<&str>,
) -> Result<(), String> {
let mut used_keys = HashSet::<&str>::new();
let mut q = vec![self];
while let Some(n) = q.pop() {
if let Some(k) = n.config.runtime.as_ref() {
used_keys.insert(k);
}
q.extend(n.sub.values());
}
let invalid_keys = used_keys.difference(available_keys).collect::<Vec<_>>();
if invalid_keys.is_empty() {
Ok(())
} else {
Err(format!("invalid rt-keys: {invalid_keys:?}"))
}
}
}
impl EffectiveActorConfig for ActorConfig<&'_ str> {
fn netmask(&self) -> NetMask {
self.netmask.unwrap_or(defaults::DEFAULT_ACTOR_NETMASK)
}
fn inbox_size(&self) -> usize {
self.inbox_size
.unwrap_or(defaults::DEFAULT_ACTOR_INBOX_SIZE)
}
fn runtime_key(&self) -> Option<&str> {
self.runtime
}
fn message_tap_key(&self) -> Option<&str> {
self.message_tap
}
}
mod defaults {
use super::*;
pub(super) const DEFAULT_ACTOR_NETMASK: NetMask = NetMask::M_56;
pub(super) const DEFAULT_ACTOR_INBOX_SIZE: usize = 1024;
}