1#![doc = include_str!("../README.md")]
4#![no_std]
5
6#[cfg(feature = "alloc")]
7extern crate alloc;
8
9#[cfg(feature = "alloc")]
10mod alloc_;
11
12#[cfg(feature = "serde")]
13mod serde_;
14
15use core::{
16 borrow::Borrow,
17 fmt::{Display, Error as FmtError, Formatter, Result as FmtResult},
18 ops::Deref,
19 str::FromStr,
20};
21use ref_cast::{RefCastCustom, ref_cast_custom};
22use thiserror::Error as ThisError;
23
24#[cfg(feature = "serde")]
25use ::serde::{Deserialize, Serialize};
26
27const MIC_SIZE: usize = 4;
28
29const fn check_mic(bytes: &[u8]) -> Result<(), Error> {
30 if bytes.len() != MIC_SIZE {
31 return Err(Error::InvalidLength(bytes.len(), MIC_SIZE));
32 }
33
34 let mut i = 0;
35 while i < MIC_SIZE {
36 if !bytes[i].is_ascii_digit() && !bytes[i].is_ascii_uppercase() {
37 return Err(Error::InvalidCharacter(i));
38 }
39
40 i += 1;
41 }
42
43 Ok(())
44}
45
46#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd, ThisError)]
48#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
49pub enum Error {
50 #[error("Invalid length.")]
52 InvalidLength(usize, usize),
53 #[error("Invalid character at position {0}.")]
55 InvalidCharacter(usize),
56}
57
58#[derive(Debug, Eq, Hash, Ord, PartialEq, PartialOrd, RefCastCustom)]
60#[allow(non_camel_case_types)]
61#[repr(transparent)]
62pub struct mic([u8]);
63
64impl mic {
65 #[ref_cast_custom]
66 pub(crate) const fn from_bytes_unchecked(src: &[u8]) -> &Self;
67
68 pub const fn from_bytes(src: &[u8]) -> Result<&Self, Error> {
70 if let Err(e) = check_mic(src) {
71 Err(e)
72 } else {
73 Ok(Self::from_bytes_unchecked(src))
74 }
75 }
76
77 pub const fn from_str(src: &str) -> Result<&Self, Error> {
79 let bytes = src.as_bytes();
80
81 if let Err(e) = check_mic(bytes) {
82 Err(e)
83 } else {
84 Ok(Self::from_bytes_unchecked(bytes))
85 }
86 }
87
88 pub const fn as_bytes(&self) -> &[u8] {
90 &self.0
91 }
92
93 #[allow(unsafe_code)]
95 pub const fn as_str(&self) -> &str {
96 unsafe { str::from_utf8_unchecked(&self.0) }
98 }
99
100 pub const fn to_mic(&self) -> Mic {
102 Mic::from_bytes_unchecked(&self.0)
103 }
104}
105
106impl AsRef<[u8]> for mic {
107 fn as_ref(&self) -> &[u8] {
108 self.as_bytes()
109 }
110}
111
112impl AsRef<str> for mic {
113 fn as_ref(&self) -> &str {
114 self.as_str()
115 }
116}
117
118impl Display for mic {
119 fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
120 write!(f, "{}", str::from_utf8(&self.0).map_err(|_e| FmtError)?)
121 }
122}
123
124#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd, RefCastCustom)]
126#[cfg_attr(
127 feature = "zerocopy",
128 derive(zerocopy::Immutable, zerocopy::IntoBytes, zerocopy::KnownLayout)
129)]
130#[repr(transparent)]
131pub struct Mic([u8; MIC_SIZE]);
132
133impl Mic {
134 pub(crate) const fn from_byte_array_unchecked(bytes: [u8; MIC_SIZE]) -> Self {
135 Self(bytes)
136 }
137
138 pub(crate) const fn from_bytes_unchecked(src: &[u8]) -> Self {
139 let mut bytes = [0u8; MIC_SIZE];
140 let (value, _reject) = src.split_at(MIC_SIZE);
141 bytes.copy_from_slice(value);
142 Self::from_byte_array_unchecked(bytes)
143 }
144
145 pub const fn from_byte_array(bytes: [u8; MIC_SIZE]) -> Result<Self, Error> {
147 if let Err(e) = check_mic(&bytes) {
148 Err(e)
149 } else {
150 Ok(Self::from_byte_array_unchecked(bytes))
151 }
152 }
153
154 pub const fn from_bytes(src: &[u8]) -> Result<Self, Error> {
156 if let Err(e) = check_mic(src) {
157 Err(e)
158 } else {
159 Ok(Self::from_bytes_unchecked(src))
160 }
161 }
162
163 pub const fn from_str_slice(s: &str) -> Result<Self, Error> {
165 Self::from_bytes(s.as_bytes())
166 }
167
168 pub const fn as_bytes(&self) -> &[u8] {
170 &self.0
171 }
172
173 #[allow(unsafe_code)]
175 pub const fn as_str(&self) -> &str {
176 unsafe { str::from_utf8_unchecked(&self.0) }
179 }
180
181 pub const fn as_mic(&self) -> &mic {
183 mic::from_bytes_unchecked(&self.0)
184 }
185}
186
187impl AsRef<[u8]> for Mic {
188 fn as_ref(&self) -> &[u8] {
189 self.as_bytes()
190 }
191}
192
193impl AsRef<str> for Mic {
194 fn as_ref(&self) -> &str {
195 self.as_str()
196 }
197}
198
199impl Deref for Mic {
200 type Target = mic;
201
202 fn deref(&self) -> &Self::Target {
203 mic::from_bytes_unchecked(&self.0)
204 }
205}
206
207impl Borrow<mic> for Mic {
208 fn borrow(&self) -> &mic {
209 mic::from_bytes_unchecked(&self.0)
210 }
211}
212
213impl Display for Mic {
214 fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
215 write!(f, "{}", str::from_utf8(&self.0).map_err(|_e| FmtError)?)
216 }
217}
218
219impl FromStr for Mic {
220 type Err = Error;
221
222 fn from_str(s: &str) -> Result<Self, Self::Err> {
223 Self::from_str_slice(s)
224 }
225}
226
227#[derive(Copy, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
229#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
230pub enum Kind {
231 #[cfg_attr(feature = "serde", serde(alias = "OPRT"))]
233 Operating,
234 #[cfg_attr(feature = "serde", serde(alias = "SGMT"))]
236 Segment,
237}
238
239#[derive(Copy, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
241#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
242pub enum Category {
243 #[cfg_attr(feature = "serde", serde(alias = "ATSS"))]
245 AlternativeTradingSystem,
246
247 #[cfg_attr(feature = "serde", serde(alias = "APPA"))]
249 ApprovedPublicationArrangement,
250
251 #[cfg_attr(feature = "serde", serde(alias = "ARMS"))]
253 ApprovedReportingMechanism,
254
255 #[cfg_attr(feature = "serde", serde(alias = "CTPS"))]
257 ConsolidatedTapeProvider,
258
259 #[cfg_attr(feature = "serde", serde(alias = "CASP"))]
261 CryptoAssetServicesProvider,
262
263 #[cfg_attr(feature = "serde", serde(alias = "DCMS"))]
265 DesignatedContractMarket,
266
267 #[cfg_attr(feature = "serde", serde(alias = "IDQS"))]
269 InterDealerQuotationSystem,
270
271 #[cfg_attr(feature = "serde", serde(alias = "MLTF"))]
273 MultilateralTradingFacility,
274
275 #[cfg_attr(feature = "serde", serde(alias = "NSPD"))]
277 NotSpecified,
278
279 #[cfg_attr(feature = "serde", serde(alias = "OTFS"))]
281 OrganisedTradingFacility,
282
283 #[cfg_attr(feature = "serde", serde(alias = "OTHR"))]
285 Other,
286
287 #[cfg_attr(feature = "serde", serde(alias = "RMOS"))]
289 RecognisedMarketOperator,
290
291 #[cfg_attr(feature = "serde", serde(alias = "RMKT"))]
293 RegulatedMarket,
294
295 #[cfg_attr(feature = "serde", serde(alias = "SEFS"))]
297 SwapExecutionFacility,
298
299 #[cfg_attr(feature = "serde", serde(alias = "SINT"))]
301 SystematicInternaliser,
302
303 #[cfg_attr(feature = "serde", serde(alias = "TRFS"))]
305 TradeReportingFacility,
306}
307
308#[derive(Copy, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
310#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
311pub enum Status {
312 #[cfg_attr(feature = "serde", serde(alias = "ACTIVE"))]
314 Active,
315
316 #[cfg_attr(feature = "serde", serde(alias = "UPDATED"))]
318 Updated,
319
320 #[cfg_attr(feature = "serde", serde(alias = "EXPIRED"))]
322 Expired,
323}