1mod derive;
93pub use derive::ToTypeProtocol;
94
95#[cfg(test)]
96mod tests;
97
98use std::{
99 str::FromStr,
100 marker::PhantomData,
101 num::{NonZeroUsize, ParseIntError},
102 fmt::{Display, Pointer}
103};
104
105pub trait IdentValidation {
106 fn validate(s: &str) -> bool;
107}
108
109#[derive(PartialEq, Eq)]
110pub struct AlwaysValid;
111#[derive(PartialEq, Eq)]
112pub struct UnicodeXID;
113#[derive(PartialEq, Eq)]
114pub struct RustIdent;
115#[derive(PartialEq, Eq)]
116pub struct AsciiIdent;
117
118impl IdentValidation for AlwaysValid {
119 fn validate(_: &str) -> bool {
120 true
121 }
122}
123
124impl IdentValidation for UnicodeXID {
125 fn validate(s: &str) -> bool {
126 let mut chars = s.chars();
127 if let Some(c) = chars.next() {
128 if unicode_ident::is_xid_start(c) {
129 chars.all(|c| unicode_ident::is_xid_continue(c))
130 } else {
131 false
132 }
133 } else {
134 false
135 }
136 }
137}
138
139impl IdentValidation for RustIdent {
140 fn validate(s: &str) -> bool {
141 let mut chars = s.chars();
142 if let Some(c) = chars.next() {
143 if unicode_ident::is_xid_start(c) || c == '_' {
144 chars.all(|c| unicode_ident::is_xid_continue(c))
145 } else {
146 false
147 }
148 } else {
149 false
150 }
151 }
152}
153
154impl IdentValidation for AsciiIdent {
155 fn validate(s: &str) -> bool {
156 let mut chars = s.chars();
157 if let Some(c) = chars.next() {
158 if matches!(c, 'a'..='z'|'A'..='Z'|'_') {
159 chars.all(|c| matches!(c, '0'..='9'|'a'..='z'|'A'..='Z'|'_'))
160 } else {
161 false
162 }
163 } else {
164 false
165 }
166 }
167}
168
169#[doc(hidden)]
170#[derive(Debug, Clone, PartialEq, Eq, Hash)]
171pub enum Never {}
172
173#[derive(Debug, Clone, PartialEq, Eq, Hash)]
174#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
175#[non_exhaustive]
176pub enum UniversalType {
177 Bool,
178 USize,
179 ISize,
180 Int(NonZeroUsize),
181 UInt(NonZeroUsize),
182 Float(NonZeroUsize),
183 Char,
184 String,
185}
186
187impl FromStr for UniversalType {
188 type Err = ();
189
190 fn from_str(s: &str) -> Result<Self, Self::Err> {
191 Ok(match s {
192 "bool" => Self::Bool,
193 "int"|"isize" => Self::ISize,
194 "uint"|"usize" => Self::USize,
195 "int8" => Self::Int(nz!(1)),
196 "int16" => Self::Int(nz!(2)),
197 "int32" => Self::Int(nz!(4)),
198 "int64" => Self::Int(nz!(8)),
199 "int128" => Self::Int(nz!(16)),
200 "uint8" => Self::UInt(nz!(1)),
201 "uint16" => Self::UInt(nz!(2)),
202 "uint32" => Self::UInt(nz!(4)),
203 "uint64" => Self::UInt(nz!(8)),
204 "uint128" => Self::UInt(nz!(16)),
205 "float16"|"half" => Self::Float(nz!(2)),
206 "float"|"float32"|"single" => Self::Float(nz!(4)),
207 "float64"|"double" => Self::Float(nz!(8)),
208 "char" => Self::Char,
209 "string" => Self::String,
210 _ => return Err(())
211 })
212 }
213}
214
215impl Display for UniversalType {
216 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
217 match self {
218 UniversalType::Bool => f.write_str("bool"),
219 UniversalType::USize => f.write_str("uint"),
220 UniversalType::ISize => f.write_str("int"),
221 UniversalType::Int(n) => {
222 f.write_str("int")?;
223 n.checked_mul(nz!(8)).unwrap().fmt(f)
224 },
225 UniversalType::UInt(n) => {
226 f.write_str("uint")?;
227 n.checked_mul(nz!(8)).unwrap().fmt(f)
228 },
229 UniversalType::Float(n) => {
230 f.write_str("float")?;
231 n.checked_mul(nz!(8)).unwrap().fmt(f)
232 },
233 UniversalType::Char => f.write_str("char"),
234 UniversalType::String => f.write_str("string"),
235 }
236 }
237}
238
239#[derive(Debug, Clone, PartialEq, Eq, Hash, strum::IntoStaticStr, strum::EnumString)]
240#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
241#[cfg_attr(feature = "rkyv", derive(rkyv::Archive))]
242#[non_exhaustive]
243pub enum ExtensionType {
244 #[strum(serialize="decimal")]
245 Decimal,
246 #[strum(serialize="datetime")]
247 DateTime,
248 #[strum(serialize="date")]
249 Date,
250 #[strum(serialize="time")]
251 Time,
252 #[strum(serialize="duration")]
253 Duration,
254 #[strum(serialize="rgb")]
255 Rgb,
256 #[strum(serialize="rgba")]
257 Rgba,
258 #[strum(serialize="uuid")]
259 Uuid,
260}
261
262
263#[derive(Debug, Clone, PartialEq, Eq, Hash)]
264#[cfg_attr(feature = "rkyv", derive(rkyv::Archive))]
265#[non_exhaustive]
266pub enum Typing<Validation = AlwaysValid> {
267 None,
269 Common(UniversalType),
273 Extension(ExtensionType),
280 Named(String),
282 Path{
284 absolute: bool,
286 path: Vec<String>,
288 name: String,
290 },
291 Option(Box<Self>),
293 Tuple(Vec<Self>),
297 Array(usize, Box<Self>),
301 Vec(Box<Self>),
305 Set(Box<Self>),
309 Map(Box<Self>,Box<Self>),
313 Foreign(Box<Self>),
317 #[doc(hidden)]
318 _Invalid(PhantomData<Validation>, Never)
319}
320
321impl<V> Typing<V> {
322 fn boxed(self) -> Box<Self> {
323 Box::new(self)
324 }
325}
326
327impl<V> Display for Typing<V> {
328 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
329 match self {
330 Typing::None => f.write_str("none"),
331 Typing::Common(t) => t.fmt(f),
332 Typing::Extension(e) => {
333 f.write_str("+")?;
334 e.fmt(f)
335 },
336 Typing::Named(n) => f.write_str(&n),
337 Typing::Path { absolute, path, name } => {
338 if *absolute { f.write_str("::")?; }
339 for s in path {
340 f.write_str(&s)?;
341 f.write_str("::")?;
342 }
343 f.write_str(&name)
344 },
345 Typing::Option(t) => {
346 f.write_str("?")?;
347 t.as_ref().fmt(f)
348 },
349 Typing::Tuple(items) => {
350 f.write_str("(")?;
351 let mut iter = items.iter();
352 if let Some(first) = iter.next() {
353 first.fmt(f)?;
354 }
355 for item in iter {
356 f.write_str(",")?;
357 item.fmt(f)?;
358 }
359 f.write_str(")")
360 },
361 Typing::Array(len, item) => {
362 f.write_str("[")?;
363 len.fmt(f)?;
364 f.write_str("]")?;
365 item.as_ref().fmt(f)
366 },
367 Typing::Vec(item) => {
368 f.write_str("[]")?;
369 item.as_ref().fmt(f)
370 },
371 Typing::Set(item) => {
372 f.write_str("[")?;
373 item.as_ref().fmt(f)?;
374 f.write_str("]")
375 },
376 Typing::Map(key, value) => {
377 f.write_str("[")?;
378 key.as_ref().fmt(f)?;
379 f.write_str("]")?;
380 value.as_ref().fmt(f)
381 },
382 Typing::Foreign(item) => {
383 f.write_str("@")?;
384 item.as_ref().fmt(f)
385 },
386 Typing::_Invalid(..) => unreachable!(),
387 }
388 }
389}
390
391#[derive(Debug, thiserror::Error, PartialEq, Eq)]
392pub enum Error {
393 #[error("Empty string as a type is not allowed, use 'none' instead.")]
394 Empty,
395 #[error("Parenthesis () mismatch.")]
396 ParenthesisMismatch,
397 #[error("Brackets [] mismatch.")]
398 BracketsMismatch,
399 #[error("Unknown extension type.")]
400 UnknownExtensionType,
401 #[error("Invalid ident found.")]
402 ValidationFailed,
403 #[error("{}", 0)]
404 ParseIntError(#[from]ParseIntError)
405}
406
407impl<V: IdentValidation> FromStr for Typing<V> {
408 type Err = Error;
409
410 fn from_str(s: &str) -> Result<Self, Self::Err> {
415 if s == "none" {
416 return Ok(Self::None);
417 }
418 let mut chars = s.chars();
419 Ok(match chars.next() {
420 None => return Err(Error::Empty),
421 Some(')'|']'|'}') => return Err(Error::BracketsMismatch),
422 Some('(') => {
423 if chars.next_back() != Some(')') {
424 return Err(Error::BracketsMismatch);
425 }
426 let mut paren = 0;
427 let mut bracket = 0;
428 let result = Self::Tuple(chars.as_str()
429 .split(|c| {
430 match c {
431 '[' => if bracket >= 0 { bracket += 1 },
432 ']' => bracket -= 1,
433 '(' => if paren >= 0 { paren += 1 },
434 ')' => paren -= 1,
435 ',' if paren == 0 && bracket == 0 => return true,
436 _ => (),
437 }
438 return false;
439 })
440 .map(|x| Self::from_str(x))
441 .collect::<Result<Vec<_>, _>>()?);
442 if paren != 0 {
443 return Err(Error::ParenthesisMismatch)
444 } else if bracket != 0 {
445 return Err(Error::BracketsMismatch)
446 } else {
447 result
448 }
449 },
450 Some('[') => {
451 let mut paren = 0;
452 let mut bracket = 1;
453 let (key, value) = match chars.as_str().split_once(|c| {
454 match c {
455 '[' => if bracket >= 0 { bracket += 1 },
456 ']' => {
457 bracket -= 1;
458 if bracket == 0 {
459 return true;
460 }
461 },
462 '(' => if paren >= 0 { paren += 1 },
463 ')' => paren -= 1,
464 _ => (),
465 }
466 return false;
467 }) {
468 Some((k, v)) => (k, v),
469 None => return Err(Error::BracketsMismatch),
470 };
471 if key.len() == 0 {
472 Self::Vec(Self::from_str(value)?.boxed())
473 } else if value.len() == 0 {
474 Self::Set(Self::from_str(key)?.boxed())
475 } else if key.chars().all(|x| matches!(x, '0'..='9')) {
476 Self::Array(key.parse()?, Self::from_str(value)?.boxed())
477 } else {
478 Self::Map(Self::from_str(key)?.boxed(), Self::from_str(value)?.boxed())
479 }
480 },
481 Some('?') => Self::Option(Self::from_str(chars.as_str())?.boxed()),
482 Some('@') => Self::Foreign(Self::from_str(chars.as_str())?.boxed()),
483 Some('+') => {
484 if let Ok(t) = ExtensionType::from_str(chars.as_str()) {
485 Self::Extension(t)
486 } else {
487 return Err(Error::UnknownExtensionType);
488 }
489 },
490 _ => {
491 if let Ok(t) = UniversalType::from_str(s) {
492 Self::Common(t)
493 } else if s.contains("::") {
494 let absolute = s.starts_with("::");
495 let s = s.trim_start_matches("::");
496 let mut path: Vec<String> = s.split("::").map(|x| x.to_owned()).collect();
497 if path.iter().any(|x| !V::validate(x)) {
498 return Err(Error::ValidationFailed);
499 }
500 let name = path.pop().ok_or(Error::Empty)?;
501 Self::Path { absolute, path, name }
502 } else if V::validate(s) {
503 Self::Named(s.to_owned())
504 } else {
505 return Err(Error::ValidationFailed);
506 }
507 }
508 })
509 }
510}
511
512#[cfg(feature = "serde")]
513const _: () = {
514 use serde::{Serialize, Deserialize};
515
516 impl<V> Serialize for Typing<V> {
517 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> where S: serde::Serializer {
518 self.to_string().serialize(serializer)
519 }
520 }
521
522 impl<'de, V: IdentValidation> Deserialize<'de> for Typing<V> {
523 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> where D: serde::Deserializer<'de> {
524 Self::from_str(<&str>::deserialize(deserializer)?)
525 .map_err(|e| serde::de::Error::custom(e.to_string()))
526 }
527 }
528};