//! MessagePack formatter for protocol UUID values.

use crate::Error;
use crate::message_pack::{
    IMessagePackFormatter, MessagePackReader, MessagePackSerializerOptions, MessagePackWriter,
};
use libremetaverse_types::UUID;

#[derive(Clone, Copy, Debug, Default)]
pub struct UUIDFormatter;

impl UUIDFormatter {
    #[must_use]
    pub const fn instance() -> Self {
        Self
    }

    pub fn new() -> Result<Self, Error> {
        Ok(Self)
    }

    pub fn serialize(
        &self,
        writer: &mut MessagePackWriter,
        value: UUID,
        _options: MessagePackSerializerOptions,
    ) -> Result<(), Error> {
        writer.write_bytes(&value.get_bytes()?)
    }

    pub fn deserialize(
        &mut self,
        reader: &mut MessagePackReader,
        _options: MessagePackSerializerOptions,
    ) -> Result<UUID, Error> {
        let bytes = reader.read_bytes()?.ok_or(Error::Argument)?;
        UUID::from_bytes(bytes, 0)
    }
}

impl IMessagePackFormatter<UUID> for UUIDFormatter {
    fn serialize(
        &self,
        writer: &mut MessagePackWriter,
        value: UUID,
        options: MessagePackSerializerOptions,
    ) -> Result<(), Error> {
        self.serialize(writer, value, options)
    }

    fn deserialize(
        &mut self,
        reader: &mut MessagePackReader,
        options: MessagePackSerializerOptions,
    ) -> Result<UUID, Error> {
        self.deserialize(reader, options)
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn uuid_round_trips_as_messagepack_binary() {
        let expected = UUID::parse("00112233-4455-6677-8899-aabbccddeeff".to_owned()).unwrap();
        let mut writer = MessagePackWriter::new();
        UUIDFormatter::instance()
            .serialize(&mut writer, expected, MessagePackSerializerOptions)
            .unwrap();
        assert_eq!(&writer.as_slice()[..2], &[0xc4, 16]);
        let mut reader = MessagePackReader::new(writer.into_bytes());
        let actual = UUIDFormatter::instance()
            .deserialize(&mut reader, MessagePackSerializerOptions)
            .unwrap();
        assert_eq!(actual, expected);
    }
}
