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