use std::{
any::Any,
fmt::{Debug, Display},
};
use serde::{Deserialize, Serialize};
use thiserror::Error;
use uuid::Uuid;
use crate::actor::Actor;
const HEX: &[u8; 16] = b"0123456789abcdef";
pub type Ident = [u8; 16];
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Nil;
#[derive(Debug, Clone, Error, Serialize, Deserialize)]
pub enum BindingError {
#[error("invalid identifier")]
InvalidIdent,
#[error("actor not found")]
NotFound,
#[error("actor type id mismatch")]
TypeMismatch,
#[error("actor ref downcast failed")]
DowncastError,
#[cfg(feature = "remote")]
#[error(transparent)]
SerializeError(#[from] postcard::Error),
}
#[derive(Debug, Clone, Error, Serialize, Deserialize)]
pub enum MonitorError {
#[error(transparent)]
BindingError(#[from] BindingError),
#[error("failed to send signal")]
SigSendError,
}
pub(crate) struct Hex<'a, const N: usize>(pub(crate) &'a [u8; N]);
impl<T: Actor> From<&T> for Nil {
fn from(_: &T) -> Self {
Self
}
}
impl Display for Hex<'_, 16> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let mut out = [0u8; 32];
for (i, byte) in self.0.iter().enumerate() {
out[i * 2] = HEX[(byte >> 4) as usize];
out[i * 2 + 1] = HEX[(byte & 0x0f) as usize];
}
write!(f, "{}", unsafe { std::str::from_utf8_unchecked(&out) })
}
}
impl Display for Hex<'_, 32> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let mut out = [0u8; 64];
for (i, byte) in self.0.iter().enumerate() {
out[i * 2] = HEX[(byte >> 4) as usize];
out[i * 2 + 1] = HEX[(byte & 0x0f) as usize];
}
write!(f, "{}", unsafe { std::str::from_utf8_unchecked(&out) })
}
}
pub(crate) fn parse_ident(s: &str) -> Result<Ident, BindingError> {
match Uuid::try_parse(s) {
Err(_) => {
let bytes = s.as_bytes();
if bytes.len() > 16 {
return Err(BindingError::InvalidIdent);
}
let mut ident = [0u8; 16];
ident[..bytes.len()].copy_from_slice(bytes);
Ok(ident)
}
Ok(uuid) => Ok(*uuid.as_bytes()),
}
}
pub(crate) fn panic_msg(payload: Box<dyn Any + Send>) -> String {
if let Some(s) = payload.downcast_ref::<&str>() {
s.to_string()
} else if let Ok(s) = payload.downcast::<String>() {
*s
} else {
"<non-string panic payload>".to_string()
}
}