//! Implementations of storage buffers for messages.
#![cfg_attr(feature = "downcast", allow(unsafe_code))]

use super::*;

/// An implementation of [`MessageBuffer`] around a slice of memory.
///
/// As the code is not even pointer sized, it is copied in.
#[derive(Clone, Debug)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct SliceBuffer<'a> {
    code: u8,
    options_and_payload: &'a [u8],
}

impl<'a> SliceBuffer<'a> {
    /// Constructs a new slice message.
    ///
    /// This constructor is rarely needed, as [`Message::new_from_slice()`] is a short-cut
    /// for it.
    #[must_use]
    pub fn new(code: u8, options_and_payload: &'a [u8]) -> Self {
        Self {
            code,
            options_and_payload,
        }
    }
}

impl MessageBuffer for SliceBuffer<'_> {
    fn code(&self) -> u8 {
        self.code
    }
    fn tail(&self) -> &[u8] {
        self.options_and_payload
    }

    #[cfg(feature = "downcast")]
    fn static_variant() -> Option<LifetimesMatterLittle<impl 'static + MessageBuffer>> {
        // SAFETY: We don't hand out 'a slices, and we don't take any long-lived input.
        Some(unsafe { LifetimesMatterLittle::<SliceBuffer<'static>>::new() })
    }
}

/// The easiest implementation of [`MessageBufferMut`] that is backed by exclusive references.
pub struct SliceBufferMut<'a> {
    code: &'a mut u8,
    tail: &'a mut [u8],
}

impl<'a> SliceBufferMut<'a> {
    /// Marks an area of memory for construction of a message.
    ///
    /// This constructor is rarely needed, as [`MessageMut::new_in_slice()`] is a short-cut for
    /// it.
    pub fn new(code: &'a mut u8, tail: &'a mut [u8]) -> Self {
        Self { code, tail }
    }
}

impl MessageBufferMut for SliceBufferMut<'_> {
    fn code_mut(&mut self) -> &mut u8 {
        self.code
    }

    fn tail_mut(&mut self) -> &mut [u8] {
        self.tail
    }

    #[cfg(feature = "downcast")]
    fn static_mut_variant() -> Option<LifetimesMatterLittle<impl 'static + MessageBufferMut>> {
        // SAFETY: We don't hand out 'a slices, and we don't take any long-lived input.
        Some(unsafe { LifetimesMatterLittle::<SliceBufferMut<'static>>::new() })
    }
}

impl MessageBuffer for SliceBufferMut<'_> {
    fn code(&self) -> u8 {
        *self.code
    }

    fn tail(&self) -> &[u8] {
        self.tail
    }
}

impl MessageBuffer for core::convert::Infallible {
    fn code(&self) -> u8 {
        match *self {}
    }

    fn tail(&self) -> &[u8] {
        match *self {}
    }
}

impl MessageBufferMut for core::convert::Infallible {
    fn code_mut(&mut self) -> &mut u8 {
        match *self {}
    }

    fn tail_mut(&mut self) -> &mut [u8] {
        match *self {}
    }
}
