1use std::fmt;
11use std::str::FromStr;
12
13use crate::errors::ParamParseError;
14
15#[derive(Debug, PartialEq)]
17pub struct Type {
18 pub name: String,
20
21 pub bare: bool,
23
24 pub generic_arg: Option<Box<Type>>,
26}
27
28impl fmt::Display for Type {
29 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
30 write!(f, "{}", self.name)?;
31 if let Some(generic_arg) = &self.generic_arg {
32 write!(f, "<{generic_arg}>")?;
33 }
34 Ok(())
35 }
36}
37
38impl FromStr for Type {
39 type Err = ParamParseError;
40
41 fn from_str(ty: &str) -> Result<Self, Self::Err> {
51 let (ty, generic_arg) = if let Some(pos) = ty.find('<') {
53 if !ty.ends_with('>') {
54 return Err(ParamParseError::InvalidGeneric);
55 }
56 (
57 &ty[..pos],
58 Some(Box::new(Type::from_str(&ty[pos + 1..ty.len() - 1])?)),
59 )
60 } else {
61 (ty, None)
62 };
63
64 if ty.is_empty() {
65 return Err(ParamParseError::Empty);
66 }
67
68 let bare = ty.chars().next().unwrap().is_ascii_lowercase();
70
71 Ok(Self {
72 name: ty.into(),
73 bare,
74 generic_arg,
75 })
76 }
77}
78
79#[cfg(test)]
80mod tests {
81 use super::*;
82
83 #[test]
84 fn check_empty_simple() {
85 assert_eq!(Type::from_str(""), Err(ParamParseError::Empty));
86 }
87
88 #[test]
89 fn check_simple() {
90 assert_eq!(
91 Type::from_str("foo"),
92 Ok(Type {
93 name: "foo".into(),
94 bare: true,
95 generic_arg: None,
96 })
97 );
98 }
99
100 #[test]
101 fn check_empty() {
102 assert_eq!(Type::from_str(""), Err(ParamParseError::Empty));
103 }
104
105 #[test]
106 fn check_bare() {
107 assert!(matches!(Type::from_str("foo"), Ok(Type { bare: true, .. })));
108 assert!(matches!(
109 Type::from_str("Foo"),
110 Ok(Type { bare: false, .. })
111 ));
112 }
113
114 #[test]
115 fn check_generic_arg() {
116 assert!(matches!(
117 Type::from_str("foo"),
118 Ok(Type {
119 generic_arg: None,
120 ..
121 })
122 ));
123 assert!(match Type::from_str("foo<bar>") {
124 Ok(Type {
125 generic_arg: Some(x),
126 ..
127 }) => *x == "bar".parse().unwrap(),
128 _ => false,
129 });
130 assert!(match Type::from_str("foo<bar>") {
131 Ok(Type {
132 generic_arg: Some(x),
133 ..
134 }) => *x == "bar".parse().unwrap(),
135 _ => false,
136 });
137 assert!(match Type::from_str("foo<bar<baz>>") {
138 Ok(Type {
139 generic_arg: Some(x),
140 ..
141 }) => *x == "bar<baz>".parse().unwrap(),
142 _ => false,
143 });
144 }
145}