use std::sync::atomic::AtomicU64;
use std::time::Duration;
use serde::{Deserialize, Serialize};
use crate::nerve::latency::LatencyEstimate;
use crate::nerve::signal::{NeuronId, PathwayId, Signal};
use amate::Engine;
#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "lowercase")]
pub enum PathwayKind {
Reflex,
Deliberative,
}
impl PathwayKind {
pub(crate) fn as_str(self) -> &'static str {
match self {
Self::Reflex => "reflex",
Self::Deliberative => "deliberative",
}
}
}
#[derive(Clone, Copy, Debug, PartialEq)]
pub struct Summation {
pub max_batch: usize,
pub window: Option<Duration>,
pub min_window: Duration,
pub max_window: Duration,
pub capacity: usize,
pub workers: usize,
pub(crate) announced_only: bool,
}
impl Default for Summation {
fn default() -> Self {
Self {
max_batch: 8,
window: None,
min_window: Duration::from_micros(200),
max_window: Duration::from_millis(20),
capacity: 1024,
workers: 1,
announced_only: false,
}
}
}
impl Summation {
pub fn none() -> Self {
Self {
max_batch: 1,
window: Some(Duration::ZERO),
..Self::default()
}
}
pub fn max_batch(mut self, n: usize) -> Self {
self.max_batch = n.max(1);
self
}
pub fn window(mut self, window: Duration) -> Self {
self.window = Some(window);
self
}
pub fn capacity(mut self, n: usize) -> Self {
self.capacity = n.max(1);
self
}
pub fn workers(mut self, n: usize) -> Self {
self.workers = n.max(1);
self
}
pub(crate) fn announced_only(mut self) -> Self {
self.announced_only = true;
self
}
}
pub(crate) struct Pathway {
pub id: PathwayId,
pub from: NeuronId,
pub to: NeuronId,
pub kind: PathwayKind,
pub weight: f32,
pub(crate) latency: LatencyEstimate,
pub(crate) signals: AtomicU64,
pub(crate) ineligible: AtomicU64,
pub(crate) overflow: AtomicU64,
pub(crate) summation: Option<Summation>,
pub(super) queue: Option<Engine<Signal>>,
}
impl Pathway {
pub(crate) fn window(&self) -> Option<Duration> {
self.summation.map(|s| {
s.window.unwrap_or_else(|| {
self.latency.p50().map_or(s.min_window, |p50| {
(p50 / 8).clamp(s.min_window, s.max_window)
})
})
})
}
pub(super) fn fits(&self, remaining: Option<Duration>) -> bool {
match (remaining, self.latency.p99()) {
(None, _) | (_, None) => true,
(Some(remaining), Some(p99)) => p99 <= remaining,
}
}
}