sharkyflac 0.2.0

A pure rust FLAC decoder and encoder
Documentation
#![allow(clippy::must_use_candidate)]

use std::fmt::{Debug, Write};
use std::ops::{Deref, DerefMut};
use std::str;

use dizzy::DstNewtype;

#[derive(PartialEq, DstNewtype)]
#[dizzy(invariant = str::is_ascii)]
#[dizzy(constructor = pub const from_str, getter = pub const as_str)]
#[dizzy(derive(Debug, Deref, IntoBoxed, CloneBoxed))]
#[repr(transparent)]
pub struct AsciiStr(str);

impl AsciiStr {
    #[inline]
    pub fn from_bytes(bytes: &[u8]) -> Option<&Self> {
        str::from_utf8(bytes).ok().and_then(Self::from_str)
    }
}

#[derive(Clone, Copy, PartialEq, Eq)]
#[must_use]
pub struct AsciiArray<const CAP: usize>(ArrayList<u8, CAP>);

impl<const CAP: usize> Deref for AsciiArray<CAP> {
    type Target = ArrayList<u8, CAP>;

    fn deref(&self) -> &Self::Target {
        &self.0
    }
}

impl<const CAP: usize> AsRef<AsciiStr> for AsciiArray<CAP> {
    #[inline]
    fn as_ref(&self) -> &AsciiStr {
        self.as_ascii_str()
    }
}

impl<const CAP: usize> AsRef<str> for AsciiArray<CAP> {
    #[inline]
    fn as_ref(&self) -> &str {
        self.as_ascii_str().as_str()
    }
}

impl<const CAP: usize> std::fmt::Display for AsciiArray<CAP> {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        f.write_str(self.as_str())
    }
}

impl<const CAP: usize> std::fmt::Debug for AsciiArray<CAP> {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        f.write_char('"')?;
        for ch in self.escape_ascii() {
            f.write_char(ch as char)?;
        }
        f.write_char('"')
    }
}

#[derive(Debug, Clone, Copy, thiserror::Error)]
#[error("Cannot store Non-Ascii data in an a AsciiArray")]
pub struct NonAscii;

impl<const N: usize> TryFrom<[u8; N]> for AsciiArray<N> {
    type Error = NonAscii;

    #[inline]
    fn try_from(array: [u8; N]) -> Result<Self, Self::Error> {
        Self::from_array(array, N)
    }
}

impl<const CAP: usize> Default for AsciiArray<CAP> {
    fn default() -> Self {
        Self::new()
    }
}

impl<const CAP: usize> AsciiArray<CAP> {
    #[inline]
    pub fn new() -> Self {
        Self(ArrayList::default())
    }

    #[inline]
    pub fn new_filled(byte: u8) -> Self {
        let mut x = Self::new();
        x.fill(byte);
        x
    }

    #[inline]
    pub const fn from_array(array: [u8; CAP], len: usize) -> Result<Self, NonAscii> {
        assert!(len <= CAP);

        if array.is_ascii() {
            Ok(Self(ArrayList::from_array(array, len)))
        } else {
            Err(NonAscii)
        }
    }

    pub fn from_bytes(bytes: &[u8]) -> Option<Self> {
        if bytes.len() > CAP {
            return None;
        }
        let mut array = [0u8; CAP];
        array[0..bytes.len()].copy_from_slice(bytes);

        Self::from_array(array, bytes.len()).ok()
    }

    pub fn copy_from_str(s: &str) -> Option<Self> {
        Self::from_bytes(s.as_bytes())
    }

    #[inline]
    pub fn as_str(&self) -> &str {
        self.as_ascii_str().as_str()
    }

    pub const fn get(&self, idx: usize) -> u8 {
        assert!(idx < self.0.len);
        self.0.array[idx]
    }

    /// Set the entire array to `ch`.
    #[inline]
    pub fn fill(&mut self, ch: u8) {
        assert!(ch.is_ascii());
        self.0.fill(ch);
    }

    pub fn fill_rest(&mut self, ch: u8) {
        assert!(ch.is_ascii());
        self.0.fill_rest(ch);
    }

    #[inline]
    pub fn push(&mut self, ch: u8) {
        assert!(ch.is_ascii());
        self.0.push(ch);
    }

    #[inline]
    pub fn pop(&mut self) -> Option<u8> {
        self.0.pop()
    }

    /// Trim arbatraty bytes from the end of the string.
    ///
    /// ```
    /// use sharkyflac::ascii_str::AsciiArray;
    ///
    /// let mut foo = AsciiArray::<16>::copy_from_str("bar\0\0\0\0").unwrap();
    /// assert!(foo.ends_with(b"\0"));
    ///
    /// foo.rtrim(b"\0");
    /// assert!(!foo.ends_with(b"\0"));
    /// ```
    pub fn rtrim(&mut self, needle: impl AsRef<[u8]>) {
        self.0.rtrim(needle)
    }

