muchin 0.1.0

Support for composing large, interacting, complicated state machines
Documentation
use crate::automaton::{Objects, Redispatch, Uid};
use std::{collections::BTreeSet, mem};

#[derive(Debug)]
pub struct Listener {
    pub max_connections: usize,
    pub on_success: Redispatch<Uid>,
    pub on_error: Redispatch<(Uid, String)>,
    pub on_new_connection: Redispatch<(Uid, Uid)>,
    pub on_connection_closed: Redispatch<(Uid, Uid)>,
    pub on_listener_closed: Redispatch<Uid>,
    pub connections: BTreeSet<Uid>,
}

impl Listener {
    pub fn new(
        max_connections: usize,
        on_success: Redispatch<Uid>,
        on_error: Redispatch<(Uid, String)>,
        on_new_connection: Redispatch<(Uid, Uid)>,
        on_connection_closed: Redispatch<(Uid, Uid)>,
        on_listener_closed: Redispatch<Uid>,
    ) -> Self {
        Self {
            max_connections,
            on_new_connection,
            on_success,
            on_error,
            on_connection_closed,
            on_listener_closed,
            connections: BTreeSet::new(),
        }
    }

    pub fn remove_connection(&mut self, uid: &Uid) {
        self.connections.remove(uid);
    }
}

#[derive(Debug)]
pub struct SendRequest {
    pub connection: Uid,
    pub on_success: Redispatch<Uid>,
    pub on_timeout: Redispatch<Uid>,
    pub on_error: Redispatch<(Uid, String)>,
}

#[derive(Debug)]
pub struct RecvRequest {
    pub connection: Uid,
    pub on_success: Redispatch<(Uid, Vec<u8>)>,
    pub on_timeout: Redispatch<(Uid, Vec<u8>)>,
    pub on_error: Redispatch<(Uid, String)>,
}

#[derive(Debug)]
pub struct PollRequest {
    pub on_success: Redispatch<Uid>,
    pub on_error: Redispatch<(Uid, String)>,
}

#[derive(Debug)]
pub struct TcpServerState {
    pub listeners: Objects<Listener>,
    pub send_requests: Objects<SendRequest>,
    pub recv_requests: Objects<RecvRequest>,
    pub poll_request: Option<PollRequest>,
}

impl TcpServerState {
    pub fn new() -> Self {
        Self {
            listeners: Objects::<Listener>::new(),
            send_requests: Objects::<SendRequest>::new(),
            recv_requests: Objects::<RecvRequest>::new(),
            poll_request: None,
        }
    }

    pub fn set_poll_request(&mut self, request: PollRequest) {
        assert!(self.poll_request.is_none());
        self.poll_request = Some(request);
    }

    pub fn take_poll_request(&mut self) -> PollRequest {
        mem::take(&mut self.poll_request).expect("Take attempt on inexistent PollRequest")
    }

    pub fn new_send_request(
        &mut self,
        uid: &Uid,
        connection: Uid,
        on_success: Redispatch<Uid>,
        on_timeout: Redispatch<Uid>,
        on_error: Redispatch<(Uid, String)>,
    ) {
        if self
            .send_requests
            .insert(
                *uid,
                SendRequest {
                    connection,
                    on_success,
                    on_timeout,
                    on_error,
                },
            )
            .is_some()
        {
            panic!("Attempt to re-use existing {:?}", uid)
        }
    }

    pub fn take_send_request(&mut self, uid: &Uid) -> SendRequest {
        self.send_requests
            .remove(uid)
            .expect(&format!("Take attempt on inexistent SendRequest {:?}", uid))
    }

    pub fn new_recv_request(
        &mut self,
        uid: &Uid,
        connection: Uid,
        on_success: Redispatch<(Uid, Vec<u8>)>,
        on_timeout: Redispatch<(Uid, Vec<u8>)>,
        on_error: Redispatch<(Uid, String)>,
    ) {
        if self
            .recv_requests
            .insert(
                *uid,
                RecvRequest {
                    connection,
                    on_success,
                    on_timeout,
                    on_error,
                },
            )
            .is_some()
        {
            panic!("Attempt to re-use existing {:?}", uid)
        }
    }

    pub fn take_recv_request(&mut self, uid: &Uid) -> RecvRequest {
        self.recv_requests
            .remove(uid)
            .expect(&format!("Take attempt on inexistent SendRequest {:?}", uid))
    }

    pub fn new_connection(&mut self, connection: Uid, listener: Uid) {
        self.get_listener_mut(&listener)
            .connections
            .insert(connection);
    }

    pub fn get_connection_listener_mut(&mut self, connection: &Uid) -> (&Uid, &mut Listener) {
        self.listeners
            .iter_mut()
            .find(|(_, listener)| listener.connections.contains(connection))
            .expect(&format!(
                "Listener not found for connection {:?}",
                connection
            ))
    }

    pub fn new_listener(
        &mut self,
        listener: Uid,
        max_connections: usize,
        on_success: Redispatch<Uid>,
        on_error: Redispatch<(Uid, String)>,
        on_new_connection: Redispatch<(Uid, Uid)>,
        on_connection_closed: Redispatch<(Uid, Uid)>,
        on_listener_closed: Redispatch<Uid>,
    ) {
        if self
            .listeners
            .insert(
                listener,
                Listener::new(
                    max_connections,
                    on_success,
                    on_error,
                    on_new_connection,
                    on_connection_closed,
                    on_listener_closed,
                ),
            )
            .is_some()
        {
            panic!("Attempt to re-use existing {:?}", listener)
        }
    }

    pub fn get_listener(&self, listener: &Uid) -> &Listener {
        self.listeners
            .get(listener)
            .expect(&format!("Listener object {:?} not found", listener))
    }

    pub fn get_listener_mut(&mut self, listener: &Uid) -> &mut Listener {
        self.listeners
            .get_mut(listener)
            .expect(&format!("Listener object {:?} not found", listener))
    }

    pub fn remove_listener(&mut self, listener: &Uid) -> Listener {
        self.listeners.remove(listener).expect(&format!(
            "Attempt to remove an inexistent Listener {:?}",
            listener
        ))
    }
}