nardol 0.0.3

Simple framework that provides structure to data sent and received from network.
Documentation
use serde::{Deserialize, Serialize};

use lazy_static::lazy_static;

use std::fmt::{Debug, Display};
use std::sync::{Arc, Mutex};

use crate::bytes::Bytes;
use crate::error::{Error, ErrorKind};
use crate::message::{ContentType, ContextType, MetaDataType, OutputType, TcpMessage, UdpMessage};
use crate::packet::{Packet, PacketKind};
use crate::ron::{FromRon, ToRon};

lazy_static! {
    static ref MESSAGE_SPLIT_PATTERN: Arc<Mutex<Vec<u8>>> = {
        let pattern = vec![0, 0, 0, 0];
        Arc::new(Mutex::new(pattern))
    };
}

pub struct Context;

impl ContextType for Context {}

pub struct Output;

impl OutputType for Output {}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Message<M, C> {
    metadata: M,
    content: C,
    end_data: Packet,
}

impl<'a, M, C> Default for Message<M, C>
where
    M: Default,
    C: Default,
{
    fn default() -> Self {
        Message {
            metadata: M::default(),
            content: C::default(),
            end_data: Packet::default(),
        }
    }
}

impl<M, C> Display for Message<M, C>
where
    M: Serialize,
    C: Serialize,
{
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        let formatted = self
            .to_ron_pretty(None)
            .expect("Failed to parse a Message to RON.");
        write!(f, "{}", &formatted)
    }
}

impl<M, C> ToRon for Message<M, C>
where
    M: Serialize,
    C: Serialize,
{
}

impl<'a, M, C> FromRon<'a> for Message<M, C>
where
    M: Deserialize<'a>,
    C: Deserialize<'a>,
{
}

impl<M, C> TryFrom<Packet> for Message<M, C>
where
    M: TryFrom<Bytes>,
    Error: From<<M as TryFrom<Bytes>>::Error>,
    C: TryFrom<Bytes> + Default,
    Error: From<<C as TryFrom<Bytes>>::Error>,
{
    type Error = Error;

    /// Tries to parse a [Packet] into [Message].
    ///
    /// Packet content is read and split on [MESSAGE_SPLIT_PATTERN],
    /// then an attempt is made to parse first part of split packet content to [metadata](M),
    /// if there are more than one part of split, attempt to parse second to [content](C),
    /// and and attempt to parse third to [Packet].
    /// Those attempt are based on implementation of [TryFrom<Bytes>] into respective data.
    fn try_from(value: Packet) -> Result<Self, Self::Error> {
        let pattern: Bytes = Bytes::from(Self::split_pattern()?);

        let packet_content = value.content_move();

        let content_split = packet_content.split_at_pat(&pattern);

        let (metadata, content, end_data) = match content_split.len() {
            1 => {
                let mut content_split_iter = content_split.into_iter();
                // One value is guaranteed by match, so unwrap can be used safely.
                let metadata_bytes = content_split_iter.next().unwrap();

                let metadata = M::try_from(metadata_bytes)?;
                let content = C::default();
                let end_data = Packet::new(PacketKind::End, Bytes::empty())?;

                (metadata, content, end_data)
            }
            2 => {
                let mut content_split_iter = content_split.into_iter();
                // Two values are guaranteed by match, so unwrap can be used safely.
                let metadata_bytes = content_split_iter.next().unwrap();
                let content_bytes = content_split_iter.next().unwrap();

                let metadata = M::try_from(metadata_bytes)?;
                let content = C::try_from(content_bytes)?;
                let end_data = Packet::new(PacketKind::End, Bytes::empty())?;

                (metadata, content, end_data)
            }
            3 => {
                let mut content_split_iter = content_split.into_iter();
                // Three values are guaranteed by match, so unwrap can be used safely.
                let metadata_bytes = content_split_iter.next().unwrap();
                let content_bytes = content_split_iter.next().unwrap();
                let end_data_bytes = content_split_iter.next().unwrap();

                let metadata = M::try_from(metadata_bytes)?;
                let content = C::try_from(content_bytes)?;
                let end_data = Packet::try_from(end_data_bytes)?;

                (metadata, content, end_data)
            }
            _ => {
                return Err(Error::new(
                    ErrorKind::ParsingFailed,
                    Some("Packet content can not be parsed to Message.\nMore than three parts found.".to_string()))
                );
            }
        };

        Ok(Self {
            metadata,
            content,
            end_data,
        })
    }
}

