use std::any::{Any, TypeId};
use std::sync::Arc;
use crate::tracker::CompletionTracker;
#[derive(Clone)]
pub struct Envelope {
pub value: Arc<dyn Any + Send + Sync>,
pub(crate) type_id: TypeId,
pub(crate) msg_id: u64,
pub(crate) tracker: Option<Arc<CompletionTracker>>,
pub(crate) origin: u64,
}
impl Envelope {
pub fn new<T: 'static + Send + Sync>(
value: T,
msg_id: u64,
tracker: Option<Arc<CompletionTracker>>,
) -> Self {
Self {
value: Arc::new(value),
type_id: TypeId::of::<T>(),
msg_id,
tracker,
origin: 0, }
}
pub fn with_origin<T: 'static + Send + Sync>(
value: T,
msg_id: u64,
tracker: Option<Arc<CompletionTracker>>,
origin: u64,
) -> Self {
Self {
value: Arc::new(value),
type_id: TypeId::of::<T>(),
msg_id,
tracker,
origin,
}
}
pub fn from_any(
value: Arc<dyn Any + Send + Sync>,
type_id: TypeId,
msg_id: u64,
tracker: Option<Arc<CompletionTracker>>,
) -> Self {
Self {
value,
type_id,
msg_id,
tracker,
origin: 0, }
}
pub fn from_any_with_origin(
value: Arc<dyn Any + Send + Sync>,
type_id: TypeId,
msg_id: u64,
tracker: Option<Arc<CompletionTracker>>,
origin: u64,
) -> Self {
Self {
value,
type_id,
msg_id,
tracker,
origin,
}
}
pub fn type_id(&self) -> TypeId {
self.type_id
}
pub fn msg_id(&self) -> u64 {
self.msg_id
}
pub fn tracker(&self) -> Option<Arc<CompletionTracker>> {
self.tracker.clone()
}
pub fn origin(&self) -> u64 {
self.origin
}
pub fn with_new_origin(&self, origin: u64) -> Self {
Self {
value: self.value.clone(),
type_id: self.type_id,
msg_id: self.msg_id,
tracker: self.tracker.clone(),
origin,
}
}
pub fn without_tracker(&self) -> Self {
Self {
value: self.value.clone(),
type_id: self.type_id,
msg_id: self.msg_id,
tracker: None,
origin: self.origin,
}
}
pub fn downcast_ref<T: 'static>(&self) -> Option<&T> {
self.value.downcast_ref()
}
pub fn downcast<T: 'static + Send + Sync>(&self) -> Option<Arc<T>> {
Arc::downcast(self.value.clone()).ok()
}
pub fn is<T: 'static>(&self) -> bool {
self.type_id == TypeId::of::<T>()
}
}
impl std::fmt::Debug for Envelope {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("Envelope")
.field("type_id", &self.type_id)
.finish()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_envelope_creation() {
let env = Envelope::new("hello".to_string(), 0, None);
assert!(env.is::<String>());
assert!(!env.is::<i32>());
}
#[test]
fn test_envelope_downcast() {
let env = Envelope::new(42i32, 0, None);
assert_eq!(env.downcast_ref::<i32>(), Some(&42));
assert_eq!(env.downcast_ref::<String>(), None);
}
#[test]
fn test_envelope_clone() {
let env1 = Envelope::new("test".to_string(), 0, None);
let env2 = env1.clone();
assert_eq!(env1.downcast_ref::<String>(), env2.downcast_ref::<String>());
}
#[test]
fn test_envelope_msg_id() {
let env = Envelope::new("test".to_string(), 42, None);
assert_eq!(env.msg_id(), 42);
}
#[test]
fn test_envelope_tracker() {
let tracker = Arc::new(CompletionTracker::new(1));
let env = Envelope::new("test".to_string(), 0, Some(tracker.clone()));
assert!(env.tracker().is_some());
let env_no_tracker = Envelope::new("test".to_string(), 0, None);
assert!(env_no_tracker.tracker().is_none());
}
}