slen 0.1.1

A library for encoding and decoding loadouts from the Splatoon series.
Documentation
use array_init::try_array_init;
use crate::ParseFailure;
use substring::Substring;

#[derive(Debug, PartialEq, Eq)]
pub struct GearItem {
    pub id: u16,
    pub main: u8,
    pub subs: [u8; 3],
}

impl std::fmt::Display for GearItem {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        write!(
            f,
            "{:x}",
            u64::from_str_radix(
                &format!(
                    "{:05b}{:05b}{:05b}{:05b}{:05b}",
                    self.id, self.main, self.subs[0], self.subs[1], self.subs[2]
                ),
                2
            )
            .unwrap()
        )
    }
}

macro_rules! assign_or_fail {
    ($e:expr, $fail:expr) => {
        if let Ok(v) = { $e } {
            v
        } else {
            $fail
        }
    };
}

impl std::str::FromStr for GearItem {
    type Err = ParseFailure;

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        let id = assign_or_fail!(
            u16::from_str_radix(s.substring(0, 2), 16),
            return Err(ParseFailure::Value)
        );

        let s = if let Some(v) = crate::hexstr_to_bin(s.substring(2, 7)) {
            v
        } else {
            return Err(ParseFailure::Value);
        };

        let main = assign_or_fail!(
            u8::from_str_radix(s.substring(0, 5), 2),
            return Err(ParseFailure::Value)
        );

        let step = [5, 10, 15, 20];
        let subs: [u8; 3] = assign_or_fail!(
            try_array_init(|i| { u8::from_str_radix(s.substring(step[i], step[i + 1]), 2) }),
            return Err(ParseFailure::Value)
        );

        Ok(Self { id, main, subs })
    }
}