mod ffi {
pub use crate::ffi::behavior_controller_v0::{self as v0, *};
pub use crate::ffi::behavior_controller_v1::{self as v1, *};
}
use crate::Error;
pub use ffi::{
ActorId, AspectAddr, BehaviorMeta, BehaviorModuleId, BehaviorModuleMeta,
BehaviorModuleRegistration, BehaviorRegistration, BehaviorTypeId, Guid, INVALID_GUID_COMPONENT,
};
use std::rc::Rc;
use std::task::Poll;
#[doc(hidden)]
pub use ffi::v1::API as FFI_API;
#[derive(Hash, PartialEq, Eq)]
struct BehaviorInstanceInner(ffi::BehaviorInstanceId);
impl Drop for BehaviorInstanceInner {
fn drop(&mut self) {
ffi::instance_destroy(self.0);
}
}
#[derive(Clone, Hash, PartialEq, Eq)]
pub struct BehaviorInstance(Rc<BehaviorInstanceInner>);
impl BehaviorInstance {
pub fn new(type_id: BehaviorTypeId, params: &str) -> Self {
Self(Rc::new(BehaviorInstanceInner(ffi::instance_create(
type_id.0, params,
))))
}
pub fn restore(type_id: BehaviorTypeId, bytes: &[u8]) -> Self {
Self(Rc::new(BehaviorInstanceInner(ffi::instance_restore(
type_id.0, bytes,
))))
}
pub fn deep_clone(instance: &Self) -> Self {
Self(Rc::new(BehaviorInstanceInner(ffi::instance_clone(
instance.0 .0,
))))
}
pub fn persist(&self) -> Vec<u8> {
ffi::instance_persist(self.0 .0)
}
pub fn type_id(&self) -> BehaviorTypeId {
BehaviorTypeId((self.0 .0 >> 32) as ffi::BehaviorTypeIdInner)
}
}
impl std::fmt::Debug for BehaviorInstance {
fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(fmt, "BehaviorInstance({})", self.0 .0)
}
}
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub struct AspectUpsert<'a> {
pub addr: AspectAddr,
pub serialized_aspect: &'a [u8],
}
impl<'a> From<AspectUpsert<'a>> for ffi::AspectUpsert {
fn from(upsert: AspectUpsert<'a>) -> Self {
Self::new(upsert.addr, upsert.serialized_aspect)
}
}
#[derive(Debug, Eq, PartialEq)]
enum IncomingMessageAddr {
Behavior {
actor_id: ActorId,
instance: BehaviorInstance,
},
Module {
module_id: u16,
instance: Option<BehaviorInstance>,
},
}
#[derive(Debug, Eq, PartialEq)]
pub struct IncomingMessage<'a> {
addr: IncomingMessageAddr,
pub serialized_message: &'a [u8],
}
impl<'a> IncomingMessage<'a> {
pub fn new_to_instance(
instance: BehaviorInstance,
actor_id: ActorId,
serialized_message: &'a [u8],
) -> Self {
Self {
addr: IncomingMessageAddr::Behavior { instance, actor_id },
serialized_message,
}
}
pub fn new_to_module(
type_id: BehaviorTypeId,
instance: Option<BehaviorInstance>,
serialized_message: &'a [u8],
) -> Self {
let module_id = (type_id.0 >> 16) as u16;
if let Some(ref instance) = instance {
assert_eq!(
instance.0 .0 >> 48,
u64::from(module_id),
"behavior type and behavior instance must refer to the same behavior module"
);
}
Self {
addr: IncomingMessageAddr::Module {
module_id,
instance,
},
serialized_message,
}
}
}
impl<'a> From<&IncomingMessage<'a>> for ffi::IncomingMessage {
fn from(msg: &IncomingMessage<'a>) -> Self {
let (actor_id, instance_id) = match &msg.addr {
IncomingMessageAddr::Behavior { actor_id, instance } => (*actor_id, instance.0 .0),
IncomingMessageAddr::Module {
module_id,
instance,
} => {
let instance = match instance {
Some(instance) => instance.0 .0,
None => {
(u64::from(*module_id) << 48) | ffi::INCOMING_MESSAGE_NO_INSTANCE_SENTINEL
}
};
(ffi::CONTROLLER_SENTINEL_ACTOR_ID, instance)
}
};
Self::new(instance_id, actor_id, msg.serialized_message)
}
}
#[derive(Clone, Debug, Eq, PartialEq, Copy)]
pub enum OutgoingMessageAddr {
Actor {
actor_id: ActorId,
behavior_guid: Option<u128>,
},
Controller,
}
impl From<&ffi::OutgoingMessageAddr> for OutgoingMessageAddr {
fn from(addr: &ffi::OutgoingMessageAddr) -> Self {
if addr.to_actor_id == ffi::CONTROLLER_SENTINEL_ACTOR_ID {
Self::Controller
} else {
Self::Actor {
actor_id: addr.to_actor_id,
behavior_guid: addr.guid(),
}
}
}
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct OutgoingMessage<'a> {
addr: OutgoingMessageAddr,
serialized_message: &'a [u8],
}
impl<'a> OutgoingMessage<'a> {
pub fn addr(&self) -> OutgoingMessageAddr {
self.addr
}
pub fn msg(&self) -> &'a [u8] {
self.serialized_message
}
}
pub struct OutgoingMessages {
bytes: Vec<u8>,
}
impl OutgoingMessages {
pub fn iter(&self) -> OutgoingMessagesIter<'_> {
OutgoingMessagesIter {
outgoing_messages: self,
offset: 0,
}
}
fn read_outgoing_msg_ffi(bytes: &[u8], offset: &mut usize) -> Option<ffi::OutgoingMessage> {
const OUTGOING_MSG_SIZE: usize = std::mem::size_of::<ffi::OutgoingMessage>();
let result = bytes
.get((*offset)..(*offset + OUTGOING_MSG_SIZE))
.map(|slice| unsafe {
std::mem::transmute::<[u8; OUTGOING_MSG_SIZE], ffi::OutgoingMessage>(
slice.try_into().unwrap(),
)
});
*offset += OUTGOING_MSG_SIZE;
result
}
fn read_outgoing_message<'a>(
bytes: &'a [u8],
offset: &mut usize,
) -> Option<OutgoingMessage<'a>> {
Self::read_outgoing_msg_ffi(bytes, offset).map(|outgoing| {
let slice = bytes
.get((*offset)..((*offset) + outgoing.serialized_message_len as usize))
.unwrap();
*offset += outgoing.serialized_message_len as usize;
OutgoingMessage {
addr: OutgoingMessageAddr::from(&outgoing.addr),
serialized_message: slice,
}
})
}
}
pub struct OutgoingMessagesIter<'a> {
outgoing_messages: &'a OutgoingMessages,
offset: usize,
}
impl<'a> Iterator for OutgoingMessagesIter<'a> {
type Item = OutgoingMessage<'a>;
fn next(&mut self) -> Option<Self::Item> {
OutgoingMessages::read_outgoing_message(&self.outgoing_messages.bytes, &mut self.offset)
}
}
pub struct LoadModuleFuture {
handle: ffi::LoadModuleHandle,
}
impl std::future::Future for LoadModuleFuture {
type Output = Result<Vec<u8>, Error>;
fn poll(
self: std::pin::Pin<&mut Self>,
_cx: &mut std::task::Context<'_>,
) -> Poll<Self::Output> {
match ffi::retrieve_module(self.handle) {
Ok(bytes) => Poll::Ready(Ok(bytes)),
Err(crate::ErrorCode::Unavailable) => Poll::Pending,
Err(error_code) => Poll::Ready(Err(Error::from(error_code))),
}
}
}
pub struct ListModulesFuture {
handle: ffi::ListModulesHandle,
}
impl std::future::Future for ListModulesFuture {
type Output = Result<Vec<u8>, Error>;
fn poll(
self: std::pin::Pin<&mut Self>,
_cx: &mut std::task::Context<'_>,
) -> Poll<Self::Output> {
match ffi::retrieve_module_list(self.handle) {
Ok(bytes) => Poll::Ready(Ok(bytes)),
Err(crate::ErrorCode::Unavailable) => Poll::Pending,
Err(error_code) => Poll::Ready(Err(Error::from(error_code))),
}
}
}
#[derive(Copy, Clone)]
pub struct BehaviorController {}
impl BehaviorController {
pub fn list_modules(&self) -> Vec<u8> {
ffi::list_modules()
}
#[inline]
pub fn list_behavior_modules(&self) -> ListModulesFuture {
ListModulesFuture {
handle: ffi::list_behavior_modules(),
}
}
pub fn instances_handle_messages(&self, messages: &[IncomingMessage<'_>]) -> OutgoingMessages {
let message_data = messages
.iter()
.map(ffi::IncomingMessage::from)
.collect::<Vec<ffi::IncomingMessage>>();
OutgoingMessages {
bytes: ffi::instances_handle_messages(&message_data),
}
}
pub fn aspect_upsert(&self, upserts: &[AspectUpsert<'_>]) {
let upserts = upserts
.iter()
.copied()
.map(ffi::AspectUpsert::from)
.collect::<Vec<ffi::AspectUpsert>>();
ffi::aspect_upsert(&upserts);
}
pub fn aspect_remove(&self, removes: &[AspectAddr]) {
ffi::aspect_remove(removes);
}
pub fn aspect_reset_all(&self) {
ffi::aspect_reset_all();
}
pub fn publish(&self, id: &BehaviorModuleId) -> Result<BehaviorModuleId, Error> {
Ok(BehaviorModuleId::new(ffi::publish(id)?))
}
pub fn load_behavior_module(&self, id: &BehaviorModuleId) -> Result<LoadModuleFuture, Error> {
let handle = ffi::load_module(id)?;
Ok(LoadModuleFuture { handle })
}
}