network_audio_protocol 0.1.0

A network protocol for sending audio over the network, still in development
Documentation
#[cfg(test)]
mod tests 
{
    mod message_type
    {
        use super::super::*;

        #[test]
        fn from_u8_test()
        {
            assert_eq!(MessageType::Null, MessageType::from(0));
            assert_eq!(MessageType::Get, MessageType::from(1));
            assert_eq!(MessageType::Reply, MessageType::from(2));
            assert_eq!(MessageType::Error, MessageType::from(3));
            assert_eq!(MessageType::Shutdown, MessageType::from(4));
            assert_eq!(MessageType::Unknown, MessageType::from(5));
        }

        #[test]
        fn as_u8_test()
        {
            assert_eq!(MessageType::Null.as_u8(), 0);
            assert_eq!(MessageType::Get.as_u8(), 1);
            assert_eq!(MessageType::Reply.as_u8(), 2);
            assert_eq!(MessageType::Error.as_u8(), 3);
            assert_eq!(MessageType::Shutdown.as_u8(), 4);
            assert_eq!(MessageType::Unknown.as_u8(), 255);
        }

        #[test]
        fn to_string_test()
        {
            assert_eq!(String::from("Null"), MessageType::Null.to_string());
            assert_eq!(String::from("Get"), MessageType::Get.to_string());
            assert_eq!(String::from("Reply"), MessageType::Reply.to_string());
            assert_eq!(String::from("Error"), MessageType::Error.to_string());
            assert_eq!(String::from("Shutdown"), MessageType::Shutdown.to_string());
            assert_eq!(String::from("Unknown"), MessageType::Unknown.to_string());
        }

    }

    mod data_type
    {
        use super::super::*;

        #[test]
        fn from_u8_test()
        {
            assert_eq!(DataType::Null, DataType::from(0));
            assert_eq!(DataType::SampleRate, DataType::from(1));
            assert_eq!(DataType::SampleFormat, DataType::from(2));
            assert_eq!(DataType::ChannelCount, DataType::from(3));
            assert_eq!(DataType::AudioSamples, DataType::from(4));
            assert_eq!(DataType::Unknown, DataType::from(255));
        }

        #[test]
        fn as_u8_test()
        {
            assert_eq!(DataType::Null.as_u8(), 0);
            assert_eq!(DataType::SampleRate.as_u8(), 1);
            assert_eq!(DataType::SampleFormat.as_u8(), 2);
            assert_eq!(DataType::ChannelCount.as_u8(), 3);
            assert_eq!(DataType::AudioSamples.as_u8(), 4);
            assert_eq!(DataType::Unknown.as_u8(), 255);
        }

        #[test]
        fn to_string_test()
        {
            assert_eq!(DataType::Null.to_string(), String::from("Null"));
            assert_eq!(DataType::SampleRate.to_string(), String::from("SampleRate"));
            assert_eq!(DataType::SampleFormat.to_string(), String::from("SampleFormat"));
            assert_eq!(DataType::ChannelCount.to_string(), String::from("ChannelCount"));
            assert_eq!(DataType::AudioSamples.to_string(), String::from("AudioSamples"));
            assert_eq!(DataType::Unknown.to_string(), String::from("Unknown"));
        }
    }
}

/// A listing of all the different kinds of message types that a Message
/// can be composed of. 
///
/// # Description #
/// The Message Type variants are put at the beginning of a network message, and 
/// determine what kind of message the network message will be. Each variant of 
/// the MessageType enum maps to a u8 integer, a MessageType
/// variant can also be created from a u8 integer.
///
/// # u8 Variant Mappings #
/// * `Null     == 0`
/// * `Get      == 1`
/// * `Reply    == 2`
/// * `Error    == 3`
/// * `Shutdown == 4`
/// * `Unknown  >= 5`
/// # Examples #
/// ```
/// use network_audio_protocol::MessageType;
///
/// let message_type: MessageType = MessageType::from(1);
/// assert_eq!(message_type, MessageType::Get);
/// assert_eq!(message_type.to_string(), String::from("Get"));
///
/// println!("Message Type: {}, maps to: {}", message_type, message_type.as_u8());
/// ```
/// The above code creates a `MessageType` variant from the u8 integer `1`, confirms that it is
/// equal to `MessageType::Get`, turns the `MessageType` into a `String`, and compares it to
/// another string value, and finally prints the `MessageType` and its corresponding u8 value
#[derive(Debug)]
#[derive(PartialEq)]
pub enum MessageType
{
    /// The `Null` variant is used to create a null, or empty message.
    Null,
    /// The `Get` variant is used to create a message that contains a request within it.
    Get,
    /// The `Reply` variant is used to create a message that contains data to fufill a `Get`
    /// request.
    Reply,
    /// The `Error` variant is used to create a message indicating an error occurred.
    Error,
    /// The `Shutdown` variant is used to create a shutdown / termination message.
    Shutdown,
    /// The `Unkown` variant is not used to make any messages, but rather to represent a message of
    /// an unknown type.
    Unknown,
}

