1use crate::core::config::Language;
2use crate::core::ir::{PrimitiveType, TypeRef};
3use crate::docs::naming::type_name;
4
5pub fn doc_type(ty: &TypeRef, lang: Language, ffi_prefix: &str) -> String {
6 match ty {
7 TypeRef::String | TypeRef::Char => match lang {
8 Language::Python => "str".to_string(),
9 Language::Node | Language::Wasm => "string".to_string(),
10 Language::Go => "string".to_string(),
11 Language::Java => "String".to_string(),
12 Language::Csharp => "string".to_string(),
13 Language::Ruby => "String".to_string(),
14 Language::Php => "string".to_string(),
15 Language::Elixir => "String.t()".to_string(),
16 Language::R => "character".to_string(),
17 Language::Rust => "String".to_string(),
18 Language::Ffi | Language::C | Language::Jni => "const char*".to_string(),
19 Language::Kotlin | Language::KotlinAndroid | Language::Swift | Language::Dart => "String".to_string(),
20 Language::Gleam => "String".to_string(),
21 Language::Zig => "[:0]const u8".to_string(),
22 },
23 TypeRef::Bytes => match lang {
24 Language::Python => "bytes".to_string(),
25 Language::Node | Language::Wasm => "Buffer".to_string(),
26 Language::Go => "[]byte".to_string(),
27 Language::Java => "byte[]".to_string(),
28 Language::Csharp => "byte[]".to_string(),
29 Language::Ruby => "String".to_string(),
30 Language::Php => "string".to_string(),
31 Language::Elixir => "binary()".to_string(),
32 Language::R => "raw".to_string(),
33 Language::Rust => "Vec<u8>".to_string(),
34 Language::Ffi | Language::C | Language::Jni => "const uint8_t*".to_string(),
35 Language::Kotlin | Language::KotlinAndroid => "ByteArray".to_string(),
36 Language::Swift => "Data".to_string(),
37 Language::Dart => "Uint8List".to_string(),
38 Language::Gleam => "BitArray".to_string(),
39 Language::Zig => "[]const u8".to_string(),
40 },
41 TypeRef::Primitive(p) => doc_primitive(p, lang),
42 TypeRef::Optional(inner) => {
43 let inner_ty = doc_type(inner, lang, ffi_prefix);
44 match lang {
45 Language::Python => format!("{inner_ty} | None"),
46 Language::Node | Language::Wasm => format!("{inner_ty} | null"),
47 Language::Go => format!("*{inner_ty}"),
48 Language::Java => {
49 let boxed = java_boxed_type(inner);
50 format!("Optional<{boxed}>")
51 }
52 Language::Csharp => format!("{inner_ty}?"),
53 Language::Ruby => format!("{inner_ty}?"),
54 Language::Php => format!("?{inner_ty}"),
55 Language::Elixir => format!("{inner_ty} | nil"),
56 Language::R => format!("{inner_ty} or NULL"),
57 Language::Rust => format!("Option<{inner_ty}>"),
58 Language::Ffi | Language::C | Language::Jni => format!("{inner_ty}*"),
59 Language::Kotlin | Language::KotlinAndroid | Language::Swift | Language::Dart => format!("{inner_ty}?"),
60 Language::Gleam => format!("Option({inner_ty})"),
61 Language::Zig => format!("?{inner_ty}"),
62 }
63 }
64 TypeRef::Vec(inner) => {
65 match lang {
66 Language::Java => {
67 let inner_ty = java_boxed_type(inner);
69 format!("List<{inner_ty}>")
70 }
71 Language::Csharp => {
72 let inner_ty = doc_type(inner, lang, ffi_prefix);
73 format!("List<{inner_ty}>")
74 }
75 _ => {
76 let inner_ty = doc_type(inner, lang, ffi_prefix);
77 match lang {
78 Language::Python => format!("list[{inner_ty}]"),
79 Language::Node | Language::Wasm => format!("Array<{inner_ty}>"),
80 Language::Go => format!("[]{inner_ty}"),
81 Language::Ruby => format!("Array<{inner_ty}>"),
82 Language::Php => format!("array<{inner_ty}>"),
83 Language::Elixir => format!("list({inner_ty})"),
84 Language::R => "list".to_string(),
85 Language::Rust => format!("Vec<{inner_ty}>"),
86 Language::Ffi | Language::C | Language::Jni => format!("{inner_ty}*"),
87 Language::Java | Language::Csharp => unreachable!(),
88 Language::Kotlin | Language::KotlinAndroid | Language::Dart => format!("List<{inner_ty}>"),
89 Language::Swift => format!("[{inner_ty}]"),
90 Language::Gleam => format!("List({inner_ty})"),
91 Language::Zig => format!("[]const {inner_ty}"),
92 }
93 }
94 }
95 }
96 TypeRef::Map(k, v) => {
97 if lang == Language::Java {
98 let kty = java_boxed_type(k);
100 let vty = java_boxed_type(v);
101 return format!("Map<{kty}, {vty}>");
102 }
103 let kty = doc_type(k, lang, ffi_prefix);
104 let vty = doc_type(v, lang, ffi_prefix);
105 match lang {
106 Language::Python => format!("dict[{kty}, {vty}]"),
107 Language::Node | Language::Wasm => format!("Record<{kty}, {vty}>"),
108 Language::Go => format!("map[{kty}]{vty}"),
109 Language::Java => format!("Map<{kty}, {vty}>"),
110 Language::Csharp => format!("Dictionary<{kty}, {vty}>"),
111 Language::Ruby => format!("Hash{{{kty}=>{vty}}}"),
112 Language::Php => format!("array<{kty}, {vty}>"),
113 Language::Elixir => "map()".to_string(),
114 Language::R => "list".to_string(),
115 Language::Rust => format!("HashMap<{kty}, {vty}>"),
116 Language::Ffi | Language::C | Language::Jni => "void*".to_string(),
117 Language::Kotlin | Language::KotlinAndroid => format!("Map<{kty}, {vty}>"),
118 Language::Swift => format!("[{kty}: {vty}]"),
119 Language::Dart => format!("Map<{kty}, {vty}>"),
120 Language::Gleam => format!("Dict({kty}, {vty})"),
121 Language::Zig => format!("std.StringHashMap({vty})"),
122 }
123 }
124 TypeRef::Named(name) if name.starts_with('(') && name.ends_with(')') => {
125 let inner = &name[1..name.len() - 1];
127 let rendered: Vec<String> = inner
128 .split(',')
129 .map(|part| {
130 let trimmed = part.trim();
131 match trimmed {
132 "usize" | "u64" | "u32" | "u16" | "u8" | "i64" | "i32" | "i16" | "i8" | "isize" => {
133 let swift_name = match trimmed {
137 "u64" | "usize" => "UInt64",
138 "u32" => "UInt32",
139 "u16" => "UInt16",
140 "u8" => "UInt8",
141 "i64" | "isize" => "Int64",
142 "i32" => "Int32",
143 "i16" => "Int16",
144 "i8" => "Int8",
145 _ => "Int64",
146 };
147 match lang {
148 Language::Python => "int".to_string(),
149 Language::Node | Language::Wasm => "number".to_string(),
150 Language::Go => "int".to_string(),
151 Language::Java => "long".to_string(),
152 Language::Csharp => "long".to_string(),
153 Language::Ruby => "Integer".to_string(),
154 Language::Php => "int".to_string(),
155 Language::Elixir => "integer()".to_string(),
156 Language::R => "integer".to_string(),
157 Language::Rust => trimmed.to_string(),
158 Language::Ffi | Language::C | Language::Jni => "uint64_t".to_string(),
159 Language::Kotlin | Language::KotlinAndroid => "Long".to_string(),
160 Language::Swift => swift_name.to_string(),
161 Language::Dart => "int".to_string(),
162 Language::Gleam => "Int".to_string(),
163 Language::Zig => "i64".to_string(),
164 }
165 }
166 s @ ("str" | "&str" | "String" | "&'static str" | "&'staticstr") => match lang {
167 Language::Python => "str".to_string(),
168 Language::Node | Language::Wasm => "string".to_string(),
169 Language::Go => "string".to_string(),
170 Language::Java => "String".to_string(),
171 Language::Csharp => "string".to_string(),
172 Language::Ruby => "String".to_string(),
173 Language::Php => "string".to_string(),
174 Language::Elixir => "String.t()".to_string(),
175 Language::R => "character".to_string(),
176 Language::Rust => s.to_string(),
177 Language::Ffi | Language::C | Language::Jni => "const char*".to_string(),
178 Language::Kotlin | Language::KotlinAndroid | Language::Swift | Language::Dart => {
179 "String".to_string()
180 }
181 Language::Gleam => "String".to_string(),
182 Language::Zig => "[]const u8".to_string(),
183 },
184 s if s.contains("[&")
187 || s.contains("[String")
188 || s.contains("Vec<&")
189 || s.contains("Vec<String")
190 || s.contains("staticstr") =>
191 {
192 match lang {
193 Language::Python => "list[str]".to_string(),
194 Language::Node | Language::Wasm => "string[]".to_string(),
195 Language::Go => "[]string".to_string(),
196 Language::Java => "List<String>".to_string(),
197 Language::Csharp => "List<string>".to_string(),
198 Language::Ruby => "Array<String>".to_string(),
199 Language::Php => "array<string>".to_string(),
200 Language::Elixir => "list(String.t())".to_string(),
201 Language::R => "list".to_string(),
202 Language::Rust => s.to_string(),
203 Language::Ffi | Language::C | Language::Jni => "const char**".to_string(),
204 Language::Kotlin | Language::KotlinAndroid | Language::Swift | Language::Dart => {
205 "List<String>".to_string()
206 }
207 Language::Gleam => "List(String)".to_string(),
208 Language::Zig => "[]const []const u8".to_string(),
209 }
210 }
211 other => {
212 if lang == Language::Rust {
215 other.to_string()
216 } else {
217 type_name(other, lang, ffi_prefix)
218 }
219 }
220 }
221 })
222 .collect();
223 match lang {
224 Language::Python => format!("tuple[{}]", rendered.join(", ")),
225 Language::Node | Language::Wasm => format!("[{}]", rendered.join(", ")),
226 Language::Go => format!("({})", rendered.join(", ")),
227 Language::Java => format!("Tuple<{}>", rendered.join(", ")),
228 Language::Csharp => format!("({})", rendered.join(", ")),
229 Language::Ruby => format!("[{}]", rendered.join(", ")),
230 Language::Php => format!("array{{{}}}", rendered.join(", ")),
231 Language::Elixir => format!("{{{}}}", rendered.join(", ")),
232 Language::R => "list".to_string(),
233 Language::Rust => format!("({})", rendered.join(", ")),
234 Language::Ffi | Language::C | Language::Jni => "void*".to_string(),
235 Language::Kotlin | Language::KotlinAndroid => format!("Pair<{}>", rendered.join(", ")),
236 Language::Swift => format!("({})", rendered.join(", ")),
237 Language::Dart => format!("({})", rendered.join(", ")),
238 Language::Gleam => format!("#({})", rendered.join(", ")),
239 Language::Zig => format!("struct {{ {} }}", rendered.join(", ")),
240 }
241 }
242 TypeRef::Named(name) => type_name(name, lang, ffi_prefix),
243 TypeRef::Path => match lang {
244 Language::Python => "str".to_string(),
245 Language::Node | Language::Wasm => "string".to_string(),
246 Language::Go => "string".to_string(),
247 Language::Java => "String".to_string(),
248 Language::Csharp => "string".to_string(),
249 Language::Ruby => "String".to_string(),
250 Language::Php => "string".to_string(),
251 Language::Elixir => "String.t()".to_string(),
252 Language::R => "character".to_string(),
253 Language::Rust => "PathBuf".to_string(),
254 Language::Ffi | Language::C | Language::Jni => "const char*".to_string(),
255 Language::Kotlin | Language::KotlinAndroid => "Path".to_string(),
256 Language::Swift => "URL".to_string(),
257 Language::Dart => "String".to_string(),
258 Language::Gleam => "String".to_string(),
259 Language::Zig => "[:0]const u8".to_string(),
260 },
261 TypeRef::Unit => match lang {
262 Language::Python => "None".to_string(),
263 Language::Node | Language::Wasm => "void".to_string(),
264 Language::Go => "".to_string(),
265 Language::Java => "void".to_string(),
266 Language::Csharp => "void".to_string(),
267 Language::Ruby => "nil".to_string(),
268 Language::Php => "void".to_string(),
269 Language::Elixir => ":ok".to_string(),
270 Language::R => "NULL".to_string(),
271 Language::Rust => "()".to_string(),
272 Language::Ffi | Language::C | Language::Jni => "void".to_string(),
273 Language::Kotlin | Language::KotlinAndroid => "Unit".to_string(),
274 Language::Swift => "Void".to_string(),
275 Language::Dart => "void".to_string(),
276 Language::Gleam => "Nil".to_string(),
277 Language::Zig => "void".to_string(),
278 },
279 TypeRef::Json => match lang {
280 Language::Python => "dict[str, Any]".to_string(),
281 Language::Node | Language::Wasm => "unknown".to_string(),
282 Language::Go => "interface{}".to_string(),
283 Language::Java => "Object".to_string(),
284 Language::Csharp => "object".to_string(),
285 Language::Ruby => "Object".to_string(),
286 Language::Php => "mixed".to_string(),
287 Language::Elixir => "term()".to_string(),
288 Language::R => "list".to_string(),
289 Language::Rust => "serde_json::Value".to_string(),
290 Language::Ffi | Language::C | Language::Jni => "void*".to_string(),
291 Language::Kotlin | Language::KotlinAndroid => "Any".to_string(),
292 Language::Swift => "String".to_string(),
294 Language::Dart => "String".to_string(),
295 Language::Gleam => "String".to_string(),
298 Language::Zig => "[:0]const u8".to_string(),
301 },
302 TypeRef::Duration => match lang {
303 Language::Python => "float".to_string(),
304 Language::Node | Language::Wasm => "number".to_string(),
305 Language::Go => "time.Duration".to_string(),
306 Language::Java => "Duration".to_string(),
307 Language::Csharp => "TimeSpan".to_string(),
308 Language::Ruby => "Float".to_string(),
309 Language::Php => "float".to_string(),
310 Language::Elixir => "integer()".to_string(),
311 Language::R => "numeric".to_string(),
312 Language::Rust => "std::time::Duration".to_string(),
313 Language::Ffi | Language::C | Language::Jni => "uint64_t".to_string(),
314 Language::Kotlin | Language::KotlinAndroid => "Duration".to_string(),
315 Language::Swift => "Duration".to_string(),
316 Language::Dart => "Duration".to_string(),
317 Language::Gleam => "Int".to_string(),
318 Language::Zig => "i64".to_string(),
319 },
320 }
321}
322
323pub(crate) fn doc_primitive(p: &PrimitiveType, lang: Language) -> String {
324 match lang {
325 Language::Python => match p {
326 PrimitiveType::Bool => "bool".to_string(),
327 PrimitiveType::F32 | PrimitiveType::F64 => "float".to_string(),
328 _ => "int".to_string(),
329 },
330 Language::Node | Language::Wasm => match p {
331 PrimitiveType::Bool => "boolean".to_string(),
332 _ => "number".to_string(),
333 },
334 Language::Go => match p {
335 PrimitiveType::Bool => "bool".to_string(),
336 PrimitiveType::U8 => "uint8".to_string(),
337 PrimitiveType::U16 => "uint16".to_string(),
338 PrimitiveType::U32 => "uint32".to_string(),
339 PrimitiveType::U64 => "uint64".to_string(),
340 PrimitiveType::I8 => "int8".to_string(),
341 PrimitiveType::I16 => "int16".to_string(),
342 PrimitiveType::I32 => "int32".to_string(),
343 PrimitiveType::I64 => "int64".to_string(),
344 PrimitiveType::F32 => "float32".to_string(),
345 PrimitiveType::F64 => "float64".to_string(),
346 PrimitiveType::Usize | PrimitiveType::Isize => "int".to_string(),
347 },
348 Language::Java => match p {
349 PrimitiveType::Bool => "boolean".to_string(),
350 PrimitiveType::U8 | PrimitiveType::I8 => "byte".to_string(),
351 PrimitiveType::U16 | PrimitiveType::I16 => "short".to_string(),
352 PrimitiveType::U32 | PrimitiveType::I32 => "int".to_string(),
353 PrimitiveType::U64 | PrimitiveType::I64 | PrimitiveType::Usize | PrimitiveType::Isize => "long".to_string(),
354 PrimitiveType::F32 => "float".to_string(),
355 PrimitiveType::F64 => "double".to_string(),
356 },
357 Language::Csharp => match p {
358 PrimitiveType::Bool => "bool".to_string(),
359 PrimitiveType::U8 => "byte".to_string(),
360 PrimitiveType::U16 => "ushort".to_string(),
361 PrimitiveType::U32 => "uint".to_string(),
362 PrimitiveType::U64 => "ulong".to_string(),
363 PrimitiveType::I8 => "sbyte".to_string(),
364 PrimitiveType::I16 => "short".to_string(),
365 PrimitiveType::I32 => "int".to_string(),
366 PrimitiveType::I64 => "long".to_string(),
367 PrimitiveType::Usize => "nuint".to_string(),
368 PrimitiveType::Isize => "nint".to_string(),
369 PrimitiveType::F32 => "float".to_string(),
370 PrimitiveType::F64 => "double".to_string(),
371 },
372 Language::Ruby => match p {
373 PrimitiveType::Bool => "Boolean".to_string(),
374 PrimitiveType::F32 | PrimitiveType::F64 => "Float".to_string(),
375 _ => "Integer".to_string(),
376 },
377 Language::Php => match p {
378 PrimitiveType::Bool => "bool".to_string(),
379 PrimitiveType::F32 | PrimitiveType::F64 => "float".to_string(),
380 _ => "int".to_string(),
381 },
382 Language::Elixir => match p {
383 PrimitiveType::Bool => "boolean()".to_string(),
384 PrimitiveType::F32 | PrimitiveType::F64 => "float()".to_string(),
385 _ => "integer()".to_string(),
386 },
387 Language::R => match p {
388 PrimitiveType::Bool => "logical".to_string(),
389 PrimitiveType::F32 | PrimitiveType::F64 => "numeric".to_string(),
390 _ => "integer".to_string(),
391 },
392 Language::Ffi | Language::C | Language::Jni => match p {
393 PrimitiveType::Bool => "bool".to_string(),
394 PrimitiveType::U8 => "uint8_t".to_string(),
395 PrimitiveType::U16 => "uint16_t".to_string(),
396 PrimitiveType::U32 => "uint32_t".to_string(),
397 PrimitiveType::U64 => "uint64_t".to_string(),
398 PrimitiveType::I8 => "int8_t".to_string(),
399 PrimitiveType::I16 => "int16_t".to_string(),
400 PrimitiveType::I32 => "int32_t".to_string(),
401 PrimitiveType::I64 => "int64_t".to_string(),
402 PrimitiveType::Usize => "uintptr_t".to_string(),
403 PrimitiveType::Isize => "intptr_t".to_string(),
404 PrimitiveType::F32 => "float".to_string(),
405 PrimitiveType::F64 => "double".to_string(),
406 },
407 Language::Rust => match p {
408 PrimitiveType::Bool => "bool".to_string(),
409 PrimitiveType::U8 => "u8".to_string(),
410 PrimitiveType::U16 => "u16".to_string(),
411 PrimitiveType::U32 => "u32".to_string(),
412 PrimitiveType::U64 => "u64".to_string(),
413 PrimitiveType::I8 => "i8".to_string(),
414 PrimitiveType::I16 => "i16".to_string(),
415 PrimitiveType::I32 => "i32".to_string(),
416 PrimitiveType::I64 => "i64".to_string(),
417 PrimitiveType::Usize => "usize".to_string(),
418 PrimitiveType::Isize => "isize".to_string(),
419 PrimitiveType::F32 => "f32".to_string(),
420 PrimitiveType::F64 => "f64".to_string(),
421 },
422 Language::Kotlin | Language::KotlinAndroid => match p {
423 PrimitiveType::Bool => "Boolean".to_string(),
424 PrimitiveType::U8 | PrimitiveType::I8 => "Byte".to_string(),
425 PrimitiveType::U16 | PrimitiveType::I16 => "Short".to_string(),
426 PrimitiveType::U32 | PrimitiveType::I32 => "Int".to_string(),
427 PrimitiveType::U64 | PrimitiveType::I64 | PrimitiveType::Usize | PrimitiveType::Isize => "Long".to_string(),
428 PrimitiveType::F32 => "Float".to_string(),
429 PrimitiveType::F64 => "Double".to_string(),
430 },
431 Language::Swift => match p {
432 PrimitiveType::Bool => "Bool".to_string(),
433 PrimitiveType::U8 => "UInt8".to_string(),
434 PrimitiveType::U16 => "UInt16".to_string(),
435 PrimitiveType::U32 => "UInt32".to_string(),
436 PrimitiveType::U64 | PrimitiveType::Usize => "UInt64".to_string(),
437 PrimitiveType::I8 => "Int8".to_string(),
438 PrimitiveType::I16 => "Int16".to_string(),
439 PrimitiveType::I32 => "Int32".to_string(),
440 PrimitiveType::I64 | PrimitiveType::Isize => "Int64".to_string(),
441 PrimitiveType::F32 => "Float".to_string(),
442 PrimitiveType::F64 => "Double".to_string(),
443 },
444 Language::Dart => match p {
445 PrimitiveType::Bool => "bool".to_string(),
446 PrimitiveType::F32 | PrimitiveType::F64 => "double".to_string(),
447 _ => "int".to_string(),
448 },
449 Language::Gleam => match p {
450 PrimitiveType::Bool => "Bool".to_string(),
451 PrimitiveType::F32 | PrimitiveType::F64 => "Float".to_string(),
452 _ => "Int".to_string(),
453 },
454 Language::Zig => match p {
455 PrimitiveType::Bool => "bool".to_string(),
456 PrimitiveType::U8 => "u8".to_string(),
457 PrimitiveType::U16 => "u16".to_string(),
458 PrimitiveType::U32 => "u32".to_string(),
459 PrimitiveType::U64 => "u64".to_string(),
460 PrimitiveType::I8 => "i8".to_string(),
461 PrimitiveType::I16 => "i16".to_string(),
462 PrimitiveType::I32 => "i32".to_string(),
463 PrimitiveType::I64 => "i64".to_string(),
464 PrimitiveType::Usize => "u64".to_string(),
466 PrimitiveType::Isize => "i64".to_string(),
467 PrimitiveType::F32 => "f32".to_string(),
468 PrimitiveType::F64 => "f64".to_string(),
469 },
470 }
471}
472
473pub(crate) fn java_boxed_type(ty: &TypeRef) -> String {
478 match ty {
479 TypeRef::Primitive(p) => match p {
480 PrimitiveType::Bool => "Boolean".to_string(),
481 PrimitiveType::U8 | PrimitiveType::I8 => "Byte".to_string(),
482 PrimitiveType::U16 | PrimitiveType::I16 => "Short".to_string(),
483 PrimitiveType::U32 | PrimitiveType::I32 => "Integer".to_string(),
484 PrimitiveType::U64 | PrimitiveType::I64 | PrimitiveType::Usize | PrimitiveType::Isize => "Long".to_string(),
485 PrimitiveType::F32 => "Float".to_string(),
486 PrimitiveType::F64 => "Double".to_string(),
487 },
488 _ => doc_type(ty, Language::Java, ""),
490 }
491}
492
493#[cfg(test)]
494mod tests;