esl 0.17.1

A library for reading, writing and processing ESM/ESP/ESS files.
Documentation
use std::char::{self};
use std::fmt::{self, Debug, Display, Formatter};
use std::str::{FromStr};

#[derive(Ord, PartialOrd, Eq, PartialEq, Hash, Copy, Clone)]
pub struct Tag {
    pub dword: u32
}

impl const From<u32> for Tag {
    fn from(dword: u32) -> Tag {
        Tag { dword }
    }
}

impl Debug for Tag {
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
        Display::fmt(self, f)
    }
}

fn byte_to_char(b: u8) -> char {
    char::from_u32((u32::from(b >> 7) << 8) | u32::from(b)).unwrap()
}

fn char_to_byte(c: char) -> Option<u8> {
    let c = c as u32;
    match c {
        0x00 ..= 0x7F => Some(c as u8),
        0x180 ..= 0x1FF => Some((c & 0xFF) as u8),
        _ => None
    }
}

impl Display for Tag {
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
        let c0 = byte_to_char(self.dword as u8);
        let c1 = byte_to_char((self.dword >> 8) as u8);
        let c2 = byte_to_char((self.dword >> 16) as u8);
        let c3 = byte_to_char((self.dword >> 24) as u8);
        write!(f, "{c0}{c1}{c2}{c3}")
    }
}

impl FromStr for Tag {
    type Err = ();

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        let mut dword = 0;
        let mut i = 0;
        for c in s.chars() {
            if i == 4 { return Err(()); }
            dword |= u32::from(char_to_byte(c).ok_or(())?) << (8 * i);
            i += 1;
        }
        if i != 4 { return Err(()); }
        Ok(Tag { dword })
    }
}

