use alloc::boxed::Box;
use alloc::sync::Arc;
use alloc::vec::Vec;
use crate::error::PoaResult;
use crate::object_id::ObjectId;
use crate::servant::Servant;
#[derive(Clone)]
pub enum ServantManager {
Activator(Arc<dyn ServantActivator>),
Locator(Arc<dyn ServantLocator>),
}
impl core::fmt::Debug for ServantManager {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
match self {
Self::Activator(_) => f.write_str("ServantManager::Activator"),
Self::Locator(_) => f.write_str("ServantManager::Locator"),
}
}
}
pub trait ServantActivator: Send + Sync {
fn incarnate(&self, oid: &ObjectId, adapter_name: &str) -> PoaResult<Box<dyn Servant>>;
fn etherealize(&self, oid: &ObjectId, adapter_name: &str, _servant: &dyn Servant) {
let _ = (oid, adapter_name);
}
}
pub type ServantLocatorCookie = Vec<u8>;
pub trait ServantLocator: Send + Sync {
fn preinvoke(
&self,
oid: &ObjectId,
adapter_name: &str,
operation: &str,
) -> PoaResult<(Box<dyn Servant>, ServantLocatorCookie)>;
fn postinvoke(
&self,
oid: &ObjectId,
adapter_name: &str,
operation: &str,
cookie: &ServantLocatorCookie,
_servant: &dyn Servant,
) {
let _ = (oid, adapter_name, operation, cookie);
}
}
#[cfg(test)]
#[allow(clippy::expect_used, clippy::unwrap_used, clippy::panic)]
mod tests {
use super::*;
use crate::servant::EchoServant;
use core::sync::atomic::{AtomicUsize, Ordering};
struct TestActivator {
incarnate_count: Arc<AtomicUsize>,
}
impl ServantActivator for TestActivator {
fn incarnate(&self, _: &ObjectId, _: &str) -> PoaResult<Box<dyn Servant>> {
self.incarnate_count.fetch_add(1, Ordering::Relaxed);
Ok(Box::new(EchoServant {
repo_id: "IDL:demo/Echo:1.0".into(),
}))
}
}
#[test]
fn activator_incarnate_is_called() {
let counter = Arc::new(AtomicUsize::new(0));
let act = TestActivator {
incarnate_count: Arc::clone(&counter),
};
let _ = act.incarnate(&ObjectId::system_id(1), "RootPOA").unwrap();
assert_eq!(counter.load(Ordering::Relaxed), 1);
}
#[allow(dead_code)]
fn _dummy_consumes_string(_: String) {}
struct TestLocator;
impl ServantLocator for TestLocator {
fn preinvoke(
&self,
_: &ObjectId,
_: &str,
_: &str,
) -> PoaResult<(Box<dyn Servant>, ServantLocatorCookie)> {
Ok((
Box::new(EchoServant {
repo_id: "IDL:demo/Echo:1.0".into(),
}),
alloc::vec![0xab, 0xcd],
))
}
}
#[test]
fn locator_preinvoke_returns_servant_and_cookie() {
let loc = TestLocator;
let (s, cookie) = loc
.preinvoke(&ObjectId::system_id(1), "RootPOA", "ping")
.unwrap();
assert_eq!(cookie, alloc::vec![0xab, 0xcd]);
assert_eq!(s.invoke("ping", &[1]), alloc::vec![1]);
}
}