kotlin_poet_rs/spec/
type.rs1use std::str::FromStr;
2
3use crate::io::RenderKotlin;
4use crate::spec::{ClassLikeTypeName, CodeBlock, FunctionType, Name, Package};
5use crate::spec::class_like_type::ClassLikeType;
6use crate::tokens;
7use crate::util::{SemanticConversionError, yolo_from_str};
8
9macro_rules! fn_basic_type_factory {
11 ($identifier:ident, $($package:tt).+, $class:ident) => {
12 #[doc = concat!(
13 "Creates `",
14 stringify!($($package).+),
15 ".",
16 stringify!($class)
17 )]
18 pub fn $identifier() -> Type {
19 use std::str::FromStr;
20
21 let package = Package::from_str(stringify!($($package).+)).unwrap();
22 let name = Name::from_str(stringify!($class)).unwrap();
23
24 Type::ClassLike(
25 ClassLikeType::new(
26 ClassLikeTypeName::top_level(
27 package,
28 name
29 )
30 )
31 )
32 }
33 };
34}
35
36macro_rules! fn_generic_type_factory {
37 ($identifier:ident, $($package:tt).+, $class:ident<$($generic:ident),+>) => {
38 #[doc = concat!(
39 "Creates `",
40 stringify!($($package).+),
41 ".",
42 stringify!($class)
43 )]
44 pub fn $identifier($($generic: Type,)+) -> Type {
45 use std::str::FromStr;
46
47 let package = Package::from_str(stringify!($($package).+)).unwrap();
48 let name = Name::from_str(stringify!($class)).unwrap();
49
50 let mut inner_type = ClassLikeType::new(
51 ClassLikeTypeName::top_level(
52 package,
53 name,
54 )
55 );
56
57 $(
58 inner_type = inner_type.generic_argument($generic);
59 )+
60
61 Type::ClassLike(
62 inner_type
63 )
64 }
65 };
66}
67#[derive(PartialEq, Debug, Clone)]
71pub enum Type {
72 ClassLike(ClassLikeType),
74 Function(FunctionType),
76 Generic(Name),
78}
79
80impl Type {
81 pub fn generic<NameLike: Into<Name>>(name: NameLike) -> Type {
83 Type::Generic(name.into())
84 }
85
86 fn_basic_type_factory!(int, kotlin, Int);
88 fn_basic_type_factory!(long, kotlin, Long);
89 fn_basic_type_factory!(short, kotlin, Short);
90 fn_basic_type_factory!(byte, kotlin, Byte);
91
92 fn_basic_type_factory!(float, kotlin, Float);
94 fn_basic_type_factory!(double, kotlin, Double);
95
96 fn_basic_type_factory!(boolean, kotlin, Boolean);
98
99 fn_basic_type_factory!(char, kotlin, Char);
101 fn_basic_type_factory!(string, kotlin, String);
102
103 fn_basic_type_factory!(unit, kotlin, Unit);
105 fn_basic_type_factory!(any, kotlin, Any);
106 fn_basic_type_factory!(nothing, kotlin, Nothing);
107
108 fn_generic_type_factory!(map, kotlin.collections, Map<key, value>);
110 fn_generic_type_factory!(list, kotlin.collections, List<value>);
111 fn_generic_type_factory!(set, kotlin.collections, Set<value>);
112 fn_generic_type_factory!(array, kotlin, Array<value>);
113}
114
115impl From<ClassLikeTypeName> for Type {
116 fn from(value: ClassLikeTypeName) -> Self {
117 Type::ClassLike(ClassLikeType::new(value))
118 }
119}
120
121impl From<ClassLikeType> for Type {
122 fn from(value: ClassLikeType) -> Self {
123 Type::ClassLike(value)
124 }
125}
126
127yolo_from_str!(Type);
128impl FromStr for Type {
129 type Err = SemanticConversionError;
130
131 fn from_str(s: &str) -> Result<Self, Self::Err> {
132 let clear = s.trim();
133
134 if !clear.contains(tokens::DOT) {
135 return Ok(
136 Type::Generic(
137 Name::from_str(clear)?
138 )
139 );
140 }
141
142 if clear.contains(tokens::ROUND_BRACKET_LEFT) {
143 return Err(
144 SemanticConversionError::new(
145 "Function types are not supported by Type::from_str"
146 )
147 );
148 }
149
150 Ok(
151 Type::ClassLike(
152 ClassLikeType::from_str(clear)?
153 )
154 )
155 }
156}
157
158impl RenderKotlin for Type {
159 fn render_into(&self, block: &mut CodeBlock) {
160 match self {
161 Type::ClassLike(class_like) => block.push_renderable(class_like),
162 Type::Generic(name) => block.push_renderable(name),
163 Type::Function(lambda) => block.push_renderable(lambda)
164 }
165 }
166}
167
168#[cfg(test)]
169mod tests {
170 use std::str::FromStr;
171
172 use crate::io::RenderKotlin;
173 use crate::spec::{Name, Type};
174
175 #[test]
176 fn render_generic_parameter() {
177 let name = Name::from_str("T").unwrap();
178 let parameter = Type::Generic(name);
179 assert_eq!(parameter.render_string(), "T");
180 }
181
182 #[test]
183 fn parse_fn_type() {
184 let new_type = Type::from_str("() -> String");
185 assert!(matches!(
186 new_type,
187 Err(_)
188 ));
189 }
190
191 #[test]
192 fn parse_generic() {
193 let new_type = Type::from_str("T");
194 assert_eq!(
195 new_type.unwrap(),
196 Type::generic("T")
197 );
198 }
199}