macro_rules! enum_serde {
    ($name:ty, $exp:literal, as $bits:ty, $signed:ident, $big:ident) => {
        impl ::serde::Serialize for $name {
            fn serialize<S>(&self, serializer: S) -> ::std::result::Result<S::Ok, S::Error> where
                S: ::serde::Serializer {
        
                if serializer.is_human_readable() {
                    format!("{}", self).serialize(serializer)
                } else {
                    <$bits as ::serde::Serialize>::serialize(
                        &(*self as $bits),
                        serializer
                    )
                }
            }
        }
        
        impl<'de> ::serde::Deserialize<'de> for $name {
            fn deserialize<D>(deserializer: D) -> ::std::result::Result<Self, D::Error> where
                D: ::serde::Deserializer<'de> {
        
                struct HRDeVisitor;
                
                impl<'de> ::serde::de::Visitor<'de> for HRDeVisitor {
                    type Value = $name;
                
                    fn expecting(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { write!(f, $exp) }
                
                    fn visit_str<E>(self, s: &str) -> Result<Self::Value, E> where E: ::serde::de::Error {
                        ::std::str::FromStr::from_str(s).map_err(|_| E::invalid_value(::serde::de::Unexpected::Str(s), &self))
                    }
                }
        
                if deserializer.is_human_readable() {
                    deserializer.deserialize_str(HRDeVisitor)
                } else {
                    let b = <$bits as ::serde::Deserialize>::deserialize(deserializer)?;
                    <$name>::n(b).ok_or_else(|| <D::Error as ::serde::de::Error>::invalid_value(::serde::de::Unexpected::$signed(b as $big), &$exp))
                }
            }
        }
    };
    ($name:ty, $exp:literal, $bits:ty, $to:ident, $from:ident) => {
        impl ::serde::Serialize for $name {
            fn serialize<S>(&self, serializer: S) -> ::std::result::Result<S::Ok, S::Error> where
                S: ::serde::Serializer {
        
                if serializer.is_human_readable() {
                    format!("{}", self).serialize(serializer)
                } else {
                    <$bits as ::serde::Serialize>::serialize(&self.$to, serializer)
                }
            }
        }
        
        impl<'de> ::serde::Deserialize<'de> for $name {
            fn deserialize<D>(deserializer: D) -> ::std::result::Result<Self, D::Error> where
                D: ::serde::Deserializer<'de> {
        
                struct HRDeVisitor;
                
                impl<'de> ::serde::de::Visitor<'de> for HRDeVisitor {
                    type Value = $name;
                
                    fn expecting(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { write!(f, $exp) }
                
                    fn visit_str<E>(self, s: &str) -> Result<Self::Value, E> where E: ::serde::de::Error {
                        ::std::str::FromStr::from_str(s).map_err(|_| E::invalid_value(::serde::de::Unexpected::Str(s), &self))
                    }
                }
        
                if deserializer.is_human_readable() {
                    deserializer.deserialize_str(HRDeVisitor)
                } else {
                    let b = <$bits as ::serde::Deserialize>::deserialize(deserializer)?;
                    Ok(<$name>::$from(b))
                }
            }
        }
    };
    ($name:ty, $exp:literal, $bits:ty, $to:ident, try $from:ident, $signed:ident, $big:ident $(, ^$xor:literal)?) => {
        impl ::serde::Serialize for $name {
            fn serialize<S>(&self, serializer: S) -> ::std::result::Result<S::Ok, S::Error> where
                S: ::serde::Serializer {
        
                if serializer.is_human_readable() {
                    format!("{}", self).serialize(serializer)
                } else {
                    <$bits as ::serde::Serialize>::serialize(&(self.$to $(^ $xor)?), serializer)
                }
            }
        }
        
        impl<'de> ::serde::Deserialize<'de> for $name {
            fn deserialize<D>(deserializer: D) -> ::std::result::Result<Self, D::Error> where
                D: ::serde::Deserializer<'de> {
        
                struct HRDeVisitor;
                
                impl<'de> ::serde::de::Visitor<'de> for HRDeVisitor {
                    type Value = $name;
                
                    fn expecting(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { write!(f, $exp) }
                
                    fn visit_str<E>(self, s: &str) -> Result<Self::Value, E> where E: ::serde::de::Error {
                        ::std::str::FromStr::from_str(s).map_err(|_| E::invalid_value(::serde::de::Unexpected::Str(s), &self))
                    }
                }
        
                if deserializer.is_human_readable() {
                    deserializer.deserialize_str(HRDeVisitor)
                } else {
                    let b = <$bits as ::serde::Deserialize>::deserialize(deserializer)? $(^ $xor)?;
                    let v = <$name>::$from(b).ok_or_else(|| <D::Error as ::serde::de::Error>::invalid_value(::serde::de::Unexpected::$signed(b as $big), &$exp))?;
                    Ok(v)
                }
            }
        }
    };
    ($name:ty, $exp:literal, $bits:ty, $to:ident (), try $from:ident, $signed:ident, $big:ident $(, ^$xor:literal)?) => {
        impl ::serde::Serialize for $name {
            fn serialize<S>(&self, serializer: S) -> ::std::result::Result<S::Ok, S::Error> where
                S: ::serde::Serializer {
        
                if serializer.is_human_readable() {
                    format!("{}", self).serialize(serializer)
                } else {
                    <$bits as ::serde::Serialize>::serialize(&(self.$to() $(^ $xor)?), serializer)
                }
            }
        }
        
        impl<'de> ::serde::Deserialize<'de> for $name {
            fn deserialize<D>(deserializer: D) -> ::std::result::Result<Self, D::Error> where
                D: ::serde::Deserializer<'de> {
        
                struct HRDeVisitor;
                
                impl<'de> ::serde::de::Visitor<'de> for HRDeVisitor {
                    type Value = $name;
                
                    fn expecting(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { write!(f, $exp) }
                
                    fn visit_str<E>(self, s: &str) -> Result<Self::Value, E> where E: ::serde::de::Error {
                        ::std::str::FromStr::from_str(s).map_err(|_| E::invalid_value(::serde::de::Unexpected::Str(s), &self))
                    }
                }
        
                if deserializer.is_human_readable() {
                    deserializer.deserialize_str(HRDeVisitor)
                } else {
                    let b = <$bits as ::serde::Deserialize>::deserialize(deserializer)? $(^ $xor)?;
                    let v = <$name>::$from(b).ok_or_else(|| <D::Error as ::serde::de::Error>::invalid_value(::serde::de::Unexpected::$signed(b as $big), &$exp))?;
                    Ok(v)
                }
            }
        }
    }
}

enum_serde!(Tag, "four-byte tag", u32, dword, from);