use crate::{ffi::behavior_v0 as ffi, Error, ErrorCode};
pub use ffi::{
ActorId, Guid, LocalBehaviorRegistration, LocalModuleRegistration, OutgoingMessageAddr,
};
#[doc(hidden)]
pub use ffi::API as FFI_API;
#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
pub struct ForeignBehaviorInstanceId(pub ffi::ForeignBehaviorInstanceId);
impl ForeignBehaviorInstanceId {
pub fn pack(type_id: LocalBehaviorTypeId, instance_id: LocalBehaviorInstanceId) -> Self {
Self((u64::from(type_id.0) << 32) | u64::from(instance_id.0))
}
pub fn unpack(&self) -> (LocalBehaviorTypeId, LocalBehaviorInstanceId) {
(
LocalBehaviorTypeId(((self.0 >> 32) & ((1 << 16) - 1)) as u16),
LocalBehaviorInstanceId(self.0 as u32),
)
}
}
#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
pub struct LocalBehaviorInstanceId(pub u32);
#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
pub struct LocalBehaviorTypeId(pub u16);
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub struct AspectAddr {
pub aspect_guid: Guid,
pub actor_id: ActorId,
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct OutgoingMessage {
pub addr: OutgoingMessageAddr,
pub serialized_message: Vec<u8>,
}
impl From<&OutgoingMessage> for ffi::OutgoingMessage {
fn from(msg: &OutgoingMessage) -> Self {
Self::new(msg.addr, &msg.serialized_message)
}
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct ActorsWithAspectIter {
len: usize,
bytes: Vec<u8>,
offset: usize,
}
impl ActorsWithAspectIter {
fn new(bytes: Vec<u8>) -> Self {
let mut offset: usize = 0;
let len = Self::read_u32(&bytes, &mut offset).unwrap_or_default() as usize;
Self { len, bytes, offset }
}
fn read_u32(bytes: &[u8], offset: &mut usize) -> Option<u32> {
let result = bytes
.get((*offset)..(*offset + std::mem::size_of::<ActorId>()))
.map(|slice| u32::from_le_bytes(slice.try_into().unwrap()));
*offset += std::mem::size_of::<ActorId>();
result
}
}
impl Iterator for ActorsWithAspectIter {
type Item = ActorId;
fn next(&mut self) -> Option<Self::Item> {
Self::read_u32(&self.bytes, &mut self.offset)
}
}
impl ExactSizeIterator for ActorsWithAspectIter {
fn len(&self) -> usize {
self.len
}
}
#[derive(Debug, Eq, PartialEq, Clone, Copy)]
pub struct BehaviorAddr {
pub actor_id: ActorId,
pub instance: ForeignBehaviorInstanceId,
}
#[derive(Debug, Eq, PartialEq)]
pub enum IncomingMessageAddr {
Behavior(BehaviorAddr),
Module(Option<ForeignBehaviorInstanceId>),
}
impl IncomingMessageAddr {
pub fn from_raw(actor_id: ActorId, instance: ForeignBehaviorInstanceId) -> Self {
if actor_id == ffi::CONTROLLER_SENTINEL_ACTOR_ID {
let instance = if instance.0 == ffi::INCOMING_MESSAGE_NO_INSTANCE_SENTINEL {
None
} else {
Some(instance)
};
Self::Module(instance)
} else {
Self::Behavior(BehaviorAddr { actor_id, instance })
}
}
pub fn unwrap_behavior(&self) -> BehaviorAddr {
if let IncomingMessageAddr::Behavior(addr) = self {
*addr
} else {
panic!("unexpected non-behavior incoming message");
}
}
}
#[derive(Debug, Eq, PartialEq)]
pub struct IncomingMessage<'a> {
pub addr: IncomingMessageAddr,
pub serialized_message: &'a [u8],
}
impl<'a> From<ffi::IncomingMessage> for IncomingMessage<'a> {
fn from(msg: ffi::IncomingMessage) -> Self {
Self {
addr: IncomingMessageAddr::from_raw(
msg.actor_id,
ForeignBehaviorInstanceId(msg.instance_id),
),
serialized_message: unsafe {
std::slice::from_raw_parts(
msg.serialized_message_ptr as *const u8,
msg.serialized_message_len as usize,
)
},
}
}
}
#[derive(Copy, Clone)]
pub struct Behavior;
impl Behavior {
pub fn aspect_get(&self, addr: AspectAddr) -> Option<Vec<u8>> {
let (aspect_guid_hi, aspect_guid_lo) =
((addr.aspect_guid >> 64) as u64, addr.aspect_guid as u64);
match ffi::aspect_get(aspect_guid_hi, aspect_guid_lo, addr.actor_id) {
Ok(data) => Some(data),
Err(ErrorCode::NotFound) => None,
Err(error) => panic!("Unexpected error: {}", Error::from(error)),
}
}
pub fn send_outgoing_messages(
&self,
outgoing_messages: &[OutgoingMessage],
) -> Result<(), Error> {
let outgoing_messages = outgoing_messages
.iter()
.map(ffi::OutgoingMessage::from)
.collect::<Vec<ffi::OutgoingMessage>>();
ffi::send_outgoing_messages(&outgoing_messages).map_err(Error::from)
}
pub fn iter_actors_with_aspect(&self, aspect_guid: Guid) -> Option<ActorsWithAspectIter> {
let (aspect_guid_hi, aspect_guid_lo) = ((aspect_guid >> 64) as u64, aspect_guid as u64);
match ffi::actors_with_aspect(aspect_guid_hi, aspect_guid_lo) {
Ok(bytes) => Some(ActorsWithAspectIter::new(bytes)),
Err(ErrorCode::NotFound) => None,
Err(error) => panic!("Unexpected error: {}", Error::from(error)),
}
}
pub fn random_seed_value(&self) -> u128 {
*ffi::random_seed_value()
}
}