esl 0.17.1

A library for reading, writing and processing ESM/ESP/ESS files.
Documentation
use crate::code_page::CodePage;
use educe::Educe;
use either::{Either, Left,  Right};
use iter_identify_first_last::IteratorIdentifyFirstLastExt;
use phantom_type::PhantomType;
use serde::{Serialize, Deserialize, Serializer, Deserializer};
use serde::de::{self, Unexpected, DeserializeSeed};
use serde::de::Error as de_Error;
use serde::ser::Error as ser_Error;
use serde::ser::SerializeTuple;
use serde_serialize_seed::{SerializeSeed, ValueWithSeed};
use std::fmt::{self, Display, Formatter};
use std::fmt::Write as fmt_Write;
use std::str::FromStr;

#[derive(Clone)]
pub struct HexDump;

impl SerializeSeed for HexDump {
    type Value = [u8];

    fn serialize<S: Serializer>(&self, value: &Self::Value, serializer: S) -> Result<S::Ok, S::Error> {
        if serializer.is_human_readable() {
            let lines = value.chunks(32).map(|x| {
                let mut s = String::with_capacity(32 * 2 + 31);
                for (is_first, b) in x.iter().copied().identify_first() {
                    if !is_first { s.push(' '); }
                    write!(&mut s, "{b:02X}").unwrap();
                }
                s
            }).collect::<Vec<_>>();
            lines.serialize(serializer)
        } else {
            value.serialize(serializer)
        }
    }
}

impl<'de> DeserializeSeed<'de> for HexDump {
    type Value = Vec<u8>;

    fn deserialize<D: Deserializer<'de>>(self, deserializer: D) -> Result<Self::Value, D::Error> {
        if deserializer.is_human_readable() {
            let lines = <Vec<String>>::deserialize(deserializer)?;
            lines
                .into_iter()
                .flat_map(|x| x.split(' ').filter(|x| !x.is_empty()).map(|x| u8::from_str_radix(x, 16)).collect::<Vec<_>>())
                .try_collect()
                .map_err(|x| D::Error::custom(x.to_string()))
        } else {
            <Vec<u8>>::deserialize(deserializer)
        }
    }
}

#[derive(Educe)]
#[educe(Clone)]
pub struct ArraySerde<T> {
    pub len: usize,
    pub phantom: PhantomType<T>,
}

impl<T: Serialize> SerializeSeed for ArraySerde<T> {
    type Value = [T];

    fn serialize<S: Serializer>(&self, value: &Self::Value, serializer: S) -> Result<S::Ok, S::Error> {
        assert_eq!(value.len(), self.len);
        let mut serializer = serializer.serialize_tuple(self.len)?;
        for item in value {
            serializer.serialize_element(item)?;
        }
        serializer.end()
    }
}

struct ArrayDeVisitor<T>(PhantomType<T>);

impl<'de, T: Deserialize<'de>> de::Visitor<'de> for ArrayDeVisitor<T> {
    type Value = Vec<T>;

    fn expecting(&self, f: &mut Formatter) -> fmt::Result {
        write!(f, "array")
    }

    fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error> where A: de::SeqAccess<'de> {
        let mut res = seq.size_hint().map_or_else(Vec::new, Vec::with_capacity);
        while let Some(item) = seq.next_element()? {
            res.push(item);
        }
        Ok(res)
    }
}

impl<'de, T: Deserialize<'de>> DeserializeSeed<'de> for ArraySerde<T> {
    type Value = Vec<T>;

    fn deserialize<D: Deserializer<'de>>(self, deserializer: D) -> Result<Self::Value, D::Error> {
        deserializer.deserialize_tuple(self.len, ArrayDeVisitor(PhantomType::new()))
    }
}

#[derive(Clone)]
pub struct NoneU8Serde { pub none: u8 }

impl SerializeSeed for NoneU8Serde {
    type Value = ();

    fn serialize<S: Serializer>(&self, _value: &Self::Value, serializer: S) -> Result<S::Ok, S::Error> {
        if serializer.is_human_readable() {
            ().serialize(serializer)
        } else {
            self.none.serialize(serializer)
        }
    }
}

