runa/crates/runa-actor/src/lib.rs

124 lines
3.0 KiB
Rust
Raw Normal View History

//! 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<Self> {
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<ActorRef>,
}
#[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<ExecutionSnapshot>,
pub queued: Vec<Message>,
pub reserved: Option<Message>,
}
#[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),
}