sms_2dm/
element.rs

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
10/// Convenience macro for defining an element.
11macro_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            /// The ID of the element.
26            pub id: U,
27            /// The IDs of nodes in the element.
28            pub nodes: [U; $n],
29            /// The ID of the material assigned to the element.
30            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) => {} // tag matches, continue
46                    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    /// Identifies a 2-noded linear element.
76    E2L, 2
77}
78mk_el! {
79    /// Identifies a 3-noded linear element.
80    E3L, 3
81}
82mk_el! {
83    /// Identifies a 3-noded triangular element.
84    E3T, 3
85}
86mk_el! {
87    /// Identifies a 6-noded triangular element.
88    E6T, 6
89}
90mk_el! {
91    /// Identifies a 4-noded quadrilateral element.
92    E4Q, 4
93}
94mk_el! {
95    /// Identifies a 8-noded quadrilateral element.
96    E8Q, 8
97}
98mk_el! {
99    /// Identifies a 9-noded quadrilateral element.
100    E9Q, 9
101}