pit-core 0.4.9

Portal Interface Types
use alloc::{borrow::ToOwned, collections::BTreeMap, string::String, vec::Vec};
use core::fmt::Display;

use nom::{
    bytes::complete::{tag, take_while_m_n},
    character::complete::{alphanumeric1, multispace0},
    multi::many0,
    sequence::delimited,
    IResult, Parser,
};

use crate::{merge, parse_attr, Attr};
#[derive(Default, Clone, Eq, PartialEq, PartialOrd, Ord, Hash, Debug)]
pub struct Info {
    pub interfaces: BTreeMap<[u8; 32], InfoEntry>,
}
impl Info {
    pub fn merge(self, x: Info) -> Info {
        let mut m: BTreeMap<[u8; 32], InfoEntry> = BTreeMap::new();
        for (a, b) in self.interfaces.into_iter().chain(x.interfaces.into_iter()) {
            let c = m.remove(&a).unwrap_or_default().merge(b);
            m.insert(a, c);
        }
        Info { interfaces: m }
    }
}
#[derive(Default, Clone, Eq, PartialEq, PartialOrd, Ord, Hash, Debug)]
pub struct InfoEntry {
    pub attrs: Vec<Attr>,
    pub methods: BTreeMap<String, MethEntry>,
}
impl InfoEntry {
    pub fn merge(self, x: InfoEntry) -> InfoEntry {
        let mut m: BTreeMap<String, MethEntry> = BTreeMap::new();
        for (a, b) in self.methods.into_iter().chain(x.methods.into_iter()) {
            let c = m.remove(&a).unwrap_or_default().merge(b);
            m.insert(a, c);
        }
        InfoEntry {
            attrs: merge(self.attrs, x.attrs),
            methods: m,
        }
    }
}
#[derive(Default, Clone, Eq, PartialEq, PartialOrd, Ord, Hash, Debug)]
pub struct MethEntry {
    pub attrs: Vec<Attr>,
}
impl MethEntry {
    pub fn merge(self, x: MethEntry) -> MethEntry {
        MethEntry {
            attrs: merge(self.attrs, x.attrs),
        }
    }
}
impl Display for InfoEntry {
    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
        for a in self.attrs.iter() {
            write!(f, "root {a}")?;
        }
        for (k, m) in self.methods.iter() {
            for a in m.attrs.iter() {
                write!(f, "method {k} {a}")?;
            }
        }
        Ok(())
    }
}
impl Display for Info {
    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
        for (i, j) in self.interfaces.iter() {
            write!(f, "{}: [{j}]", hex::encode(i))?;
        }
        Ok(())
    }
}
pub fn parse_entry(a: &str) -> IResult<&str, InfoEntry> {
    let (a, _) = multispace0(a)?;
    pub fn go1(a: &str) -> IResult<&str, Attr> {
        let (a, _) = multispace0(a)?;
        let (a, _) = tag("root")(a)?;
        let (a, _) = multispace0(a)?;
        return parse_attr(a);
    }
    pub fn go2(a: &str) -> IResult<&str, (&str, Attr)> {
        let (a, _) = multispace0(a)?;
        let (a, _) = tag("method")(a)?;
        let (a, _) = multispace0(a)?;
        let (a, b) = alphanumeric1(a)?;
        let (a, _) = multispace0(a)?;
        let (a, c) = parse_attr(a)?;
        Ok((a, (b, c)))
    }
    let (a, mut e) = many0(go1).parse(a)?;
    e.sort_by_key(|k| k.name.clone());
    let mut n: BTreeMap<String, MethEntry> = BTreeMap::new();
    let (a, l) = many0(go2).parse(a)?;
    for (k, v) in l {
        n.entry(k.to_owned())
            .or_insert_with(Default::default)
            .attrs
            .push(v);
    }
    for v in n.values_mut() {
        v.attrs.sort_by_key(|k| k.name.clone());
    }
    let (a, _) = multispace0(a)?;
    Ok((
        a,
        InfoEntry {
            attrs: e,
            methods: n,
        },
    ))
}
pub fn parse_info(a: &str) -> IResult<&str, Info> {
    pub fn go(a: &str) -> IResult<&str, ([u8; 32], InfoEntry)> {
        let (a, _) = multispace0(a)?;
        let (a, d) = take_while_m_n(64, 64, |a: char| a.is_digit(16))(a)?;
        let mut b = [0u8; 32];
        hex::decode_to_slice(d, &mut b).unwrap();
        let (a, _) = multispace0(a)?;
        let (a, _) = tag(":")(a)?;
        let (a, _) = multispace0(a)?;
        let (a, c) = delimited(tag("["), parse_entry, tag("]")).parse(a)?;
        return Ok((a, (b, c)));
    }
    let (a, all) = many0(go).parse(a)?;
    Ok((
        a,
        Info {
            interfaces: all.into_iter().collect(),
        },
    ))
}