#![doc = include_str!("../README.md")]
#![no_std]
#[cfg(feature = "alloc")]
extern crate alloc;
#[cfg(feature = "alloc")]
mod alloc_;
#[cfg(feature = "serde")]
mod serde_;
use core::{
borrow::Borrow,
fmt::{Display, Error as FmtError, Formatter, Result as FmtResult},
ops::Deref,
str::FromStr,
};
use ref_cast::{RefCastCustom, ref_cast_custom};
use thiserror::Error as ThisError;
#[cfg(feature = "serde")]
use ::serde::{Deserialize, Serialize};
const MIC_SIZE: usize = 4;
const fn check_mic(bytes: &[u8]) -> Result<(), Error> {
if bytes.len() != MIC_SIZE {
return Err(Error::InvalidLength(bytes.len(), MIC_SIZE));
}
let mut i = 0;
while i < MIC_SIZE {
if !bytes[i].is_ascii_digit() && !bytes[i].is_ascii_uppercase() {
return Err(Error::InvalidCharacter(i));
}
i += 1;
}
Ok(())
}
#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd, ThisError)]
#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
pub enum Error {
#[error("Invalid length.")]
InvalidLength(usize, usize),
#[error("Invalid character at position {0}.")]
InvalidCharacter(usize),
}
#[derive(Debug, Eq, Hash, Ord, PartialEq, PartialOrd, RefCastCustom)]
#[allow(non_camel_case_types)]
#[repr(transparent)]
pub struct mic([u8]);
impl mic {
#[ref_cast_custom]
pub(crate) const fn from_bytes_unchecked(src: &[u8]) -> &Self;
pub const fn from_bytes(src: &[u8]) -> Result<&Self, Error> {
if let Err(e) = check_mic(src) {
Err(e)
} else {
Ok(Self::from_bytes_unchecked(src))
}
}
pub const fn from_str(src: &str) -> Result<&Self, Error> {
let bytes = src.as_bytes();
if let Err(e) = check_mic(bytes) {
Err(e)
} else {
Ok(Self::from_bytes_unchecked(bytes))
}
}
pub const fn as_bytes(&self) -> &[u8] {
&self.0
}
#[allow(unsafe_code)]
pub const fn as_str(&self) -> &str {
unsafe { str::from_utf8_unchecked(&self.0) }
}
pub const fn to_mic(&self) -> Mic {
Mic::from_bytes_unchecked(&self.0)
}
}
impl AsRef<[u8]> for mic {
fn as_ref(&self) -> &[u8] {
self.as_bytes()
}
}
impl AsRef<str> for mic {
fn as_ref(&self) -> &str {
self.as_str()
}
}
impl Display for mic {
fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
write!(f, "{}", str::from_utf8(&self.0).map_err(|_e| FmtError)?)
}
}
#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd, RefCastCustom)]
#[cfg_attr(
feature = "zerocopy",
derive(zerocopy::Immutable, zerocopy::IntoBytes, zerocopy::KnownLayout)
)]
#[repr(transparent)]
pub struct Mic([u8; MIC_SIZE]);
impl Mic {
pub(crate) const fn from_byte_array_unchecked(bytes: [u8; MIC_SIZE]) -> Self {
Self(bytes)
}
pub(crate) const fn from_bytes_unchecked(src: &[u8]) -> Self {
let mut bytes = [0u8; MIC_SIZE];
let (value, _reject) = src.split_at(MIC_SIZE);
bytes.copy_from_slice(value);
Self::from_byte_array_unchecked(bytes)
}
pub const fn from_byte_array(bytes: [u8; MIC_SIZE]) -> Result<Self, Error> {
if let Err(e) = check_mic(&bytes) {
Err(e)
} else {
Ok(Self::from_byte_array_unchecked(bytes))
}
}
pub const fn from_bytes(src: &[u8]) -> Result<Self, Error> {
if let Err(e) = check_mic(src) {
Err(e)
} else {
Ok(Self::from_bytes_unchecked(src))
}
}
pub const fn from_str_slice(s: &str) -> Result<Self, Error> {
Self::from_bytes(s.as_bytes())
}
pub const fn as_bytes(&self) -> &[u8] {
&self.0
}
#[allow(unsafe_code)]
pub const fn as_str(&self) -> &str {
unsafe { str::from_utf8_unchecked(&self.0) }
}
pub const fn as_mic(&self) -> &mic {
mic::from_bytes_unchecked(&self.0)
}
}
impl AsRef<[u8]> for Mic {
fn as_ref(&self) -> &[u8] {
self.as_bytes()
}
}
impl AsRef<str> for Mic {
fn as_ref(&self) -> &str {
self.as_str()
}
}
impl Deref for Mic {
type Target = mic;
fn deref(&self) -> &Self::Target {
mic::from_bytes_unchecked(&self.0)
}
}
impl Borrow<mic> for Mic {
fn borrow(&self) -> &mic {
mic::from_bytes_unchecked(&self.0)
}
}
impl Display for Mic {
fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
write!(f, "{}", str::from_utf8(&self.0).map_err(|_e| FmtError)?)
}
}
impl FromStr for Mic {
type Err = Error;
fn from_str(s: &str) -> Result<Self, Self::Err> {
Self::from_str_slice(s)
}
}
#[derive(Copy, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
pub enum Kind {
#[cfg_attr(feature = "serde", serde(alias = "OPRT"))]
Operating,
#[cfg_attr(feature = "serde", serde(alias = "SGMT"))]
Segment,
}
#[derive(Copy, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
pub enum Category {
#[cfg_attr(feature = "serde", serde(alias = "ATSS"))]
AlternativeTradingSystem,
#[cfg_attr(feature = "serde", serde(alias = "APPA"))]
ApprovedPublicationArrangement,
#[cfg_attr(feature = "serde", serde(alias = "ARMS"))]
ApprovedReportingMechanism,
#[cfg_attr(feature = "serde", serde(alias = "CTPS"))]
ConsolidatedTapeProvider,
#[cfg_attr(feature = "serde", serde(alias = "CASP"))]
CryptoAssetServicesProvider,
#[cfg_attr(feature = "serde", serde(alias = "DCMS"))]
DesignatedContractMarket,
#[cfg_attr(feature = "serde", serde(alias = "IDQS"))]
InterDealerQuotationSystem,
#[cfg_attr(feature = "serde", serde(alias = "MLTF"))]
MultilateralTradingFacility,
#[cfg_attr(feature = "serde", serde(alias = "NSPD"))]
NotSpecified,
#[cfg_attr(feature = "serde", serde(alias = "OTFS"))]
OrganisedTradingFacility,
#[cfg_attr(feature = "serde", serde(alias = "OTHR"))]
Other,
#[cfg_attr(feature = "serde", serde(alias = "RMOS"))]
RecognisedMarketOperator,
#[cfg_attr(feature = "serde", serde(alias = "RMKT"))]
RegulatedMarket,
#[cfg_attr(feature = "serde", serde(alias = "SEFS"))]
SwapExecutionFacility,
#[cfg_attr(feature = "serde", serde(alias = "SINT"))]
SystematicInternaliser,
#[cfg_attr(feature = "serde", serde(alias = "TRFS"))]
TradeReportingFacility,
}
#[derive(Copy, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
pub enum Status {
#[cfg_attr(feature = "serde", serde(alias = "ACTIVE"))]
Active,
#[cfg_attr(feature = "serde", serde(alias = "UPDATED"))]
Updated,
#[cfg_attr(feature = "serde", serde(alias = "EXPIRED"))]
Expired,
}