use crate::backpressure::BackpressureConfig;
use crate::codec::{Codec, CodecName};
use crate::erasure::synapse::{SynapseExternalErased, SynapseInternalErased};
use crate::neuron::Neuron;
use std::collections::{HashMap, HashSet};
use std::sync::Arc;
use parking_lot::RwLock;
use uuid::Uuid;
#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
pub enum ConnectionState {
Disconnected,
Connecting,
Handshaking,
Established,
Ready,
Connected,
Disconnecting,
}
pub struct BaseGanglionInner<S: ?Sized> {
pub id: Uuid,
pub synapses_by_name: Arc<RwLock<HashMap<String, Arc<RwLock<S>>>>>,
pub state: RwLock<ConnectionState>,
pub relevant_neurons: RwLock<HashSet<String>>,
pub ignored_neurons: RwLock<HashSet<String>>,
pub relevant_codecs: RwLock<HashSet<String>>,
pub ignored_codecs: RwLock<HashSet<String>>,
pub transmit_backpressure: BackpressureConfig,
pub transduce_backpressure: BackpressureConfig,
}
#[derive(Clone)]
pub struct BaseGanglionExternal {
pub inner: Arc<BaseGanglionInner<dyn SynapseExternalErased + Send + Sync + 'static>>,
}
#[derive(Clone)]
pub struct BaseGanglionInternal {
pub inner: Arc<BaseGanglionInner<dyn SynapseInternalErased + Send + Sync + 'static>>,
}
impl BaseGanglionExternal {
pub fn new() -> Self {
Self {
inner: Arc::new(BaseGanglionInner {
id: Uuid::now_v7(),
synapses_by_name: Arc::new(RwLock::new(HashMap::new())),
state: RwLock::new(ConnectionState::Disconnected),
relevant_neurons: RwLock::new(HashSet::new()),
ignored_neurons: RwLock::new(HashSet::new()),
relevant_codecs: RwLock::new(HashSet::new()),
ignored_codecs: RwLock::new(HashSet::new()),
transmit_backpressure: BackpressureConfig::default(),
transduce_backpressure: BackpressureConfig::default(),
}),
}
}
pub fn with_backpressure(transmit: BackpressureConfig, transduce: BackpressureConfig) -> Self {
Self {
inner: Arc::new(BaseGanglionInner {
id: Uuid::now_v7(),
synapses_by_name: Arc::new(RwLock::new(HashMap::new())),
state: RwLock::new(ConnectionState::Disconnected),
relevant_neurons: RwLock::new(HashSet::new()),
ignored_neurons: RwLock::new(HashSet::new()),
relevant_codecs: RwLock::new(HashSet::new()),
ignored_codecs: RwLock::new(HashSet::new()),
transmit_backpressure: transmit,
transduce_backpressure: transduce,
}),
}
}
pub fn capable<T, C>(&self, neuron: &Arc<dyn Neuron<T, C> + Send + Sync>) -> bool
where
C: Codec<T> + CodecName + Send + Sync + 'static,
T: Send + Sync + 'static,
{
check_capable(&self.inner, neuron)
}
pub fn get_synapse(
&self,
name: &str,
) -> Option<Arc<RwLock<dyn SynapseExternalErased + Send + Sync + 'static>>> {
let map = self.inner.synapses_by_name.read();
map.get(name).cloned()
}
pub fn insert_synapse(
&self,
name: String,
synapse: Arc<RwLock<dyn SynapseExternalErased + Send + Sync + 'static>>,
) {
let mut map = self.inner.synapses_by_name.write();
map.insert(name, synapse);
}
pub fn id(&self) -> Uuid {
self.inner.id
}
pub fn set_state(&self, state: ConnectionState) {
let mut guard = self.inner.state.write();
*guard = state;
}
pub fn state(&self) -> ConnectionState {
*self.inner.state.read()
}
}
impl Default for BaseGanglionExternal {
fn default() -> Self {
Self::new()
}
}
impl BaseGanglionInternal {
pub fn new() -> Self {
Self {
inner: Arc::new(BaseGanglionInner {
id: Uuid::now_v7(),
synapses_by_name: Arc::new(RwLock::new(HashMap::new())),
state: RwLock::new(ConnectionState::Disconnected),
relevant_neurons: RwLock::new(HashSet::new()),
ignored_neurons: RwLock::new(HashSet::new()),
relevant_codecs: RwLock::new(HashSet::new()),
ignored_codecs: RwLock::new(HashSet::new()),
transmit_backpressure: BackpressureConfig::default(),
transduce_backpressure: BackpressureConfig::default(),
}),
}
}
pub fn capable<T, C>(&self, neuron: &Arc<dyn Neuron<T, C> + Send + Sync>) -> bool
where
C: Codec<T> + CodecName + Send + Sync + 'static,
T: Send + Sync + 'static,
{
check_capable(&self.inner, neuron)
}
pub fn get_synapse(
&self,
name: &str,
) -> Option<Arc<RwLock<dyn SynapseInternalErased + Send + Sync + 'static>>> {
let map = self.inner.synapses_by_name.read();
map.get(name).cloned()
}
pub fn insert_synapse(
&self,
name: String,
synapse: Arc<RwLock<dyn SynapseInternalErased + Send + Sync + 'static>>,
) {
let mut map = self.inner.synapses_by_name.write();
map.insert(name, synapse);
}
pub fn id(&self) -> Uuid {
self.inner.id
}
}
impl Default for BaseGanglionInternal {
fn default() -> Self {
Self::new()
}
}
fn check_capable<T, C, S: ?Sized>(
inner: &Arc<BaseGanglionInner<S>>,
neuron: &Arc<dyn Neuron<T, C> + Send + Sync>,
) -> bool
where
C: Codec<T> + CodecName + Send + Sync + 'static,
T: Send + Sync + 'static,
{
let neuron_name = neuron.name();
let codec_name = C::name();
{
let relevant = inner.relevant_neurons.read();
if !relevant.is_empty() && !relevant.contains(&neuron_name) {
return false;
}
}
{
let ignored = inner.ignored_neurons.read();
if ignored.contains(&neuron_name) {
return false;
}
}
{
let relevant = inner.relevant_codecs.read();
if !relevant.is_empty() && !relevant.contains(codec_name) {
return false;
}
}
{
let ignored = inner.ignored_codecs.read();
if ignored.contains(codec_name) {
return false;
}
}
true
}
pub type BaseGanglion = BaseGanglionExternal;