1use std::{fmt, str::FromStr};
2
3use num_traits::Unsigned;
4use paste::paste;
5#[cfg(feature = "serde")]
6use serde::{Deserialize, Serialize};
7
8use crate::{error::weak_error, DefaultUnsigned, Error};
9
10macro_rules! mk_el {
12 ($(#[$attr:meta])* $name: ident, $n: literal) => {
13 paste! {
14 pub(crate) const [<$name _TAG>]: &str = stringify!($name);
15 }
16
17 $(#[$attr])*
18 #[derive(Copy, Clone, Debug, PartialEq)]
19 #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
20 pub struct $name<U = DefaultUnsigned>
21 where
22 U: Unsigned + Copy + fmt::Debug,
23 Error: From<U::FromStrRadixErr>,
24 {
25 pub id: U,
27 pub nodes: [U; $n],
29 pub material: U,
31 }
32 impl<U> FromStr for $name<U>
33 where
34 U: Unsigned + Copy + fmt::Debug,
35 Error: From<U::FromStrRadixErr>,
36 {
37 type Err = Error;
38 fn from_str(s: &str) -> Result<Self, Self::Err> {
39 let mut field_it = s.split_whitespace();
40
41 paste! {
42 const TAG: &str = [<$name _TAG>];
43 }
44 match field_it.next() {
45 Some(TAG) => {} Some(t) => Err(Error::WrongCardTag { expect: TAG.into(), actual: t.into() })?,
47 None => Err(Error::EmptyLine)?,
48 }
49
50 let id_raw = field_it.next().ok_or(Error::MissingValue)?;
51 let id = U::from_str_radix(id_raw, 10)?;
52
53 let mut nodes = [U::zero(); $n];
54 for node in nodes.iter_mut() {
55 let Some(node_raw) = field_it.next() else {
56 Err(Error::MissingValue)?
57 };
58 *node = U::from_str_radix(node_raw, 10)?;
59 }
60
61 let mat_raw = field_it.next().ok_or(Error::MissingValue)?;
62 let material = U::from_str_radix(mat_raw, 10)?;
63
64 if let Some(v) = field_it.next() {
65 weak_error(Error::ExtraneousValue(v.into()))?;
66 }
67
68 Ok(Self{ id, nodes, material })
69 }
70 }
71 };
72}
73
74mk_el! {
75 E2L, 2
77}
78mk_el! {
79 E3L, 3
81}
82mk_el! {
83 E3T, 3
85}
86mk_el! {
87 E6T, 6
89}
90mk_el! {
91 E4Q, 4
93}
94mk_el! {
95 E8Q, 8
97}
98mk_el! {
99 E9Q, 9
101}