aika 0.2.1

Multi-agent coordination framework in Rust with single and multi-threaded execution engines.
Documentation
use std::{
    fs::File,
    io::Write,
    sync::{
        atomic::{AtomicBool, Ordering},
        Arc,
    },
    time::{Duration, Instant},
};

use bytemuck::{Pod, Zeroable};
use mesocarp::comms::buses::ThreadedMessenger;
use mesocarp::MesoError;

use crate::{objects::Transfer, AikaError};

pub struct MessageBus<const MSG_BW: usize, MessageType: Pod + Zeroable + Clone> {
    pub(crate) messenger: ThreadedMessenger<MSG_BW, Transfer<MessageType>>,
    pub(crate) terminal_flag: Arc<AtomicBool>,
    pub(crate) log: Option<File>,
    pub(crate) start: Instant,
}

impl<const MSG_BW: usize, MessageType: Pod + Zeroable + Clone> MessageBus<MSG_BW, MessageType> {
    pub(crate) fn from_substrate(
        messenger: ThreadedMessenger<MSG_BW, Transfer<MessageType>>,
        log: Option<File>,
        start: Instant,
        terminal_flag: Arc<AtomicBool>,
    ) -> Self {
        Self {
            messenger,
            terminal_flag,
            log,
            start,
        }
    }

    pub(crate) fn deliver_the_mail(&mut self) -> Result<(), AikaError> {
        match self.messenger.poll() {
            Ok(msgs) => {
                if let Some(file) = &mut self.log {
                    writeln!(
                        file,
                        "[{}] Found {:?} messages in-transit.",
                        self.start.elapsed().as_micros(),
                        msgs.len()
                    )
                    .map_err(|_| AikaError::LoggingWriteError)?;
                }
                self.messenger.deliver(msgs)?;
                Ok(())
            }
            Err(err) => {
                if let MesoError::NoDirectCommsToShare = err {
                    Ok(())
                } else {
                    if let Some(file) = &mut self.log {
                        writeln!(
                            file,
                            "[{}] Error delivering mail!",
                            self.start.elapsed().as_micros(),
                        )
                        .map_err(|_| AikaError::LoggingWriteError)?;
                    }
                    Err(AikaError::MesoError(err))
                }
            }
        }
    }

    pub fn master(mut self) -> Result<Self, AikaError> {
        if let Some(log) = &mut self.log {
            writeln!(
                log,
                "[{}] Starting Master",
                self.start.elapsed().as_micros()
            )
            .map_err(|_| AikaError::LoggingWriteError)?;
        }
        loop {
            let flag = self.terminal_flag.load(Ordering::SeqCst);
            if flag {
                if let Some(log) = &mut self.log {
                    writeln!(
                        log,
                        "[{}] Flag closing Master",
                        self.start.elapsed().as_micros()
                    )
                    .map_err(|_| AikaError::LoggingWriteError)?;
                }
                break;
            }
            if let Some(log) = &mut self.log {
                writeln!(log, "[{}] looping master", self.start.elapsed().as_micros())
                    .map_err(|_| AikaError::LoggingWriteError)?;
            }
            for _ in 0..100 {
                self.deliver_the_mail()?;
            }
            std::thread::sleep(Duration::from_nanos(1));
        }
        if let Some(log) = &mut self.log {
            writeln!(log, "[{}] Closing Master", self.start.elapsed().as_micros())
                .map_err(|_| AikaError::LoggingWriteError)?;
        }
        Ok(self)
    }
}