ferogram_tl_parser/tl/
ty.rs1use std::fmt;
12use std::str::FromStr;
13
14use crate::errors::ParamParseError;
15
16#[derive(Clone, Debug, PartialEq, Eq, Hash)]
18pub struct Type {
19 pub namespace: Vec<String>,
21
22 pub name: String,
24
25 pub bare: bool,
27
28 pub generic_ref: bool,
30
31 pub generic_arg: Option<Box<Type>>,
33}
34
35impl fmt::Display for Type {
36 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
37 for ns in &self.namespace {
38 write!(f, "{ns}.")?;
39 }
40 if self.generic_ref {
41 write!(f, "!")?;
42 }
43 write!(f, "{}", self.name)?;
44 if let Some(arg) = &self.generic_arg {
45 write!(f, "<{arg}>")?;
46 }
47 Ok(())
48 }
49}
50
51impl Type {
52 pub(crate) fn collect_generic_refs<'a>(&'a self, output: &mut Vec<&'a str>) {
54 if self.generic_ref {
55 output.push(&self.name);
56 }
57 if let Some(arg) = &self.generic_arg {
58 arg.collect_generic_refs(output);
59 }
60 }
61}
62
63impl FromStr for Type {
64 type Err = ParamParseError;
65
66 fn from_str(raw: &str) -> Result<Self, Self::Err> {
75 let (raw, generic_ref) = match raw.strip_prefix('!') {
77 Some(r) => (r, true),
78 None => (raw, false),
79 };
80
81 let (name_part, generic_arg) = match raw.split_once('<') {
83 Some((name, rest)) => match rest.strip_suffix('>') {
84 Some(arg) => (name, Some(Box::new(Type::from_str(arg)?))),
85 None => return Err(ParamParseError::InvalidGeneric),
86 },
87 None => (raw, None),
88 };
89
90 let (namespace, name) = match name_part.rsplit_once('.') {
92 Some((ns_part, n)) => (ns_part.split('.').map(String::from).collect::<Vec<_>>(), n),
93 None => (Vec::new(), name_part),
94 };
95
96 if namespace.iter().any(|p| p.is_empty()) {
97 return Err(ParamParseError::Empty);
98 }
99
100 let first = name.chars().next().ok_or(ParamParseError::Empty)?;
101 let bare = first.is_ascii_lowercase();
102
103 Ok(Self {
104 namespace,
105 name: name.to_owned(),
106 bare,
107 generic_ref,
108 generic_arg,
109 })
110 }
111}