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