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