impl MessageType
{
    /// Returns the corresponding u8 integer value for the used `MessageType` variant. Unlike
    /// `Into` it does not consume self.
    pub fn as_u8(&self) -> u8
    {
        return match self
        {
            MessageType::Null => 0,
            MessageType::Get => 1,
            MessageType::Reply => 2,
            MessageType::Error => 3, 
            MessageType::Shutdown => 4,
            MessageType::Unknown => 255,
        };
    }
}

impl From<u8> for MessageType
{
    fn from(byte: u8) -> Self
    {
        return match byte
        {
            0 => MessageType::Null,
            1 => MessageType::Get,
            2 => MessageType::Reply,
            3 => MessageType::Error,
            4 => MessageType::Shutdown,
            _ => MessageType::Unknown,
        };
    }
}

impl std::fmt::Display for MessageType
{
    fn fmt(&self, formatter: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error>
    {
        let string: String = match self
        {
            MessageType::Null =>     String::from("Null"),
            MessageType::Get =>      String::from("Get"),
            MessageType::Reply =>    String::from("Reply"),
            MessageType::Error =>    String::from("Error"),
            MessageType::Shutdown => String::from("Shutdown"),
            MessageType::Unknown =>  String::from("Unknown"),
        };

        formatter.write_str(string.as_str())?;

        return Ok(());
    }
}

/// A listing of data types used to compose Get and Reply Messages
///
/// # Description #
/// The Data Type enum variants are used to specify what data is contained in a Message, it comes
/// directly after the Message Type, and is only relevant for `MessageType::Get` and
/// `MessageType::Reply` Messages. Each variant as a mapping to a u8 integer.
///
/// # u8 Variant Mappings #
/// * `Null         == 0`
/// * `SampleRate   == 1`
/// * `SampleFormat == 2`
/// * `ChannelCount == 3`
/// * `AudioSamples == 4`
/// * `Unknown      >= 5`
///
/// # Examples #
///
/// ```
/// use network_audio_protocol::DataType;
/// 
/// // create a DataType variant from the integer 1
/// let data_type: DataType = DataType::from(1);
///
/// // turn the DataType variant into a string
/// let as_string: String = data_type.to_string();
///
/// // check for valid results
/// assert_eq!(DataType::SampleRate, data_type);
/// assert_eq!(String::from("SampleRate"), as_string);
/// 
/// // print out the DataType variant, and its u8 integer mapping
/// println!("Data Type: {}, maps to: {}", data_type, data_type.as_u8());
/// ```
#[derive(Debug)]
#[derive(PartialEq)]
pub enum DataType
{
    /// Used to send a Message whithout a data type.
    Null,
    /// Used to send a message requesting / containing the audio sample rate or frequency.
    /// `SampleRate` is represented as a `u32` integer.
    SampleRate,
    /// Used to send a message requesting / containing the audio data sample format. `SampleFormat`
    /// is represented as `(bool, bool, u32)` tuple, where the first boolean is the Endianness of the
    /// samples `(true == Little Endian)`, the second boolean is the Signedness of the samples `(true
    /// == Signed)`, and the `u32` is the bit depth of the samples.
    SampleFormat,
    /// Used to send a message requesting / containing the number of audio channels. `ChannelCount`
    /// is represented as a `u32` integer.
    ChannelCount,
    /// Used to send a message requesting / containing audio samples / audio data. `AudioSamples`
    /// are represented as a `u8` slice, or `&[u8]`. The Endianness and Signedness 
    /// of the bytes is not altered when the message is serialized / deserialized.
    AudioSamples,
    /// Not formally used in composing messages, but rather for specifying that a message is made up of an
    /// unknown, or undefined data type.
    Unknown,
}

impl DataType
{
    pub fn as_u8(&self) -> u8
    {
        return match self
        {
            DataType::Null =>         0,
            DataType::SampleRate =>   1,
            DataType::SampleFormat => 2,
            DataType::ChannelCount => 3,
            DataType::AudioSamples => 4,
            DataType::Unknown =>      255,
        };
    }
}

impl From<u8> for DataType
{
    fn from(byte: u8) -> Self
    {
        return match byte
        {
            0 => DataType::Null,
            1 => DataType::SampleRate,
            2 => DataType::SampleFormat,
            3 => DataType::ChannelCount,
            4 => DataType::AudioSamples,
            _ => DataType::Unknown,
        };
    }
}

impl std::fmt::Display for DataType
{
    fn fmt(&self, formatter: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error>
    {
        let string: String = match self
        {
            DataType::Null =>         String::from("Null"),
            DataType::SampleRate =>   String::from("SampleRate"),
            DataType::SampleFormat => String::from("SampleFormat"),
            DataType::ChannelCount => String::from("ChannelCount"),
            DataType::AudioSamples => String::from("AudioSamples"),
            DataType::Unknown =>      String::from("Unknown"),
        };

        formatter.write_str(string.as_str())?;

        return Ok(());
    }
}