impl<'de> DeserializeSeed<'de> for NoneU8Serde {
    type Value = ();

    fn deserialize<D: Deserializer<'de>>(self, deserializer: D) -> Result<Self::Value, D::Error> {
        if deserializer.is_human_readable() {
            <()>::deserialize(deserializer)
        } else {
            let d = u8::deserialize(deserializer)?;
            if d != self.none {
                let e: &str = &format!("{}", self.none);
                Err(D::Error::invalid_value(Unexpected::Unsigned(d as u64), &e))
            } else {
                Ok(())
            }
        }
    }
}

#[derive(Clone)]
pub struct BoolU8Serde;

impl SerializeSeed for BoolU8Serde {
    type Value = bool;

    fn serialize<S: Serializer>(&self, &value: &Self::Value, serializer: S) -> Result<S::Ok, S::Error> {
        if serializer.is_human_readable() {
            value.serialize(serializer)
        } else {
            u8::from(value).serialize(serializer)
        }
    }
}

impl<'de> DeserializeSeed<'de> for BoolU8Serde {
    type Value = bool;

    fn deserialize<D: Deserializer<'de>>(self, deserializer: D) -> Result<Self::Value, D::Error> {
        if deserializer.is_human_readable() {
            Ok(bool::deserialize(deserializer)?)
        } else {
            let d = u8::deserialize(deserializer)?;
            match d {
                0 => Ok(false),
                1 => Ok(true),
                d => Err(D::Error::invalid_value(Unexpected::Unsigned(d as u64), &"0 or 1"))
            }
        }
    }
}

#[derive(Clone)]
pub struct BoolU32Serde;

impl SerializeSeed for BoolU32Serde {
    type Value = bool;

    fn serialize<S: Serializer>(&self, &value: &Self::Value, serializer: S) -> Result<S::Ok, S::Error> {
        if serializer.is_human_readable() {
            value.serialize(serializer)
        } else {
            u32::from(value).serialize(serializer)
        }
    }
}

impl<'de> DeserializeSeed<'de> for BoolU32Serde {
    type Value = bool;

    fn deserialize<D: Deserializer<'de>>(self, deserializer: D) -> Result<Self::Value, D::Error> {
        if deserializer.is_human_readable() {
            Ok(bool::deserialize(deserializer)?)
        } else {
            let d = u32::deserialize(deserializer)?;
            match d {
                0 => Ok(false),
                1 => Ok(true),
                d => Err(D::Error::invalid_value(Unexpected::Unsigned(d as u64), &"0 or 1"))
            }
        }
    }
}

#[derive(Clone)]
pub struct OptionIndexSerde<
    I: Copy + Eq + Display,
    T: Copy,
    From: Fn(I) -> Option<T>,
    Into: Fn(T) -> I,
> {
    pub name: &'static str,
    pub none: I,
    pub from: From,
    pub into: Into,
}

impl<
    I: Copy + Eq + Display + Serialize,
    T: Copy + Serialize,
    From: Fn(I) -> Option<T>,
    Into: Fn(T) -> I,
> SerializeSeed for OptionIndexSerde<I, T, From, Into> {
    type Value = Either<Option<I>, T>;

    fn serialize<S: Serializer>(&self, &value: &Self::Value, serializer: S) -> Result<S::Ok, S::Error> {
        if serializer.is_human_readable() {
            match value {
                Left(i) => OptionIndexHRSurrogate::None(i),
                Right(v) => OptionIndexHRSurrogate::Some(v),
            }.serialize(serializer)
        } else {
            let v = match value {
                Left(Some(i)) => {
                    if i == self.none || (self.from)(i).is_some() {
                        let err = format!("{} is not valid undefined {} value", i, self.name);
                        return Err(S::Error::custom(err));
                    }
                    i
                },
                Left(None) => self.none,
                Right(a) => (self.into)(a)
            };
            v.serialize(serializer)
        }
    }
}

