//! Value contracts for the single-worker actor prototype. use runa_core::ImplementationId; use std::fmt; #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] pub struct ActorRef([u8; 21]); impl ActorRef { pub fn new() -> Self { Self::parse(&nanoid::nanoid!()).expect("Nano ID uses the supported alphabet") } pub fn as_str(&self) -> &str { std::str::from_utf8(&self.0).expect("Nano ID is valid UTF-8") } pub fn parse(value: &str) -> Option { if value.len() != 21 || !value .bytes() .all(|byte| byte.is_ascii_alphanumeric() || matches!(byte, b'_' | b'-')) { return None; } let mut bytes = [0; 21]; bytes.copy_from_slice(value.as_bytes()); Some(Self(bytes)) } } impl Default for ActorRef { fn default() -> Self { Self::new() } } impl fmt::Debug for ActorRef { fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { write!(formatter, "@{}", self.as_str()) } } impl fmt::Display for ActorRef { fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { formatter.write_str(self.as_str()) } } #[cfg(test)] mod tests { use super::ActorRef; #[test] fn generated_actor_references_are_parseable_and_display_without_prefix() { let actor_ref = ActorRef::new(); let parsed = ActorRef::parse(actor_ref.as_str()).expect("generated reference is valid"); assert_eq!(parsed, actor_ref); assert_eq!(actor_ref.to_string().len(), 21); assert_eq!(format!("{actor_ref:?}"), format!("@{actor_ref}")); } #[test] fn parsing_rejects_references_outside_the_url_safe_nanoid_shape() { assert!(ActorRef::parse("too-short").is_none()); assert!(ActorRef::parse("abcdefghijklmnopqrstu!").is_none()); } } #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] pub struct MailboxId(pub u64); #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub struct Message { pub kind: i64, pub value: i64, pub target_ref: Option, } #[derive(Debug, Clone, PartialEq, Eq)] pub enum Status { Idle, Running, Awaiting, Paused, Stopped, Failed(String), } #[derive(Debug, Clone)] pub struct ActorSnapshot { pub actor_ref: ActorRef, pub mailbox: MailboxId, pub implementation: ImplementationId, pub incarnation: u64, pub state: i64, pub status: Status, pub execution: Option, pub queued: Vec, pub reserved: Option, } #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub struct ExecutionSnapshot { pub vm_steps: u64, pub instruction_pointer: usize, pub call_depth: usize, } #[derive(Debug, Clone)] pub enum Event { Spawned(ActorRef), Committed(ActorRef), Failed(ActorRef, String), Stopped(ActorRef), Restarted(ActorRef), Paused(ActorRef), Resumed(ActorRef), InvocationCancelled(ActorRef), BehaviorInstalled(ActorRef, ImplementationId), StateMigrated(ActorRef, i64, i64), }