impl<M, C> TryFrom<Message<M, C>> for Packet
where
    M: Into<Bytes>,
    C: Into<Bytes>,
{
    type Error = Error;

    /// Parses a [Message] into [Packet] with [PacketKind::Unit].
    ///
    /// metadata, content and end_data are converted to [Bytes] and joined together,
    /// split by [MESSAGE_SPLIT_PATTERN].
    fn try_from(value: Message<M, C>) -> Result<Self, Self::Error> {
        let metadata = value.metadata;
        let content = value.content;
        let end_data = value.end_data;

        let mut metadata_bytes: Bytes = metadata.into();
        let mut content_bytes: Bytes = content.into();
        let mut end_data_bytes: Bytes = end_data.into();

        let mut packet_content = Bytes::empty();
        packet_content.append(&mut metadata_bytes);
        packet_content.append(&mut Bytes::from(Message::<M, C>::split_pattern()?));
        packet_content.append(&mut content_bytes);
        packet_content.append(&mut Bytes::from(Message::<M, C>::split_pattern()?));
        packet_content.append(&mut end_data_bytes);

        Packet::new(PacketKind::Unit, packet_content)
    }
}

impl<'a, M, C> TcpMessage<'a, M, C> for Message<M, C>
where
    M: MetaDataType<'a, M, C> + Debug + Default,
    C: ContentType<'a, M, C> + Default,
{
    fn destructure(self) -> (M, C, Packet) {
        let Self {
            metadata,
            content,
            end_data,
        } = self;
        (metadata, content, end_data)
    }

    fn build(metadata: M, content: C, end_data: Packet) -> Self {
        Self {
            metadata,
            content,
            end_data,
        }
    }
}

impl<'a, M, C> UdpMessage<'a> for Message<M, C>
where
    Self: Default + ToRon + FromRon<'a> + TryFrom<Packet> + TryInto<Packet>,
    Error: From<<Self as TryInto<Packet>>::Error> + From<<Self as TryFrom<Packet>>::Error>,
    <Self as TryInto<Packet>>::Error: Into<Error> + Debug,
    <Self as TryFrom<Packet>>::Error: Into<Error> + Debug,
{
}

impl<M, C> Message<M, C> {
    /// Returns `MESSAGE_SPLIT_PATTERN` as [Result] of [Vec] of [u8] or [Error].
    pub fn split_pattern() -> Result<Vec<u8>, Error> {
        match MESSAGE_SPLIT_PATTERN.try_lock() {
            Ok(value) => Ok(value.clone()),
            Err(e) => Err(Error::new(
                ErrorKind::OtherSource(Box::new(e)),
                Some("Failed to acquire a lock to MESSAGE_SPLIT_PATTERN.".to_string()),
            )),
        }
    }

    /// Sets `MESSAGE_SPLIT_PATTERN`.
    pub fn set_split_pattern(mut value: Vec<u8>) -> Result<(), Error> {
        // Kinda forgot how to use Arcs and mutexes.
        match MESSAGE_SPLIT_PATTERN.lock() {
            Ok(mut inner) => {
                inner.truncate(0);
                inner.append(&mut value);
                Ok(())
            }
            Err(e) => Err(Error::new(
                ErrorKind::OtherSource(Box::new(e)),
                Some("Failed to acquire a lock to MESSAGE_SPLIT_PATTERN.".to_string()),
            )),
        }
    }
}

#[test]
fn split_pattern_test() {
    let new_pat = vec![1, 2, 3, 4];
    Message::<usize, usize>::set_split_pattern(new_pat).unwrap();
    let pat = Message::<usize, usize>::split_pattern().unwrap();
    println!("{:?}", &pat);
    assert_eq!(vec![1, 2, 3, 4], pat);
}