1#![warn(missing_docs)]
33
34pub mod error;
36pub mod serde_helpers;
38
39#[cfg(feature = "dataframe")]
40pub mod dataframe {
42 pub use paft_utils::dataframe::*;
43}
44
45#[doc(hidden)]
48#[macro_export]
49macro_rules! __string_enum_base {
50 (
51 $Type:ident, $enum_name:literal, error, {
52 $( $alias:literal => $variant:path ),+ $(,)?
53 }
54 ) => {
55 impl paft_utils::StringCode for $Type {
56 fn code(&self) -> &str { $Type::code(self) }
57 }
58
59 impl ::serde::Serialize for $Type {
60 fn serialize<S>(&self, serializer: S) -> ::std::result::Result<S::Ok, S::Error>
61 where
62 S: ::serde::Serializer,
63 {
64 serializer.serialize_str(self.code())
65 }
66 }
67
68 impl<'de> ::serde::Deserialize<'de> for $Type {
69 fn deserialize<D>(deserializer: D) -> ::std::result::Result<Self, D::Error>
70 where
71 D: ::serde::Deserializer<'de>,
72 {
73 let raw = <String as ::serde::Deserialize>::deserialize(deserializer)?;
74 Self::from_str(&raw).map_err(::serde::de::Error::custom)
75 }
76 }
77
78 impl ::std::str::FromStr for $Type {
79 type Err = $crate::error::PaftError;
80
81 fn from_str(input: &str) -> ::std::result::Result<Self, Self::Err> {
82 let trimmed = input.trim();
83 if trimmed.is_empty() {
84 return Err($crate::error::PaftError::InvalidEnumValue {
85 enum_name: $enum_name,
86 value: input.to_string(),
87 });
88 }
89 let token = paft_utils::canonicalize(trimmed);
90 let parsed = match token.as_ref() {
91 $( $alias => $variant, )*
92 _ => {
93 return Err($crate::error::PaftError::InvalidEnumValue {
94 enum_name: $enum_name,
95 value: input.to_string(),
96 });
97 }
98 };
99 Ok(parsed)
100 }
101 }
102
103 impl ::std::convert::TryFrom<String> for $Type {
104 type Error = $crate::error::PaftError;
105
106 fn try_from(value: String) -> ::std::result::Result<Self, Self::Error> {
107 Self::from_str(&value)
108 }
109 }
110
111 impl ::std::convert::From<$Type> for String {
112 fn from(v: $Type) -> Self { v.code().to_string() }
113 }
114
115 impl $Type {
116 #[doc(hidden)]
117 pub const __ALIASES: &'static [(&'static str, $Type)] = &[
118 $( ($alias, $variant) ),*
119 ];
120 }
121 };
122
123 (
124 $Type:ident, $enum_name:literal, other($OtherVariant:path), {
125 $( $alias:literal => $variant:path ),+ $(,)?
126 }
127 ) => {
128 impl paft_utils::StringCode for $Type {
129 fn code(&self) -> &str { $Type::code(self) }
130 fn is_canonical(&self) -> bool { $Type::is_canonical(self) }
131 }
132
133 impl $Type {
134 #[must_use]
136 pub const fn is_canonical(&self) -> bool { !matches!(self, $OtherVariant(_)) }
137 }
138
139 impl ::serde::Serialize for $Type {
140 fn serialize<S>(&self, serializer: S) -> ::std::result::Result<S::Ok, S::Error>
141 where
142 S: ::serde::Serializer,
143 {
144 serializer.serialize_str(self.code())
145 }
146 }
147
148 impl<'de> ::serde::Deserialize<'de> for $Type {
149 fn deserialize<D>(deserializer: D) -> ::std::result::Result<Self, D::Error>
150 where
151 D: ::serde::Deserializer<'de>,
152 {
153 let raw = <String as ::serde::Deserialize>::deserialize(deserializer)?;
154 Self::from_str(&raw).map_err(::serde::de::Error::custom)
155 }
156 }
157
158 impl ::std::str::FromStr for $Type {
159 type Err = $crate::error::PaftError;
160
161 fn from_str(input: &str) -> ::std::result::Result<Self, Self::Err> {
162 let trimmed = input.trim();
163 if trimmed.is_empty() {
164 return Err($crate::error::PaftError::InvalidEnumValue {
165 enum_name: $enum_name,
166 value: input.to_string(),
167 });
168 }
169 let token = paft_utils::canonicalize(trimmed);
170 let parsed = match token.as_ref() {
171 $( $alias => $variant, )*
172 _ => {
173 let canon = paft_utils::Canonical::try_new(trimmed)
174 .map_err(|_| $crate::error::PaftError::InvalidEnumValue {
175 enum_name: $enum_name,
176 value: input.to_string(),
177 })?;
178 return Ok($OtherVariant(canon));
179 }
180 };
181 Ok(parsed)
182 }
183 }
184
185 impl ::std::convert::TryFrom<String> for $Type {
186 type Error = $crate::error::PaftError;
187
188 fn try_from(value: String) -> ::std::result::Result<Self, Self::Error> {
189 Self::from_str(&value)
190 }
191 }
192
193 impl ::std::convert::From<$Type> for String {
194 fn from(v: $Type) -> Self { v.code().to_string() }
195 }
196
197 impl $Type {
198 #[doc(hidden)]
199 pub const __ALIASES: &'static [(&'static str, $Type)] = &[
200 $( ($alias, $variant) ),*
201 ];
202 }
203 };
204}
205
206#[doc(hidden)]
208#[macro_export]
209macro_rules! impl_display_via_code {
210 ( $Type:ident ) => {
211 impl ::std::fmt::Display for $Type {
212 fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
213 f.write_str(self.code())
214 }
215 }
216 };
217}
218
219#[doc(hidden)]
221#[macro_export]
222macro_rules! string_enum_with_code {
223 (
224 $Type:ident, $Other:ident, $enum_name:literal,
225 { $( $canon_token:literal => $canon_variant:path ),+ $(,)? },
226 { $( $alias:literal => $variant:path ),* $(,)? }
227 ) => {
228 impl $Type {
229 #[must_use]
231 pub fn code(&self) -> &str {
232 match self {
233 $( $canon_variant => $canon_token, )+
234 $Type::$Other(s) => s.as_ref(),
235 }
236 }
237 }
238
239 $crate::__string_enum_base! {
240 $Type, $enum_name, other($Type::$Other),
241 { $( $canon_token => $canon_variant ),+ $(, $alias => $variant )* }
242 }
243 };
244
245 (
246 $Type:ident, $Other:ident, $enum_name:literal,
247 { $( $canon_token:literal => $canon_variant:path ),+ $(,)? }
248 ) => {
249 $crate::string_enum_with_code!(
250 $Type, $Other, $enum_name,
251 { $( $canon_token => $canon_variant ),+ },
252 {}
253 );
254 };
255}
256
257#[doc(hidden)]
259#[macro_export]
260macro_rules! string_enum_closed_with_code {
261 (
262 $Type:ident, $enum_name:literal,
263 { $( $canon_token:literal => $canon_variant:path ),+ $(,)? },
264 { $( $alias:literal => $variant:path ),* $(,)? }
265 ) => {
266 impl $Type {
267 #[must_use]
269 pub const fn code(&self) -> &str {
270 match self {
271 $( $canon_variant => $canon_token, )+
272 }
273 }
274 }
275
276 $crate::__string_enum_base! {
277 $Type, $enum_name, error,
278 { $( $canon_token => $canon_variant ),+ $(, $alias => $variant )* }
279 }
280 };
281
282 (
283 $Type:ident, $enum_name:literal,
284 { $( $canon_token:literal => $canon_variant:path ),+ $(,)? }
285 ) => {
286 $crate::string_enum_closed_with_code!(
287 $Type, $enum_name,
288 { $( $canon_token => $canon_variant ),+ },
289 {}
290 );
291 };
292}
293
294pub use error::PaftError;
295
296#[cfg(feature = "dataframe")]
297pub use paft_utils::dataframe::{Columnar, ToDataFrame, ToDataFrameVec};