use alloc::boxed::Box;
use alloc::string::String;
use core::future::Future;
use core::marker::PhantomData;
use core::pin::Pin;
use core::time::Duration;
use super::{ModusRestitutio, StatusInfantis};
const DEFAULT_WORKER_PRIORITY: u32 = 100;
const DEFAULT_SUPERVISOR_PRIORITY: u32 = 50;
#[derive(Clone)]
pub struct InfansSpec {
id: String,
genus: GenusInfantis,
modus: ModusRestitutio,
shutdown_timeout: Duration,
priority: u32,
}
impl InfansSpec {
pub fn worker(id: impl Into<String>) -> Self {
InfansSpec {
id: id.into(),
genus: GenusInfantis::Operarius,
modus: ModusRestitutio::default(),
shutdown_timeout: Duration::from_secs(5),
priority: DEFAULT_WORKER_PRIORITY,
}
}
pub fn supervisor(id: impl Into<String>) -> Self {
InfansSpec {
id: id.into(),
genus: GenusInfantis::Supervisor,
modus: ModusRestitutio::Permanens,
shutdown_timeout: Duration::from_secs(30),
priority: DEFAULT_SUPERVISOR_PRIORITY,
}
}
#[inline]
pub fn with_modus(mut self, modus: ModusRestitutio) -> Self {
self.modus = modus;
self
}
#[inline]
pub fn with_shutdown_timeout(mut self, timeout: Duration) -> Self {
self.shutdown_timeout = timeout;
self
}
#[inline]
pub fn with_priority(mut self, priority: u32) -> Self {
self.priority = priority;
self
}
#[inline]
pub fn id(&self) -> &str {
&self.id
}
#[inline]
pub fn genus(&self) -> GenusInfantis {
self.genus
}
#[inline]
pub fn modus(&self) -> ModusRestitutio {
self.modus
}
#[inline]
pub fn shutdown_timeout(&self) -> Duration {
self.shutdown_timeout
}
#[inline]
pub fn priority(&self) -> u32 {
self.priority
}
}
impl core::fmt::Debug for InfansSpec {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
f.debug_struct("InfansSpec")
.field("id", &self.id)
.field("genus", &self.genus)
.field("modus", &self.modus)
.field("priority", &self.priority)
.finish_non_exhaustive()
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum GenusInfantis {
Operarius,
Supervisor,
}
pub struct InfansCurrens {
spec: InfansSpec,
status: StatusInfantis,
restart_count: u32,
last_restart_time: Option<u64>,
}
impl InfansCurrens {
pub fn new(spec: InfansSpec) -> Self {
InfansCurrens {
spec,
status: StatusInfantis::Incipiens,
restart_count: 0,
last_restart_time: None,
}
}
#[inline]
pub fn spec(&self) -> &InfansSpec {
&self.spec
}
#[inline]
pub fn status(&self) -> StatusInfantis {
self.status
}
#[inline]
pub fn set_status(&mut self, status: StatusInfantis) {
self.status = status;
}
#[inline]
pub fn restart_count(&self) -> u32 {
self.restart_count
}
#[inline]
pub fn record_restart(&mut self, time: u64) {
self.restart_count += 1;
self.last_restart_time = Some(time);
self.status = StatusInfantis::Restituens;
}
#[inline]
pub fn mark_running(&mut self) {
self.status = StatusInfantis::Currens;
}
#[inline]
pub fn mark_failed(&mut self) {
self.status = StatusInfantis::Defectus;
}
#[inline]
pub fn mark_terminated(&mut self) {
self.status = StatusInfantis::Terminatus;
}
}
impl core::fmt::Debug for InfansCurrens {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
f.debug_struct("InfansCurrens")
.field("id", &self.spec.id)
.field("status", &self.status)
.field("restart_count", &self.restart_count)
.finish_non_exhaustive()
}
}
pub trait FabricaInfantis: Send + Sync {
type Output: Send + 'static;
fn create(&self) -> Pin<Box<dyn Future<Output = Self::Output> + Send>>;
}
pub struct FabricaSimplex<F, Fut, T>
where
F: Fn() -> Fut + Send + Sync,
Fut: Future<Output = T> + Send + 'static,
T: Send + 'static,
{
factory: F,
_marker: PhantomData<(Fut, T)>,
}
impl<F, Fut, T> FabricaSimplex<F, Fut, T>
where
F: Fn() -> Fut + Send + Sync,
Fut: Future<Output = T> + Send + 'static,
T: Send + 'static,
{
pub fn new(factory: F) -> Self {
FabricaSimplex {
factory,
_marker: PhantomData,
}
}
}
impl<F, Fut, T> FabricaInfantis for FabricaSimplex<F, Fut, T>
where
F: Fn() -> Fut + Send + Sync,
Fut: Future<Output = T> + Send + Sync + 'static,
T: Send + Sync + 'static,
{
type Output = T;
fn create(&self) -> Pin<Box<dyn Future<Output = T> + Send>> {
Box::pin((self.factory)())
}
}
pub struct ManubriumInfantis<T> {
spec: InfansSpec,
_marker: PhantomData<T>,
}
impl<T> ManubriumInfantis<T> {
pub fn new(spec: InfansSpec) -> Self {
ManubriumInfantis {
spec,
_marker: PhantomData,
}
}
pub fn spec(&self) -> &InfansSpec {
&self.spec
}
}
impl<T> core::fmt::Debug for ManubriumInfantis<T> {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
f.debug_struct("ManubriumInfantis")
.field("spec", &self.spec)
.finish()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_infans_spec_worker() {
let spec = InfansSpec::worker("worker1");
assert_eq!(spec.id(), "worker1");
assert_eq!(spec.genus(), GenusInfantis::Operarius);
}
#[test]
fn test_infans_spec_supervisor() {
let spec = InfansSpec::supervisor("supervisor1");
assert_eq!(spec.id(), "supervisor1");
assert_eq!(spec.genus(), GenusInfantis::Supervisor);
}
#[test]
fn test_infans_spec_builder() {
let spec = InfansSpec::worker("worker1")
.with_modus(ModusRestitutio::Transiens)
.with_priority(10);
assert_eq!(spec.modus(), ModusRestitutio::Transiens);
assert_eq!(spec.priority(), 10);
}
#[test]
fn test_infans_currens() {
let spec = InfansSpec::worker("worker1");
let mut child = InfansCurrens::new(spec);
assert_eq!(child.status(), StatusInfantis::Incipiens);
assert_eq!(child.restart_count(), 0);
child.mark_running();
assert_eq!(child.status(), StatusInfantis::Currens);
child.record_restart(1000);
assert_eq!(child.status(), StatusInfantis::Restituens);
assert_eq!(child.restart_count(), 1);
}
}