zusi-protocol 0.2.1

Contains serialization and deserialization logic for the Zusi 3 TCP-Protocol
Documentation
use either::Either;
use nom::{
    branch::alt,
    bytes::streaming::{tag, take},
    number::streaming::{le_u16, le_u32},
    IResult,
};

#[derive(Debug, Default)]
pub struct Node {
    pub id: u16,
    pub attributes: Vec<Attribute>,
    pub children: Vec<Node>,
}

impl Node {
    pub fn with_id(id: u16) -> Self {
        Self { id, ..Default::default() }
    }
}

#[derive(Debug)]
pub struct Attribute {
    pub id: u16,
    pub value: Vec<u8>,
}

pub fn read(input: &[u8]) -> IResult<&[u8], Option<AttrOrNode>> {
    let (input, attr_or_node) = alt((node, end, attribute))(input)?;

    Ok((input, attr_or_node))
}

pub fn node(input: &[u8]) -> IResult<&[u8], Option<AttrOrNode>> {
    let (input, _) = tag(&[0x00, 0x00, 0x00, 0x00])(input)?;
    let (input, id) = le_u16(input)?;

    let mut node = Node::with_id(id);

    let mut input = input;
    loop {
        let (inp, elem) = read(input)?;
        input = inp;
        if let Some(elem) = elem {
            match elem {
                Either::Left(a) => node.attributes.push(a),
                Either::Right(n) => node.children.push(n),
            }
        } else {
            return Ok((input, Some(node.into())));
        }
    }
}

pub fn attribute(input: &[u8]) -> IResult<&[u8], Option<AttrOrNode>> {
    let (input, len) = le_u32(input)?;
    let (input, id) = le_u16(input)?;
    let (input, value) = take(len - 2)(input)?;

    Ok((input, Some(Attribute { id, value: value.to_vec() }.into())))
}

pub fn end(input: &[u8]) -> IResult<&[u8], Option<AttrOrNode>> {
    let (input, _) = tag(&[0xFF, 0xFF, 0xFF, 0xFF])(input)?;

    Ok((input, None))
}

pub type AttrOrNode = Either<Attribute, Node>;

impl From<Node> for AttrOrNode {
    fn from(n: Node) -> Self {
        Self::Right(n)
    }
}

impl From<Attribute> for AttrOrNode {
    fn from(a: Attribute) -> Self {
        Self::Left(a)
    }
}