1use std::{
2 cmp::Ordering,
3 fmt::{Debug, Display, Formatter, Result as FmtResult},
4 str::FromStr,
5};
6
7use crate::error::AcronymParseError;
8
9#[derive(Copy, Clone, PartialEq, Eq, Hash)]
13#[repr(transparent)]
14#[cfg_attr(
15 feature = "rkyv",
16 derive(rkyv::bytecheck::CheckBytes),
17 bytecheck(crate = rkyv::bytecheck),
18)]
19pub struct Acronym([u8; 3]);
20
21impl Acronym {
22 pub const unsafe fn from_str_unchecked(s: &str) -> Self {
43 let array = if s.len() == 2 {
44 let [a, b] = unsafe { *(s.as_ptr().cast::<[u8; 2]>()) };
46
47 [0, a, b]
48 } else {
49 unsafe { *s.as_ptr().cast::<[u8; 3]>() }
51 };
52
53 Self(array)
54 }
55
56 pub fn as_str(&self) -> &str {
66 let start_idx = usize::from(self.0[0] == 0);
67
68 unsafe { std::str::from_utf8_unchecked(&self.0[start_idx..]) }
70 }
71}
72
73impl Debug for Acronym {
74 fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
75 Debug::fmt(self.as_str(), f)
76 }
77}
78
79impl Display for Acronym {
80 fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
81 f.write_str(self.as_str())
82 }
83}
84
85impl FromStr for Acronym {
86 type Err = AcronymParseError;
87
88 fn from_str(s: &str) -> Result<Self, Self::Err> {
92 match <[u8; 2]>::try_from(s.as_bytes()) {
93 Ok([a, b]) => Ok(Self([0, a.to_ascii_uppercase(), b.to_ascii_uppercase()])),
94 Err(_) => s
95 .as_bytes()
96 .try_into()
97 .map(|mut array: [u8; 3]| {
98 array.make_ascii_uppercase();
99
100 Self(array)
101 })
102 .map_err(|_| AcronymParseError {
103 acronym: Box::from(s),
104 }),
105 }
106 }
107}
108
109impl PartialOrd for Acronym {
110 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
111 Some(self.cmp(other))
112 }
113}
114
115impl Ord for Acronym {
116 fn cmp(&self, other: &Self) -> Ordering {
117 self.as_str().cmp(other.as_str())
118 }
119}
120
121#[cfg(feature = "serde")]
122#[cfg_attr(all(docsrs, not(doctest)), doc(cfg(feature = "serde")))]
123const _: () = {
124 use serde::{
125 de::{Deserialize, Deserializer, Error as DeError, Visitor},
126 ser::{Serialize, Serializer},
127 };
128
129 impl<'de> Deserialize<'de> for Acronym {
130 fn deserialize<D: Deserializer<'de>>(d: D) -> Result<Self, D::Error> {
131 struct AcronymVisitor;
132
133 impl Visitor<'_> for AcronymVisitor {
134 type Value = Acronym;
135
136 fn expecting(&self, f: &mut Formatter<'_>) -> FmtResult {
137 f.write_str("string")
138 }
139
140 fn visit_str<E: DeError>(self, v: &str) -> Result<Self::Value, E> {
141 v.parse().map_err(DeError::custom)
142 }
143
144 fn visit_string<E: DeError>(self, v: String) -> Result<Self::Value, E> {
145 self.visit_str(&v)
146 }
147 }
148
149 d.deserialize_str(AcronymVisitor)
150 }
151 }
152
153 impl Serialize for Acronym {
154 fn serialize<S: Serializer>(&self, s: S) -> Result<S::Ok, S::Error> {
155 s.serialize_str(self.as_str())
156 }
157 }
158};
159
160#[cfg(feature = "rkyv")]
161#[cfg_attr(all(docsrs, not(doctest)), doc(cfg(feature = "rkyv")))]
162const _: () = {
163 use rkyv::{
164 munge::munge, rancor::Fallible, traits::NoUndef, Archive, Deserialize, Place, Portable,
165 Serialize,
166 };
167
168 unsafe impl Portable for Acronym {}
169
170 unsafe impl NoUndef for Acronym {}
171
172 impl Archive for Acronym {
173 type Archived = Self;
174 type Resolver = ();
175
176 fn resolve(&self, (): Self::Resolver, out: Place<Self::Archived>) {
177 munge!(let Self(out) = out);
178 self.0.resolve([(); 3], out);
179 }
180 }
181
182 impl<S: Fallible + ?Sized> Serialize<S> for Acronym {
183 fn serialize(&self, s: &mut S) -> Result<(), S::Error> {
184 self.0.serialize(s).map(|_| ())
185 }
186 }
187
188 impl<D: Fallible + ?Sized> Deserialize<Self, D> for Acronym {
189 fn deserialize(&self, _: &mut D) -> Result<Self, D::Error> {
190 Ok(*self)
191 }
192 }
193};