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