1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
use std::{fmt::Display, str::FromStr};

use crate::ParseError;

use super::Property;

#[derive(Debug)]
pub struct Update {
    pub id: u64,
    pub props: Vec<Property>,
}

impl FromStr for Update {
    type Err = ParseError;

    fn from_str(line: &str) -> Result<Self, Self::Err> {
        let (id, mut rest) = line.split_once(',').ok_or(ParseError::Eol)?;
        let id = u64::from_str_radix(id, 16)?;
        let mut props = Vec::new();

        let mut prev = None;
        let mut offset = 0;
        for (i, ch) in rest.char_indices() {
            if ch == ',' && prev != Some('\\') {
                let (kv, r) = rest.split_at(i - offset);
                rest = r.strip_prefix(',').unwrap_or(rest);
                offset = i + 1;

                props.push(Property::from_str(kv)?);
            }

            prev = Some(ch);
        }

        if !rest.is_empty() {
            props.push(Property::from_str(rest)?);
        }

        Ok(Update { id, props })
    }
}

impl Display for Update {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        write!(f, "{}", self.id)?;
        for p in &self.props {
            write!(f, ",{}", p)?;
        }
        Ok(())
    }
}