sms_2dm/
nodestring.rs

1use std::{fmt, ops::ControlFlow};
2
3use num_traits::Unsigned;
4#[cfg(feature = "serde")]
5use serde::{Deserialize, Serialize};
6
7use crate::{error::weak_error, DefaultUnsigned, Error};
8
9pub(crate) const NODESTRING_TAG: &str = "NS";
10/// Identifies a nodestring.
11#[derive(Clone, Debug, PartialEq)]
12#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
13pub struct Nodestring<U = DefaultUnsigned>
14where
15    U: Unsigned + Copy + fmt::Debug,
16    Error: From<U::FromStrRadixErr>,
17{
18    pub nodes: Vec<U>,
19}
20impl<U> Nodestring<U>
21where
22    U: Unsigned + Copy + fmt::Debug,
23    Error: From<U::FromStrRadixErr>,
24{
25    pub(crate) fn new() -> Self {
26        Self { nodes: vec![] }
27    }
28
29    /// Ingest a nodestring card.
30    ///
31    /// The returned [`ControlFlow`] indicates whether parsing should continue
32    /// into the next line (i.e. `Break` when a tail node is encountered).
33    ///
34    /// The tail node is denoted by a negative sign prefix.
35    pub(crate) fn ingest(&mut self, line: impl AsRef<str>) -> Result<ControlFlow<()>, Error> {
36        let line = line.as_ref();
37        let mut field_it = line.split_whitespace();
38
39        match field_it.next() {
40            Some(NODESTRING_TAG) => {} // tag matches, continue
41            Some(t) => Err(Error::WrongCardTag {
42                expect: NODESTRING_TAG.into(),
43                actual: t.into(),
44            })?,
45            None => Err(Error::EmptyLine)?,
46        }
47
48        while let Some(node_raw) = field_it.next() {
49            if let Some(node_n) = node_raw.strip_prefix('-') {
50                let node = U::from_str_radix(node_n, 10)?;
51                self.nodes.push(node);
52
53                if let Some(val) = field_it.next() {
54                    weak_error(Error::ExtraneousValue(val.into()))?;
55                }
56                return Ok(ControlFlow::Break(()));
57            }
58
59            let node = U::from_str_radix(node_raw, 10)?;
60            self.nodes.push(node);
61        }
62
63        Ok(ControlFlow::Continue(()))
64    }
65}