1use core::fmt;
4
5#[derive(Debug, Clone, Copy, PartialEq, Eq)]
16#[non_exhaustive]
17pub enum MessageType {
18 Nil,
19 Dataspace,
20 LinkInfo,
21 Datatype,
22 FillValueOld,
23 FillValue,
24 Link,
25 ExternalDataFiles,
30 DataLayout,
31 GroupInfo,
32 FilterPipeline,
33 Attribute,
34 ObjectHeaderContinuation,
35 SymbolTable,
36 ObjectModificationTime,
37 BTreeKValues,
38 SharedMessageTable,
39 AttributeInfo,
40 ObjectReferenceCount,
41 FileSpaceInfo,
42 Unknown(u16),
44}
45
46impl MessageType {
47 pub fn from_u16(val: u16) -> MessageType {
49 match val {
50 0x0000 => MessageType::Nil,
51 0x0001 => MessageType::Dataspace,
52 0x0002 => MessageType::LinkInfo,
53 0x0003 => MessageType::Datatype,
54 0x0004 => MessageType::FillValueOld,
55 0x0005 => MessageType::FillValue,
56 0x0006 => MessageType::Link,
57 0x0007 => MessageType::ExternalDataFiles,
58 0x0008 => MessageType::DataLayout,
59 0x000A => MessageType::GroupInfo,
60 0x000B => MessageType::FilterPipeline,
61 0x000C => MessageType::Attribute,
62 0x000F => MessageType::SharedMessageTable,
63 0x0010 => MessageType::ObjectHeaderContinuation,
64 0x0011 => MessageType::SymbolTable,
65 0x0012 => MessageType::ObjectModificationTime,
66 0x0013 => MessageType::BTreeKValues,
67 0x0015 => MessageType::AttributeInfo,
68 0x0016 => MessageType::ObjectReferenceCount,
69 0x0017 => MessageType::FileSpaceInfo,
70 other => MessageType::Unknown(other),
71 }
72 }
73
74 pub fn to_u16(self) -> u16 {
76 match self {
77 MessageType::Nil => 0x0000,
78 MessageType::Dataspace => 0x0001,
79 MessageType::LinkInfo => 0x0002,
80 MessageType::Datatype => 0x0003,
81 MessageType::FillValueOld => 0x0004,
82 MessageType::FillValue => 0x0005,
83 MessageType::Link => 0x0006,
84 MessageType::ExternalDataFiles => 0x0007,
85 MessageType::DataLayout => 0x0008,
86 MessageType::GroupInfo => 0x000A,
87 MessageType::FilterPipeline => 0x000B,
88 MessageType::Attribute => 0x000C,
89 MessageType::SharedMessageTable => 0x000F,
90 MessageType::ObjectHeaderContinuation => 0x0010,
91 MessageType::SymbolTable => 0x0011,
92 MessageType::ObjectModificationTime => 0x0012,
93 MessageType::BTreeKValues => 0x0013,
94 MessageType::AttributeInfo => 0x0015,
95 MessageType::ObjectReferenceCount => 0x0016,
96 MessageType::FileSpaceInfo => 0x0017,
97 MessageType::Unknown(v) => v,
98 }
99 }
100}
101
102impl fmt::Display for MessageType {
103 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
105 let name = match self {
106 Self::Nil => "NIL",
107 Self::Dataspace => "dataspace",
108 Self::LinkInfo => "link info",
109 Self::Datatype => "datatype",
110 Self::FillValueOld => "fill value (old)",
111 Self::FillValue => "fill value",
112 Self::Link => "link",
113 Self::ExternalDataFiles => "external data files",
114 Self::DataLayout => "data layout",
115 Self::GroupInfo => "group info",
116 Self::FilterPipeline => "filter pipeline",
117 Self::Attribute => "attribute",
118 Self::ObjectHeaderContinuation => "object header continuation",
119 Self::SymbolTable => "symbol table",
120 Self::ObjectModificationTime => "object modification time",
121 Self::BTreeKValues => "B-tree K values",
122 Self::SharedMessageTable => "shared message table",
123 Self::AttributeInfo => "attribute info",
124 Self::ObjectReferenceCount => "object reference count",
125 Self::FileSpaceInfo => "file space info",
126 Self::Unknown(id) => return write!(f, "unknown message 0x{id:04x}"),
127 };
128 f.write_str(name)
132 }
133}
134
135#[cfg(test)]
136mod tests {
137 use super::*;
138
139 #[test]
140 fn known_types_roundtrip() {
141 let known = [
142 (0x0000, MessageType::Nil),
143 (0x0001, MessageType::Dataspace),
144 (0x0002, MessageType::LinkInfo),
145 (0x0003, MessageType::Datatype),
146 (0x0004, MessageType::FillValueOld),
147 (0x0005, MessageType::FillValue),
148 (0x0006, MessageType::Link),
149 (0x0007, MessageType::ExternalDataFiles),
150 (0x0008, MessageType::DataLayout),
151 (0x000A, MessageType::GroupInfo),
152 (0x000B, MessageType::FilterPipeline),
153 (0x000C, MessageType::Attribute),
154 (0x000F, MessageType::SharedMessageTable),
155 (0x0010, MessageType::ObjectHeaderContinuation),
156 (0x0011, MessageType::SymbolTable),
157 (0x0012, MessageType::ObjectModificationTime),
158 (0x0013, MessageType::BTreeKValues),
159 (0x0015, MessageType::AttributeInfo),
160 (0x0016, MessageType::ObjectReferenceCount),
161 (0x0017, MessageType::FileSpaceInfo),
162 ];
163 for (val, expected) in &known {
164 let mt = MessageType::from_u16(*val);
165 assert_eq!(mt, *expected);
166 assert_eq!(mt.to_u16(), *val);
167 }
168 }
169
170 #[test]
171 fn unknown_type() {
172 let mt = MessageType::from_u16(0x00FF);
173 assert_eq!(mt, MessageType::Unknown(0x00FF));
174 assert_eq!(mt.to_u16(), 0x00FF);
175 }
176
177 #[test]
191 fn the_specifications_testing_only_type_stays_unknown() {
192 let mt = MessageType::from_u16(0x0009);
193 assert_eq!(mt, MessageType::Unknown(0x0009));
194 }
195
196 #[test]
197 fn external_data_files_is_a_named_type() {
198 let mt = MessageType::from_u16(0x0007);
199 assert_eq!(mt, MessageType::ExternalDataFiles);
200 assert_eq!(mt.to_u16(), 0x0007);
201 }
202}
203
204#[cfg(all(test, feature = "std"))]
205mod display_tests {
206 use super::*;
207
208 #[test]
211 fn known_messages_read_as_prose() {
212 assert_eq!(MessageType::Dataspace.to_string(), "dataspace");
213 assert_eq!(MessageType::LinkInfo.to_string(), "link info");
214 assert_eq!(
215 MessageType::ObjectHeaderContinuation.to_string(),
216 "object header continuation"
217 );
218 }
219
220 #[test]
221 fn an_unknown_message_reports_its_raw_identifier() {
222 assert_eq!(
223 MessageType::Unknown(0x00ff).to_string(),
224 "unknown message 0x00ff"
225 );
226 }
227
228 #[test]
231 fn every_known_message_has_a_name() {
232 for raw in 0x0000..=0x0017u16 {
233 let message = MessageType::from_u16(raw);
234 if message == MessageType::Unknown(raw) {
235 continue;
236 }
237 let shown = message.to_string();
238 assert!(!shown.starts_with("unknown message"), "{raw:#06x}: {shown}");
239 }
240 }
241}