use alloc::{boxed::Box, format};
use super::{
errors::LocalError,
round::{PartyId, Protocol, Round},
round_id::RoundId,
};
#[derive_where::derive_where(Debug)]
pub struct BoxedRound<Id: PartyId, P: Protocol<Id>>(Box<dyn Round<Id, Protocol = P>>);
impl<Id: PartyId, P: Protocol<Id>> BoxedRound<Id, P> {
pub fn new_dynamic<R: Round<Id, Protocol = P>>(round: R) -> Self {
Self(Box::new(round))
}
pub(crate) fn as_ref(&self) -> &dyn Round<Id, Protocol = P> {
self.0.as_ref()
}
pub(crate) fn into_boxed(self) -> Box<dyn Round<Id, Protocol = P>> {
self.0
}
fn boxed_type_is<T: 'static>(&self) -> bool {
core::any::TypeId::of::<T>() == self.0.get_type_id()
}
pub fn try_downcast<T: Round<Id>>(self) -> Result<T, Self> {
if self.boxed_type_is::<T>() {
let boxed_downcast = unsafe { Box::<T>::from_raw(Box::into_raw(self.0) as *mut T) };
Ok(*boxed_downcast)
} else {
Err(self)
}
}
pub fn downcast<T: Round<Id>>(self) -> Result<T, LocalError> {
self.try_downcast()
.map_err(|_| LocalError::new(format!("Failed to downcast into type {}", core::any::type_name::<T>())))
}
pub fn downcast_ref<T: Round<Id>>(&self) -> Result<&T, LocalError> {
if self.boxed_type_is::<T>() {
let ptr: *const dyn Round<Id, Protocol = P> = self.0.as_ref();
Ok(unsafe { &*(ptr as *const T) })
} else {
Err(LocalError::new(format!(
"Failed to downcast into type {}",
core::any::type_name::<T>()
)))
}
}
pub fn id(&self) -> RoundId {
self.0.transition_info().id()
}
}