sms_2dm/
node.rs

1use std::{fmt, str::FromStr};
2
3use num_traits::{Float, Unsigned};
4#[cfg(feature = "serde")]
5use serde::{Deserialize, Serialize};
6
7use crate::{error::weak_error, DefaultFloat, DefaultUnsigned, Error};
8
9pub(crate) const NODE_TAG: &str = "ND";
10
11/// Defines the ID and location for each node of the mesh.
12///
13/// Corresponds to the card `ND`.
14#[derive(Copy, Clone, Debug, PartialEq)]
15#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
16pub struct Node<U = DefaultUnsigned, F = DefaultFloat>
17where
18    U: Unsigned + Copy + fmt::Debug,
19    F: Float + fmt::Debug,
20    Error: From<U::FromStrRadixErr> + From<F::FromStrRadixErr>,
21{
22    /// The ID of the node.
23    pub id: U,
24    /// The x, y, and z coordinates of the point.
25    pub coordinate: [F; 3],
26}
27impl<U, F> FromStr for Node<U, F>
28where
29    U: Unsigned + Copy + fmt::Debug,
30    F: Float + fmt::Debug,
31    Error: From<U::FromStrRadixErr> + From<F::FromStrRadixErr>,
32{
33    type Err = Error;
34
35    fn from_str(s: &str) -> Result<Self, Self::Err> {
36        let mut field_it = s.split_whitespace();
37
38        match field_it.next() {
39            Some(NODE_TAG) => {} // tag matches, continue
40            Some(t) => Err(Error::WrongCardTag {
41                expect: NODE_TAG.into(),
42                actual: t.into(),
43            })?,
44            None => Err(Error::EmptyLine)?,
45        }
46
47        let id_raw = field_it.next().ok_or(Error::MissingValue)?;
48        let id = U::from_str_radix(id_raw, 10)?;
49
50        let mut coordinate = [F::zero(); 3];
51        for component in coordinate.iter_mut() {
52            let Some(c_raw) = field_it.next() else {
53                Err(Error::MissingValue)?
54            };
55            *component = F::from_str_radix(c_raw, 10)?;
56        }
57
58        if let Some(v) = field_it.next() {
59            weak_error(Error::ExtraneousValue(v.into()))?;
60        }
61
62        Ok(Self { id, coordinate })
63    }
64}