use crate::codec::{Codec, CodecName};
use crate::erasure::error::{ErasureError, ErasureResult};
use crate::erasure::neuron::{NeuronErased, erase_neuron};
use crate::erasure::payload::{
PayloadErased, PayloadErasedWrapper, PayloadRawErased, PayloadRawErasedWrapper,
};
use crate::erasure::reactant::{ErrorReactantErased, ReactantErased, ReactantRawErased};
use crate::payload::PayloadRaw;
use crate::reactant::{ErrorReactant, Reactant, ReactantRaw};
use crate::synapse::{RawSender, SynapseError, SynapseExternal, SynapseInternal};
use std::any::{Any, TypeId};
use std::future::Future;
use std::marker::PhantomData;
use std::pin::Pin;
use std::sync::Arc;
use parking_lot::RwLock;
pub trait SynapseInternalErased: Send + Sync + 'static {
fn as_any(&self) -> &dyn Any;
fn neuron(&self) -> Arc<dyn NeuronErased + Send + Sync + 'static>;
fn neuron_name(&self) -> String;
fn codec_name(&self) -> String;
fn neuron_schema(&self) -> String;
fn payload_type_id(&self) -> TypeId;
fn codec_type_id(&self) -> TypeId;
fn clone_to_box(&self) -> Box<dyn SynapseInternalErased + Send + Sync + 'static>;
fn clone_to_arc(&self) -> Arc<RwLock<dyn SynapseInternalErased + Send + Sync + 'static>>;
#[allow(clippy::type_complexity)]
fn transduce_erased(
&self,
payload: Arc<dyn PayloadErased + Send + Sync + 'static>,
) -> Pin<Box<dyn Future<Output = Result<Vec<()>, SynapseError>> + Send + 'static>>;
#[allow(clippy::type_complexity)]
fn transmit_erased(
&self,
payload: Arc<dyn PayloadErased + Send + Sync + 'static>,
) -> Pin<Box<dyn Future<Output = Result<Vec<()>, SynapseError>> + Send + 'static>>;
fn react_erased(
&mut self,
reactants: Vec<Arc<dyn ReactantErased + Send + Sync + 'static>>,
error_reactants: Vec<Arc<dyn ErrorReactantErased + Send + Sync>>,
);
}
pub trait SynapseExternalErased: Send + Sync + 'static {
fn as_any(&self) -> &dyn Any;
fn neuron(&self) -> Arc<dyn NeuronErased + Send + Sync + 'static>;
fn neuron_name(&self) -> String;
fn codec_name(&self) -> String;
fn neuron_schema(&self) -> String;
fn payload_type_id(&self) -> TypeId;
fn codec_type_id(&self) -> TypeId;
fn clone_to_box(&self) -> Box<dyn SynapseExternalErased + Send + Sync + 'static>;
fn clone_to_arc(&self) -> Arc<RwLock<dyn SynapseExternalErased + Send + Sync + 'static>>;
#[allow(clippy::type_complexity)]
fn transduce_erased(
&self,
payload: Arc<dyn PayloadRawErased + Send + Sync + 'static>,
) -> Pin<Box<dyn Future<Output = Result<(Vec<()>, Vec<()>), SynapseError>> + Send + 'static>>;
#[allow(clippy::type_complexity)]
fn transmit_erased(
&self,
payload: Arc<dyn PayloadRawErased + Send + Sync + 'static>,
) -> Pin<Box<dyn Future<Output = Result<(Vec<()>, Vec<()>), SynapseError>> + Send + 'static>>;
fn react_erased(
&mut self,
reactants: Vec<Arc<dyn ReactantErased + Send + Sync + 'static>>,
raw_reactants: Vec<Arc<dyn ReactantRawErased + Send + Sync + 'static>>,
error_reactants: Vec<Arc<dyn ErrorReactantErased + Send + Sync>>,
);
}
pub struct SimpleSynapseInternalErased {
neuron: Arc<dyn NeuronErased + Send + Sync + 'static>,
reactants: Arc<RwLock<Vec<Arc<dyn ReactantErased + Send + Sync + 'static>>>>,
error_reactants: Arc<RwLock<Vec<Arc<dyn ErrorReactantErased + Send + Sync + 'static>>>>,
}
impl SimpleSynapseInternalErased {
pub fn new(neuron: Arc<dyn NeuronErased + Send + Sync + 'static>) -> Self {
Self {
neuron,
reactants: Arc::new(RwLock::new(Vec::new())),
error_reactants: Arc::new(RwLock::new(Vec::new())),
}
}
}
impl SynapseInternalErased for SimpleSynapseInternalErased {
fn as_any(&self) -> &dyn Any {
self
}
fn neuron(&self) -> Arc<dyn NeuronErased + Send + Sync + 'static> {
self.neuron.clone()
}
fn neuron_name(&self) -> String {
self.neuron.name()
}
fn codec_name(&self) -> String {
"erased".to_string()
}
fn neuron_schema(&self) -> String {
self.neuron.schema()
}
fn payload_type_id(&self) -> TypeId {
self.neuron.payload_type_id()
}
fn codec_type_id(&self) -> TypeId {
self.neuron.codec_type_id()
}
fn clone_to_box(&self) -> Box<dyn SynapseInternalErased + Send + Sync + 'static> {
Box::new(Self {
neuron: self.neuron.clone(),
reactants: self.reactants.clone(),
error_reactants: self.error_reactants.clone(),
})
}
fn clone_to_arc(&self) -> Arc<RwLock<dyn SynapseInternalErased + Send + Sync + 'static>> {
Arc::new(RwLock::new(Self {
neuron: self.neuron.clone(),
reactants: self.reactants.clone(),
error_reactants: self.error_reactants.clone(),
}))
}
fn transduce_erased(
&self,
payload: Arc<dyn PayloadErased + Send + Sync + 'static>,
) -> Pin<Box<dyn Future<Output = Result<Vec<()>, SynapseError>> + Send + 'static>> {
self.transmit_erased(payload)
}
fn transmit_erased(
&self,
payload: Arc<dyn PayloadErased + Send + Sync + 'static>,
) -> Pin<Box<dyn Future<Output = Result<Vec<()>, SynapseError>> + Send + 'static>> {
let reactants = self.reactants.read().clone();
let error_reactants = self.error_reactants.read().clone();
Box::pin(async move {
let mut futures = Vec::new();
for reactant in reactants {
futures.push(reactant.react_erased(payload.clone()));
}
let results = futures_util::future::join_all(futures).await;
let mut errors = Vec::new();
let mut successes = Vec::new();
for res in results {
match res {
Ok(_) => successes.push(()),
Err(e) => errors.push(Arc::new(e)),
}
}
if !errors.is_empty() && !error_reactants.is_empty() {
let mut err_futures = Vec::new();
for err in errors {
for err_reactant in &error_reactants {
err_futures.push(err_reactant.react_error_erased(err.clone(), payload.clone()));
}
}
futures_util::future::join_all(err_futures).await;
}
Ok(successes)
})
}
fn react_erased(
&mut self,
reactants: Vec<Arc<dyn ReactantErased + Send + Sync + 'static>>,
error_reactants: Vec<Arc<dyn ErrorReactantErased + Send + Sync>>,
) {
self.reactants.write().extend(reactants);
self.error_reactants.write().extend(error_reactants);
}
}
pub struct SimpleSynapseExternalErased {
neuron: Arc<dyn NeuronErased + Send + Sync + 'static>,
reactants: Arc<RwLock<Vec<Arc<dyn ReactantErased + Send + Sync + 'static>>>>,
raw_reactants: Arc<RwLock<Vec<Arc<dyn ReactantRawErased + Send + Sync + 'static>>>>,
error_reactants: Arc<RwLock<Vec<Arc<dyn ErrorReactantErased + Send + Sync + 'static>>>>,
sender: Option<Arc<dyn RawSender>>,
}
impl SimpleSynapseExternalErased {
pub fn new(neuron: Arc<dyn NeuronErased + Send + Sync + 'static>) -> Self {
Self {
neuron,
reactants: Arc::new(RwLock::new(Vec::new())),
raw_reactants: Arc::new(RwLock::new(Vec::new())),
error_reactants: Arc::new(RwLock::new(Vec::new())),
sender: None,
}
}
pub fn new_with_sender(
neuron: Arc<dyn NeuronErased + Send + Sync + 'static>,
sender: Arc<dyn RawSender>,
) -> Self {
Self {
neuron,
reactants: Arc::new(RwLock::new(Vec::new())),
raw_reactants: Arc::new(RwLock::new(Vec::new())),
error_reactants: Arc::new(RwLock::new(Vec::new())),
sender: Some(sender),
}
}
}
impl SynapseExternalErased for SimpleSynapseExternalErased {
fn as_any(&self) -> &dyn Any {
self
}
fn neuron(&self) -> Arc<dyn NeuronErased + Send + Sync + 'static> {
self.neuron.clone()
}
fn neuron_name(&self) -> String {
self.neuron.name()
}
fn codec_name(&self) -> String {
"erased".to_string()
}
fn neuron_schema(&self) -> String {
self.neuron.schema()
}
fn payload_type_id(&self) -> TypeId {
self.neuron.payload_type_id()
}
fn codec_type_id(&self) -> TypeId {
self.neuron.codec_type_id()
}
fn clone_to_box(&self) -> Box<dyn SynapseExternalErased + Send + Sync + 'static> {
Box::new(Self {
neuron: self.neuron.clone(),
reactants: self.reactants.clone(),
raw_reactants: self.raw_reactants.clone(),
error_reactants: self.error_reactants.clone(),
sender: self.sender.clone(),
})
}
fn clone_to_arc(&self) -> Arc<RwLock<dyn SynapseExternalErased + Send + Sync + 'static>> {
Arc::new(RwLock::new(Self {
neuron: self.neuron.clone(),
reactants: self.reactants.clone(),
raw_reactants: self.raw_reactants.clone(),
error_reactants: self.error_reactants.clone(),
sender: self.sender.clone(),
}))
}
fn transduce_erased(
&self,
payload: Arc<dyn PayloadRawErased + Send + Sync + 'static>,
) -> Pin<Box<dyn Future<Output = Result<(Vec<()>, Vec<()>), SynapseError>> + Send + 'static>>
{
let raw_reactants = self.raw_reactants.read().clone();
Box::pin(async move {
let mut raw_futures = Vec::new();
for r in raw_reactants {
raw_futures.push(r.react_erased(payload.clone()));
}
let results = futures_util::future::join_all(raw_futures).await;
let mut successes = Vec::new();
for res in results {
if res.is_ok() {
successes.push(());
}
}
Ok((vec![], successes))
})
}
fn transmit_erased(
&self,
payload: Arc<dyn PayloadRawErased + Send + Sync + 'static>,
) -> Pin<Box<dyn Future<Output = Result<(Vec<()>, Vec<()>), SynapseError>> + Send + 'static>>
{
let sender = self.sender.clone();
let topic = self.neuron.name();
Box::pin(async move {
if let Some(s) = sender {
let bytes = payload.get_bytes();
let data = bytes.as_ref().clone();
s.send(&topic, data).await.map_err(|e| SynapseError::Dendrite(crate::dendrite::DendriteError::Other(e)))?;
}
Ok((vec![], vec![]))
})
}
fn react_erased(
&mut self,
reactants: Vec<Arc<dyn ReactantErased + Send + Sync + 'static>>,
raw_reactants: Vec<Arc<dyn ReactantRawErased + Send + Sync + 'static>>,
error_reactants: Vec<Arc<dyn ErrorReactantErased + Send + Sync>>,
) {
self.reactants.write().extend(reactants);
self.raw_reactants.write().extend(raw_reactants);
self.error_reactants.write().extend(error_reactants);
}
}
pub struct SynapseInternalErasedWrapper<T, C, S> {
synapse: Arc<RwLock<S>>,
erased_reactants: Vec<Arc<dyn ReactantErased + Send + Sync + 'static>>,
_phantom: PhantomData<(T, C)>,
}
impl<T, C, S> SynapseInternalErasedWrapper<T, C, S>
where
T: Send + Sync + 'static,
C: Codec<T> + CodecName + Send + Sync + 'static,
S: SynapseInternal<T, C> + Send + Sync + 'static,
{
pub fn new(synapse: S) -> Self {
Self {
synapse: Arc::new(RwLock::new(synapse)),
erased_reactants: Vec::new(),
_phantom: PhantomData,
}
}
pub fn from_typed_synapse(
synapse: S,
) -> Arc<RwLock<dyn SynapseInternalErased + Send + Sync + 'static>>
where
T: 'static,
C: 'static,
S: 'static,
{
Arc::new(RwLock::new(Self::new(synapse)))
}
pub fn to_typed_synapse<U, D, R>(&self) -> ErasureResult<Arc<RwLock<R>>>
where
U: Send + Sync + 'static,
D: Codec<U> + CodecName + Send + Sync + 'static,
R: SynapseInternal<U, D> + Send + Sync + 'static,
{
if TypeId::of::<T>() == TypeId::of::<U>() && TypeId::of::<C>() == TypeId::of::<D>() {
unsafe {
Ok(std::mem::transmute::<Arc<RwLock<S>>, Arc<RwLock<R>>>(
self.synapse.clone(),
))
}
} else {
Err(ErasureError::SynapseTypeMismatch {
expected_payload_type: TypeId::of::<U>(),
expected_codec_type: TypeId::of::<D>(),
actual_payload_type: TypeId::of::<T>(),
actual_codec_type: TypeId::of::<C>(),
})
}
}
}
impl<T, C, S> SynapseInternalErased for SynapseInternalErasedWrapper<T, C, S>
where
T: Send + Sync + 'static,
C: Codec<T> + CodecName + Send + Sync + 'static,
S: SynapseInternal<T, C> + Send + Sync + 'static,
{
fn as_any(&self) -> &dyn Any {
self
}
fn neuron(&self) -> Arc<dyn NeuronErased + Send + Sync + 'static> {
erase_neuron(self.synapse.read().neuron())
}
fn transduce_erased(
&self,
payload: Arc<dyn PayloadErased + Send + Sync + 'static>,
) -> Pin<Box<dyn Future<Output = Result<Vec<()>, SynapseError>> + Send + 'static>> {
if let Some(wrapper) = payload
.as_any()
.downcast_ref::<PayloadErasedWrapper<T, C>>()
{
let typed_payload = wrapper.get_typed_payload();
let synapse_arc = self.synapse.clone();
let future = {
let synapse = synapse_arc.read();
synapse.transduce(typed_payload)
};
Box::pin(future)
} else {
let neuron_name = self.neuron_name();
Box::pin(async move { Err(SynapseError::NeuronTypeConversion { neuron_name }) })
}
}
fn transmit_erased(
&self,
payload: Arc<dyn PayloadErased + Send + Sync + 'static>,
) -> Pin<Box<dyn Future<Output = Result<Vec<()>, SynapseError>> + Send + 'static>> {
if let Some(wrapper) = payload
.as_any()
.downcast_ref::<PayloadErasedWrapper<T, C>>()
{
let typed_payload = wrapper.get_typed_payload();
let synapse_arc = self.synapse.clone();
let future = {
let synapse = synapse_arc.read();
synapse.transmit(typed_payload)
};
Box::pin(future)
} else {
let neuron_name = self.neuron_name();
Box::pin(async move { Err(SynapseError::NeuronTypeConversion { neuron_name }) })
}
}
fn react_erased(
&mut self,
reactants: Vec<Arc<dyn ReactantErased + Send + Sync + 'static>>,
error_reactants: Vec<Arc<dyn ErrorReactantErased + Send + Sync>>,
) {
if reactants.is_empty() && error_reactants.is_empty() {
return; }
let typed_reactants: Vec<_> = reactants
.into_iter()
.filter_map(|erased_reactant| {
if erased_reactant.payload_type_id() != TypeId::of::<T>()
|| erased_reactant.codec_type_id() != TypeId::of::<C>()
{
return None;
}
let any_arc = erased_reactant.clone_to_any();
any_arc
.downcast::<Arc<dyn Reactant<T, C> + Send + Sync + 'static>>()
.ok()
.map(|boxed_arc| (*boxed_arc).clone())
})
.collect();
let typed_error_reactants: Vec<_> = error_reactants
.into_iter()
.filter_map(|erased_reactant| {
if erased_reactant.payload_type_id() != TypeId::of::<T>()
|| erased_reactant.codec_type_id() != TypeId::of::<C>()
{
return None;
}
let any_arc = erased_reactant.clone_to_any();
any_arc
.downcast::<Arc<dyn ErrorReactant<T, C> + Send + Sync + 'static>>()
.ok()
.map(|boxed_arc| (*boxed_arc).clone())
})
.collect();
if !typed_reactants.is_empty() || !typed_error_reactants.is_empty() {
let _ = self
.synapse
.write()
.react(typed_reactants, typed_error_reactants);
}
}
fn neuron_name(&self) -> String {
self.synapse.read().neuron().name()
}
fn codec_name(&self) -> String {
C::name().to_string()
}
fn neuron_schema(&self) -> String {
self.synapse.read().neuron().schema()
}
fn payload_type_id(&self) -> TypeId {
TypeId::of::<T>()
}
fn codec_type_id(&self) -> TypeId {
TypeId::of::<C>()
}
fn clone_to_box(&self) -> Box<dyn SynapseInternalErased + Send + Sync + 'static> {
Box::new(Self {
synapse: self.synapse.clone(),
erased_reactants: self.erased_reactants.clone(),
_phantom: PhantomData,
})
}
fn clone_to_arc(&self) -> Arc<RwLock<dyn SynapseInternalErased + Send + Sync + 'static>> {
Arc::new(RwLock::new(Self {
synapse: self.synapse.clone(),
erased_reactants: self.erased_reactants.clone(),
_phantom: PhantomData,
}))
}
}
pub struct SynapseExternalErasedWrapper<T, C, S> {
synapse: Arc<RwLock<S>>,
_phantom: PhantomData<(T, C)>,
}
impl<T, C, S> SynapseExternalErasedWrapper<T, C, S>
where
T: Send + Sync + 'static,
C: Codec<T> + CodecName + Send + Sync + 'static,
S: SynapseExternal<T, C> + Send + Sync + 'static,
{
pub fn new(synapse: S) -> Self {
Self {
synapse: Arc::new(RwLock::new(synapse)),
_phantom: PhantomData,
}
}
pub fn from_typed_synapse(
synapse: S,
) -> Arc<RwLock<dyn SynapseExternalErased + Send + Sync + 'static>>
where
T: 'static,
C: 'static,
S: 'static,
{
Arc::new(RwLock::new(Self::new(synapse)))
}
pub fn to_typed_synapse<U, D, R>(&self) -> ErasureResult<Arc<RwLock<R>>>
where
U: Send + Sync + 'static,
D: Codec<U> + CodecName + Send + Sync + 'static,
R: SynapseExternal<U, D> + Send + Sync + 'static,
{
if TypeId::of::<T>() == TypeId::of::<U>() && TypeId::of::<C>() == TypeId::of::<D>() {
unsafe {
Ok(std::mem::transmute::<Arc<RwLock<S>>, Arc<RwLock<R>>>(
self.synapse.clone(),
))
}
} else {
Err(ErasureError::SynapseTypeMismatch {
expected_payload_type: TypeId::of::<U>(),
expected_codec_type: TypeId::of::<D>(),
actual_payload_type: TypeId::of::<T>(),
actual_codec_type: TypeId::of::<C>(),
})
}
}
}
impl<T, C, S> SynapseExternalErased for SynapseExternalErasedWrapper<T, C, S>
where
T: Send + Sync + 'static,
C: Codec<T> + CodecName + Send + Sync + 'static,
S: SynapseExternal<T, C> + Send + Sync + 'static,
{
fn as_any(&self) -> &dyn Any {
self
}
fn neuron(&self) -> Arc<dyn NeuronErased + Send + Sync + 'static> {
erase_neuron(self.synapse.read().neuron())
}
fn transduce_erased(
&self,
payload: Arc<dyn PayloadRawErased + Send + Sync + 'static>,
) -> Pin<Box<dyn Future<Output = Result<(Vec<()>, Vec<()>), SynapseError>> + Send + 'static>>
{
if let Some(wrapper) = payload
.as_any()
.downcast_ref::<PayloadRawErasedWrapper<T, C>>()
{
let typed_payload = wrapper.get_payload_raw();
let synapse_arc = self.synapse.clone();
let future = {
let synapse = synapse_arc.read();
synapse.transduce(typed_payload)
};
Box::pin(future)
} else {
let synapse_arc = self.synapse.clone();
let bytes = payload.get_bytes();
let trace = payload.get_trace_context();
let future_res = {
let synapse = synapse_arc.read();
let typed_payload = Arc::new(PayloadRaw::from_parts(
bytes,
synapse.neuron().clone(),
trace,
));
synapse.transduce(typed_payload)
};
Box::pin(future_res)
}
}
fn transmit_erased(
&self,
payload: Arc<dyn PayloadRawErased + Send + Sync + 'static>,
) -> Pin<Box<dyn Future<Output = Result<(Vec<()>, Vec<()>), SynapseError>> + Send + 'static>>
{
if let Some(wrapper) = payload
.as_any()
.downcast_ref::<PayloadRawErasedWrapper<T, C>>()
{
let typed_payload = wrapper.get_payload_raw();
let synapse_arc = self.synapse.clone();
let future = {
let synapse = synapse_arc.read();
synapse.transmit(typed_payload)
};
Box::pin(future)
} else {
let synapse_arc = self.synapse.clone();
let bytes = payload.get_bytes();
let trace = payload.get_trace_context();
let future_res = {
let synapse = synapse_arc.read();
let typed_payload = Arc::new(PayloadRaw::from_parts(
bytes,
synapse.neuron().clone(),
trace,
));
synapse.transmit(typed_payload)
};
Box::pin(future_res)
}
}
fn react_erased(
&mut self,
reactants: Vec<Arc<dyn ReactantErased + Send + Sync + 'static>>,
raw_reactants: Vec<Arc<dyn ReactantRawErased + Send + Sync + 'static>>,
error_reactants: Vec<Arc<dyn ErrorReactantErased + Send + Sync>>,
) {
if reactants.is_empty() && raw_reactants.is_empty() && error_reactants.is_empty() {
return; }
let typed_reactants: Vec<_> = reactants
.into_iter()
.filter_map(|erased_reactant| {
if erased_reactant.payload_type_id() != TypeId::of::<T>()
|| erased_reactant.codec_type_id() != TypeId::of::<C>()
{
return None;
}
let any_arc = erased_reactant.clone_to_any();
any_arc
.downcast::<Arc<dyn Reactant<T, C> + Send + Sync + 'static>>()
.ok()
.map(|boxed_arc| (*boxed_arc).clone())
})
.collect();
let typed_raw_reactants: Vec<_> = raw_reactants
.into_iter()
.filter_map(|erased_reactant| {
if erased_reactant.payload_type_id() != TypeId::of::<T>()
|| erased_reactant.codec_type_id() != TypeId::of::<C>()
{
return None;
}
let any_arc = erased_reactant.clone_to_any();
any_arc
.downcast::<Arc<dyn ReactantRaw<T, C> + Send + Sync + 'static>>()
.ok()
.map(|boxed_arc| (*boxed_arc).clone())
})
.collect();
let typed_error_reactants: Vec<_> = error_reactants
.into_iter()
.filter_map(|erased_reactant| {
if erased_reactant.payload_type_id() != TypeId::of::<T>()
|| erased_reactant.codec_type_id() != TypeId::of::<C>()
{
return None;
}
let any_arc = erased_reactant.clone_to_any();
any_arc
.downcast::<Arc<dyn ErrorReactant<T, C> + Send + Sync + 'static>>()
.ok()
.map(|boxed_arc| (*boxed_arc).clone())
})
.collect();
if !typed_reactants.is_empty()
|| !typed_raw_reactants.is_empty()
|| !typed_error_reactants.is_empty()
{
let _ = self
.synapse
.write()
.react(typed_reactants, typed_raw_reactants, typed_error_reactants);
}
}
fn neuron_name(&self) -> String {
self.synapse.read().neuron().name()
}
fn codec_name(&self) -> String {
C::name().to_string()
}
fn neuron_schema(&self) -> String {
self.synapse.read().neuron().schema()
}
fn payload_type_id(&self) -> TypeId {
TypeId::of::<T>()
}
fn codec_type_id(&self) -> TypeId {
TypeId::of::<C>()
}
fn clone_to_box(&self) -> Box<dyn SynapseExternalErased + Send + Sync + 'static> {
Box::new(Self {
synapse: self.synapse.clone(),
_phantom: PhantomData,
})
}
fn clone_to_arc(&self) -> Arc<RwLock<dyn SynapseExternalErased + Send + Sync + 'static>> {
Arc::new(RwLock::new(Self {
synapse: self.synapse.clone(),
_phantom: PhantomData,
}))
}
}
pub fn erase_synapse_internal<T, C, S>(
synapse: S,
) -> Arc<RwLock<dyn SynapseInternalErased + Send + Sync + 'static>>
where
T: Send + Sync + 'static,
C: Codec<T> + CodecName + Send + Sync + 'static,
S: SynapseInternal<T, C> + Send + Sync + 'static,
{
SynapseInternalErasedWrapper::from_typed_synapse(synapse)
}
pub fn erase_synapse_external<T, C, S>(
synapse: S,
) -> Arc<RwLock<dyn SynapseExternalErased + Send + Sync + 'static>>
where
T: Send + Sync + 'static,
C: Codec<T> + CodecName + Send + Sync + 'static,
S: SynapseExternal<T, C> + Send + Sync + 'static,
{
SynapseExternalErasedWrapper::from_typed_synapse(synapse)
}