impl<
    'de,
    I: Copy + Eq + Display + Deserialize<'de>,
    T: Copy + Deserialize<'de>,
    From: Fn(I) -> Option<T>,
    Into: Fn(T) -> I,
> DeserializeSeed<'de> for OptionIndexSerde<I, T, From, Into> {
    type Value = Either<Option<I>, T>;

    fn deserialize<D: Deserializer<'de>>(self, deserializer: D) -> Result<Self::Value, D::Error> {
        if deserializer.is_human_readable() {
            let v = <OptionIndexHRSurrogate<I, T>>::deserialize(deserializer)?;
            Ok(match v {
                OptionIndexHRSurrogate::None(i) => Left(i),
                OptionIndexHRSurrogate::Some(v) => Right(v),
            })
        } else {
            let d = I::deserialize(deserializer)?;
            if d == self.none { return Ok(Left(None)); }
            if let Some(a) = (self.from)(d) {
                Ok(Right(a))
            } else {
                Ok(Left(Some(d)))
            }
        }
    }
}

#[derive(Serialize, Deserialize)]
#[serde(untagged)]
#[serde(rename="OptionIndex")]
enum OptionIndexHRSurrogate<I, T> {
    None(Option<I>),
    Some(T)
}

#[derive(Clone)]
pub struct F32AsIsSerde;

impl SerializeSeed for F32AsIsSerde {
    type Value = f32;

    fn serialize<S>(&self, &value: &Self::Value, serializer: S) -> Result<S::Ok, S::Error> where S: Serializer {
        if !serializer.is_human_readable() {
            value.serialize(serializer)
        } else if value.is_nan() {
            let d: u32 = value.to_bits();
            if d == 0xFFFFFFFF {
                value.serialize(serializer)
            } else {
                format!("nan{d:08X}").serialize(serializer)
            }
        } else {
            f64::from_str(&value.to_string()).unwrap().copysign(value as f64).serialize(serializer)
        }
    }
}

impl<'de> DeserializeSeed<'de> for F32AsIsSerde {
    type Value = f32;

    fn deserialize<D>(self, deserializer: D) -> Result<Self::Value, D::Error> where D: Deserializer<'de> {
        if deserializer.is_human_readable() {
            deserializer.deserialize_any(F32HRDeVisitor)
        } else {
            Ok(f32::deserialize(deserializer)?)
        }
    }
}

struct F32HRDeVisitor;

impl<'de> de::Visitor<'de> for F32HRDeVisitor {
    type Value = f32;

    fn expecting(&self, f: &mut Formatter) -> fmt::Result {
        write!(f, "32-bit float value or 'nanXXXXXXXX' (where X is hex digit)")
    }

    fn visit_f32<E>(self, v: f32) -> Result<Self::Value, E> where E: de::Error {
        Ok(if v.is_nan() { f32::from_bits(0xFFFFFFFFu32) } else { v })
    }

    fn visit_f64<E>(self, v: f64) -> Result<Self::Value, E> where E: de::Error {
        let v_as_f32 = v as f32;
        if !v_as_f32.is_nan() || !v.is_nan() {
            let v_as_u64: u64 = v.to_bits();
            let v_as_u32_as_u64: u64 = f64::from_str(&v_as_f32.to_string()).unwrap().copysign(v_as_f32 as f64).to_bits();
            if v_as_u32_as_u64 != v_as_u64 {
                return Err(E::invalid_value(Unexpected::Float(v), &self));
            }
        }
        self.visit_f32(v_as_f32)
    }

    fn visit_str<E>(self, s: &str) -> Result<Self::Value, E> where E: de::Error {
        if s.len() != 3 + 8 || !s.starts_with("nan") || &s[4..5] == "+" {
            return Err(E::invalid_value(Unexpected::Str(s), &self));
        }
        let d = u32::from_str_radix(&s[3..], 16).map_err(|_| E::invalid_value(Unexpected::Str(s), &self))?;
        if d == 0xFFFFFFFF {
            return Err(E::invalid_value(Unexpected::Str(s), &self));
        }
        Ok(f32::from_bits(d))
    }
}

