use std::{borrow::Cow, string::String as StdString};
use binrw::binrw;
#[binrw]
#[derive(Debug, Clone, PartialEq, Eq)]
#[brw(big)]
pub struct String {
    #[bw(calc = payload.len() as u32)]
    len: u32,
    #[br(count = len)]
    payload: Vec<u8>,
}
impl std::ops::Deref for String {
    type Target = [u8];
    fn deref(&self) -> &Self::Target {
        self.payload.as_ref()
    }
}
#[binrw]
#[derive(Debug, Clone, PartialEq, Eq)]
#[brw(big)]
pub struct StringUtf8 {
    #[bw(calc = payload.len() as u32)]
    size: u32,
    #[br(try_map = |bytes: Vec<u8>| StdString::from_utf8(bytes).map(Cow::Owned), count = size)]
    #[bw(map = |payload| payload.as_bytes())]
    payload: Cow<'static, str>,
}
impl StringUtf8 {
    pub fn new(s: impl Into<Cow<'static, str>>) -> Self {
        Self { payload: s.into() }
    }
}
impl std::ops::Deref for StringUtf8 {
    type Target = str;
    fn deref(&self) -> &Self::Target {
        self.payload.as_ref()
    }
}
#[binrw]
#[derive(Debug, Clone, PartialEq, Eq)]
#[brw(big)]
pub struct StringAscii {
    #[bw(calc = payload.len() as u32)]
    size: u32,
    #[br(try_map = |bytes: Vec<u8>| StdString::from_utf8(bytes).map(Cow::Owned), count = size)]
    #[bw(map = |payload| payload.as_bytes())]
    #[brw(assert(payload.is_ascii()))]
    payload: Cow<'static, str>,
}
impl StringAscii {
    pub fn new(s: impl Into<Cow<'static, str>>) -> Self {
        Self { payload: s.into() }
    }
}
impl std::ops::Deref for StringAscii {
    type Target = str;
    fn deref(&self) -> &Self::Target {
        self.payload.as_ref()
    }
}
#[binrw]
#[derive(Debug, Clone, PartialEq, Eq)]
#[brw(big)]
pub struct NameList(StringAscii);
#[binrw]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[brw(big)]
pub struct Bool(
    #[br(map = |n: u8| n > 0)]
    #[bw(map = |b| u8::from(*b))]
    bool,
);
impl std::ops::Not for Bool {
    type Output = Self;
    fn not(self) -> Self::Output {
        Self(!self.0)
    }
}
impl std::ops::Deref for Bool {
    type Target = bool;
    fn deref(&self) -> &Self::Target {
        &self.0
    }
}
impl std::convert::From<bool> for Bool {
    fn from(value: bool) -> Self {
        Self(value)
    }
}