    #[inline]
    pub fn as_ascii_str(&self) -> &AsciiStr {
        AsciiStr::from_bytes(&self.0).unwrap()
    }
}

pub struct ArrayList<T, const C: usize> {
    array: [T; C],
    len:   usize,
}

impl<T: Clone, const C: usize> Clone for ArrayList<T, C> {
    fn clone(&self) -> Self {
        Self {
            array: self.array.clone(),
            len:   self.len,
        }
    }
}

impl<T: Debug, const C: usize> Debug for ArrayList<T, C> {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        f.debug_struct("ArrayList")
            .field("array", &&self.array[0..self.len])
            .field("len", &self.len)
            .finish()
    }
}

impl<T: Default + Clone + Copy, const C: usize> Default for ArrayList<T, C> {
    fn default() -> Self {
        Self {
            array: [T::default(); C],
            len:   0,
        }
    }
}

impl<T: Copy, const C: usize> Copy for ArrayList<T, C> {}

impl<T: PartialEq, const C: usize> PartialEq for ArrayList<T, C> {
    fn eq(&self, other: &Self) -> bool {
        self.array.eq(&other.array)
    }
}
impl<T: PartialEq, const C: usize> ArrayList<T, C> {
    pub fn rtrim(&mut self, needle: impl AsRef<[T]>) {
        let needle = needle.as_ref();
        if needle.is_empty() {
            return;
        }

        while self.array[..self.len].ends_with(needle) {
            self.len = self.len.saturating_sub(needle.len());
        }
    }
}

impl<T: Eq, const C: usize> Eq for ArrayList<T, C> {}

impl<T: Clone + Copy, const C: usize> ArrayList<T, C> {
    #[inline]
    pub fn new_with_len(item: T, len: usize) -> Self {
        assert!(len <= C);

        Self {
            array: [item; C],
            len,
        }
    }

    #[inline]
    pub fn new_filled(item: T) -> Self {
        Self::new_with_len(item, C)
    }
}

impl<T: Default + Clone + Copy, const C: usize> ArrayList<T, C> {
    #[inline]
    pub fn default_with_len(len: usize) -> Self {
        assert!(len <= C);
        Self::new_with_len(T::default(), len)
    }
}

impl<T: Default + Clone, const C: usize> ArrayList<T, C> {
    /// # Panics
    ///
    /// Will panic if the length of the slice is more than the remaning
    /// capacity.
    pub fn extend_from_slice(&mut self, slice: &[T]) {
        if slice.is_empty() {
            return;
        }
        assert!(slice.len() + self.len <= C);

        self.array[self.len..(self.len + slice.len())].clone_from_slice(slice);
        self.len += slice.len();
    }
}

impl<T: Clone, const C: usize> ArrayList<T, C> {
    #[inline]
    pub fn fill(&mut self, item: T) {
        self.array.fill(item);
    }

    pub fn fill_rest(&mut self, item: T) {
        self.array[self.len..].fill(item);
        self.len = C;
    }

    #[inline]
    pub fn pop(&mut self) -> Option<T> {
        self.len = self.len.checked_sub(1)?;
        Some(self.array[self.len].clone())
    }
}

impl<T, const C: usize> AsRef<[T]> for ArrayList<T, C> {
    #[inline]
    fn as_ref(&self) -> &[T] {
        &self.array[0..self.len]
    }
}

impl<T, const C: usize> AsMut<[T]> for ArrayList<T, C> {
    fn as_mut(&mut self) -> &mut [T] {
        &mut self.array[0..self.len]
    }
}
impl<T, const C: usize> Deref for ArrayList<T, C> {
    type Target = [T];

    #[inline]
    fn deref(&self) -> &Self::Target {
        &self.array[0..self.len]
    }
}
impl<T, const C: usize> DerefMut for ArrayList<T, C> {
    #[inline]
    fn deref_mut(&mut self) -> &mut Self::Target {
        &mut self.array[0..self.len]
    }
}

impl<T, const C: usize> ArrayList<T, C> {
    #[inline]
    pub fn push(&mut self, item: T) {
        assert!(self.len < C);

        self.array[self.len] = item;
        self.len += 1;
    }

    #[inline]
    pub const fn set_len(&mut self, new_len: usize) {
        assert!(new_len <= C);
        self.len = new_len;
    }

    #[inline]
    pub const fn from_array(array: [T; C], len: usize) -> Self {
        assert!(len <= C);
        Self { array, len }
    }
}

impl<const C: usize, T> From<[T; C]> for ArrayList<T, C> {
    #[inline]
    fn from(value: [T; C]) -> Self {
        Self::from_array(value, C)
    }
}