#[derive(Clone)]
pub struct StringSerde {
    pub code_page: Option<CodePage>,
    pub len: Option<usize>
}

impl SerializeSeed for StringSerde {
    type Value = str;

    fn serialize<S: Serializer>(&self, value: &Self::Value, serializer: S) -> Result<S::Ok, S::Error> {
        if serializer.is_human_readable() {
            value.serialize(serializer)
        } else {
            let Some(code_page) = self.code_page else {
                return Err(S::Error::custom("code page required for binary serialization"));
            };
            let mut bytes = code_page.encode(value).map_err(|e| match e {
                None => S::Error::custom(format!("the '{value}' string does not correspond to any source byte sequence")),
                Some(c) => S::Error::custom(format!("the '{c}' char is not representable in {code_page:?} code page"))
            })?;
            if let Some(len) = self.len {
                if bytes.len() > len {
                    return Err(S::Error::custom(format!(
                        "short string (len = {}) does not fit (max len = {})", bytes.len(), len
                    )));
                }
                if bytes.last() == Some(&0) {
                    return Err(S::Error::custom("short string value has tail zero"));
                }
                bytes.resize(len, 0);
                ValueWithSeed(&bytes[..], ArraySerde { len, phantom: PhantomType::new() }).serialize(serializer)
            } else {
                bytes.serialize(serializer)
            }
        }
    }
}

impl<'de> DeserializeSeed<'de> for StringSerde {
    type Value = String;

    fn deserialize<D: Deserializer<'de>>(self, deserializer: D) -> Result<Self::Value, D::Error> {
        if deserializer.is_human_readable() {
            String::deserialize(deserializer)
        } else {
            let bytes = if let Some(len) = self.len {
                ArraySerde { len, phantom: PhantomType::new() }.deserialize(deserializer)?
            } else {
                <Vec<u8>>::deserialize(deserializer)?
            };
            let bytes = if self.len.is_some() {
                let trim = bytes.iter().copied().rev().take_while(|&x| x == 0).count();
                &bytes[.. bytes.len() - trim]
            } else {
                &bytes
            };
            let Some(code_page) = self.code_page else {
                return Err(D::Error::custom("code page required for binary serialization"));
            };
            Ok(code_page.decode(bytes))
        }
    }
}

#[derive(Clone)]
pub struct StringListSerde {
    pub code_page: Option<CodePage>,
    pub separator: &'static str,
    pub len: Option<usize>
}

impl SerializeSeed for StringListSerde {
    type Value = [String];

    fn serialize<S: Serializer>(&self, value: &Self::Value, serializer: S) -> Result<S::Ok, S::Error> {
        if serializer.is_human_readable() {
            value.serialize(serializer)
        } else {
            if self.separator.is_empty() {
                return Err(S::Error::custom("empty string list separator"));
            }
            if value.is_empty() {
                return Err(S::Error::custom("\
                    empty string list cannot be serialized bacause \
                    it is indistinguishable from list with one empty string\
                "));
            }
            let mut capacity = 0;
            for line in value {
                if line.contains(self.separator) {
                    return Err(S::Error::custom("string list item contains separator"));
                }
                capacity += line.len() + self.separator.len();
            }
            let mut text = String::with_capacity(capacity);
            for line in value.iter() {
                text.push_str(line);
                text.push_str(self.separator);
            }
            text.truncate(text.len() - self.separator.len());
            ValueWithSeed(text.as_str(), StringSerde { code_page: self.code_page, len: self.len }).serialize(serializer)
        }
    }
}

impl<'de> DeserializeSeed<'de> for StringListSerde {
    type Value = Vec<String>;

    fn deserialize<D: Deserializer<'de>>(self, deserializer: D) -> Result<Self::Value, D::Error> {
        if deserializer.is_human_readable() {
            <Vec<String>>::deserialize(deserializer)
        } else {
            if self.separator.is_empty() {
                return Err(D::Error::custom("empty string list separator"));
            }
            let s = StringSerde { code_page: self.code_page, len: self.len }.deserialize(deserializer)?;
            Ok(s.split(self.separator).map(|x| x.into()).collect())
        }
    }
}