neodes_codec/line/id/
block_id.rs

1use crate::line::id::short_block_id::{ShortBlockId, ShortBlockIdParsingError};
2use crate::line::id::short_group_id::{ShortGroupId, ShortGroupIdParsingError};
3use crate::line::id::short_struc_id::{ShortStrucId, ShortStrucIdParsingError};
4use serde_with::{DeserializeFromStr, SerializeDisplay};
5use std::error::Error;
6use std::fmt::{Display, Formatter};
7use std::str::FromStr;
8
9/// Structure representing the three first parts of a field ID
10/// i.e. the `S21.G00.42` in `S21.G00.42.001`
11#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug, DeserializeFromStr, SerializeDisplay)]
12pub struct BlockId {
13	short_struc_id: ShortStrucId,
14	short_group_id: ShortGroupId,
15	short_block_id: ShortBlockId,
16}
17
18impl BlockId {
19	/// Creates a BlockId from numbers. Truncates the decimals to the last 2
20	#[inline]
21	pub const fn new(
22		short_struc_id: ShortStrucId,
23		short_group_id: ShortGroupId,
24		short_block_id: ShortBlockId,
25	) -> BlockId {
26		BlockId {
27			short_struc_id,
28			short_group_id,
29			short_block_id,
30		}
31	}
32
33	/// Short Structure ID
34	///
35	/// # Examples
36	///
37	/// ```
38	/// # use std::error::Error;
39	/// # fn main() -> Result<(), Box<dyn Error>> {
40	/// use neodes_codec::line::{BlockId, ShortStrucId};
41	/// use std::str::FromStr;
42	///
43	/// let block_id = BlockId::from_str("S21.G00.00")?;
44	/// assert_eq!(block_id.short_struc_id(), ShortStrucId::from_u8_lossy(21));
45	///
46	/// # Ok(())
47	/// # }
48	/// ```
49	#[inline]
50	pub fn short_struc_id(&self) -> ShortStrucId {
51		self.short_struc_id
52	}
53
54	/// # Examples
55	///
56	/// ```
57	/// # use std::error::Error;
58	/// # fn main() -> Result<(), Box<dyn Error>> {
59	/// use neodes_codec::line::{BlockId, ShortGroupId };
60	/// use std::str::FromStr;
61	///
62	/// let block_id = BlockId::from_str("S21.G01.13")?;
63	/// assert_eq!(block_id.short_group_id(), ShortGroupId::from_u8_lossy(1));
64	///
65	/// # Ok(())
66	/// # }
67	/// ```
68	#[inline]
69	pub fn short_group_id(&self) -> ShortGroupId {
70		self.short_group_id
71	}
72
73	/// Short Structure ID
74	/// ```
75	/// # use std::error::Error;
76	/// # fn main() -> Result<(), Box<dyn Error>> {
77	/// use neodes_codec::line::{BlockId, ShortBlockId};
78	/// use std::str::FromStr;
79	///
80	/// let block_id = BlockId::from_str("S21.G00.13")?;
81	/// assert_eq!(block_id.short_block_id(), ShortBlockId::from_u8_lossy(13));
82	///
83	/// # Ok(())
84	/// # }
85	/// ```
86	#[inline]
87	pub fn short_block_id(&self) -> ShortBlockId {
88		self.short_block_id
89	}
90}
91
92impl Display for BlockId {
93	#[inline]
94	fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
95		f.write_fmt(format_args!(
96			"{}.{}.{}",
97			self.short_struc_id, self.short_group_id, self.short_block_id
98		))
99	}
100}
101
102impl FromStr for BlockId {
103	type Err = BlockIdParseError;
104
105	/// ```
106	/// # use std::error::Error;
107	/// # fn main() -> Result<(), Box<dyn Error>> {
108	/// use neodes_codec::line::{BlockId, BlockIdParseError, ShortBlockId, ShortFieldId, ShortGroupId, ShortStrucId};
109	/// use std::str::FromStr;
110	///
111	/// assert_eq!(
112	///     BlockId::from_str("S21.G00.01"),
113	///     Ok(BlockId::new(
114	///         ShortStrucId::from_u8_lossy(21),
115	///         ShortGroupId::from_u8_lossy(0),
116	///         ShortBlockId::from_u8_lossy(1))
117	///     )
118	/// );
119	/// assert_eq!(BlockId::from_str("S21.G00"), Err(BlockIdParseError::Format));
120	///
121	/// # Ok(())
122	/// # }
123	/// ```
124	#[inline]
125	fn from_str(s: &str) -> Result<Self, Self::Err> {
126		let mut split_n = s.splitn(3, '.');
127
128		let next_split = split_n.next().ok_or(BlockIdParseError::Format)?;
129		let short_struc_id = ShortStrucId::from_str(next_split)?;
130
131		let next_split = split_n.next().ok_or(BlockIdParseError::Format)?;
132		let short_group_id = ShortGroupId::from_str(next_split)?;
133
134		let next_split = split_n.next().ok_or(BlockIdParseError::Format)?;
135		let short_block_id = ShortBlockId::from_str(next_split)?;
136
137		Ok(BlockId {
138			short_struc_id,
139			short_group_id,
140			short_block_id,
141		})
142	}
143}
144
145/// Parsing error returned when parsing of `BlockId` from a string failed.
146#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
147pub enum BlockIdParseError {
148	/// Field id was badly formed (missing dots)
149	Format,
150
151	/// Structure id was unreadable
152	Structure,
153
154	/// Group id was unreadable
155	Group,
156
157	/// Block id was unreadable
158	Block,
159}
160
161impl Error for BlockIdParseError {}
162
163impl From<ShortStrucIdParsingError> for BlockIdParseError {
164	#[inline]
165	fn from(_: ShortStrucIdParsingError) -> Self {
166		BlockIdParseError::Structure
167	}
168}
169
170impl From<ShortGroupIdParsingError> for BlockIdParseError {
171	#[inline]
172	fn from(_: ShortGroupIdParsingError) -> Self {
173		BlockIdParseError::Group
174	}
175}
176
177impl From<ShortBlockIdParsingError> for BlockIdParseError {
178	#[inline]
179	fn from(_: ShortBlockIdParsingError) -> Self {
180		BlockIdParseError::Block
181	}
182}
183
184impl Display for BlockIdParseError {
185	#[inline]
186	fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
187		match self {
188			BlockIdParseError::Format => {
189				write!(f, "Wrong Field ID format")
190			}
191			BlockIdParseError::Structure => {
192				write!(f, "Cannot parse structure ID")
193			}
194			BlockIdParseError::Group => {
195				write!(f, "Cannot parse group ID")
196			}
197			BlockIdParseError::Block => {
198				write!(f, "Cannot parse block ID")
199			}
200		}
201	}
202}
203
204#[cfg(test)]
205mod tests {
206	use crate::line::{BlockId, ShortBlockId, ShortGroupId, ShortStrucId};
207	use parameterized::parameterized;
208	use std::str::FromStr;
209
210	#[parameterized(input = {
211			"S215G00.00",
212			"S21.G00|00",
213			"S2X.G00.00",
214			"S21.G0X.00",
215			"S21.G00.0X",
216			"S21.G00.00.",
217			"S21.G00.00.001"
218		})]
219	fn returns_parsing_errors(input: &str) {
220		assert!(BlockId::from_str(input).is_err());
221	}
222
223	#[test]
224	fn can_parse_string() {
225		assert_eq!(
226			BlockId::from_str("S21.G00.00"),
227			Ok(BlockId {
228				short_struc_id: ShortStrucId::from_u8_lossy(21),
229				short_group_id: ShortGroupId::from_u8_lossy(0),
230				short_block_id: ShortBlockId::from_u8_lossy(0),
231			})
232		);
233	}
234}