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