use crate::core::ir::{ParamDef, PrimitiveType, TypeRef};
use std::collections::{HashMap, HashSet};
pub fn format_type_ref(ty: &crate::core::ir::TypeRef, type_paths: &HashMap<String, String>) -> String {
use crate::core::ir::{PrimitiveType, TypeRef};
match ty {
TypeRef::Primitive(p) => match p {
PrimitiveType::Bool => "bool",
PrimitiveType::U8 => "u8",
PrimitiveType::U16 => "u16",
PrimitiveType::U32 => "u32",
PrimitiveType::U64 => "u64",
PrimitiveType::I8 => "i8",
PrimitiveType::I16 => "i16",
PrimitiveType::I32 => "i32",
PrimitiveType::I64 => "i64",
PrimitiveType::F32 => "f32",
PrimitiveType::F64 => "f64",
PrimitiveType::Usize => "usize",
PrimitiveType::Isize => "isize",
}
.to_string(),
TypeRef::String => "String".to_string(),
TypeRef::Char => "char".to_string(),
TypeRef::Bytes => "Vec<u8>".to_string(),
TypeRef::Optional(inner) => format!("Option<{}>", format_type_ref(inner, type_paths)),
TypeRef::Vec(inner) => format!("Vec<{}>", format_type_ref(inner, type_paths)),
TypeRef::Map(k, v) => format!(
"std::collections::HashMap<{}, {}>",
format_type_ref(k, type_paths),
format_type_ref(v, type_paths)
),
TypeRef::Named(name) => type_paths.get(name.as_str()).cloned().unwrap_or_else(|| name.clone()),
TypeRef::Path => "std::path::PathBuf".to_string(),
TypeRef::Unit => "()".to_string(),
TypeRef::Json => "serde_json::Value".to_string(),
TypeRef::Duration => "std::time::Duration".to_string(),
}
}
pub fn format_return_type(
ty: &crate::core::ir::TypeRef,
error_type: Option<&str>,
type_paths: &HashMap<String, String>,
returns_ref: bool,
) -> String {
let inner = if returns_ref {
if let crate::core::ir::TypeRef::Vec(elem) = ty {
let elem_str = match elem.as_ref() {
crate::core::ir::TypeRef::String => "&str".to_string(),
crate::core::ir::TypeRef::Bytes => "&[u8]".to_string(),
crate::core::ir::TypeRef::Named(name) => {
let qualified = type_paths.get(name.as_str()).cloned().unwrap_or_else(|| name.clone());
format!("&{qualified}")
}
other => format_type_ref(other, type_paths),
};
format!("&[{elem_str}]")
} else {
format_type_ref(ty, type_paths)
}
} else {
format_type_ref(ty, type_paths)
};
match error_type {
Some(err) => format!("std::result::Result<{inner}, {err}>"),
None => inner,
}
}
pub fn format_param_type(param: &ParamDef, type_paths: &HashMap<String, String>) -> String {
use crate::core::ir::TypeRef;
let base = if param.is_ref {
let mutability = if param.is_mut { "mut " } else { "" };
match ¶m.ty {
TypeRef::String => format!("&{mutability}str"),
TypeRef::Bytes => format!("&{mutability}[u8]"),
TypeRef::Path => format!("&{mutability}std::path::Path"),
TypeRef::Vec(inner) => format!("&{mutability}[{}]", format_type_ref(inner, type_paths)),
TypeRef::Named(name) => {
let qualified = type_paths.get(name.as_str()).cloned().unwrap_or_else(|| name.clone());
format!("&{mutability}{qualified}")
}
TypeRef::Optional(inner) => {
let inner_type_str = match inner.as_ref() {
TypeRef::String => format!("&{mutability}str"),
TypeRef::Bytes => format!("&{mutability}[u8]"),
TypeRef::Path => format!("&{mutability}std::path::Path"),
TypeRef::Vec(v) => format!("&{mutability}[{}]", format_type_ref(v, type_paths)),
TypeRef::Named(name) => {
let qualified = type_paths.get(name.as_str()).cloned().unwrap_or_else(|| name.clone());
format!("&{mutability}{qualified}")
}
other => format_type_ref(other, type_paths),
};
return format!("Option<{inner_type_str}>");
}
other => format_type_ref(other, type_paths),
}
} else {
format_type_ref(¶m.ty, type_paths)
};
if param.optional {
format!("Option<{base}>")
} else {
base
}
}
pub fn format_param_type_with_lifetimes(
param: &ParamDef,
type_paths: &HashMap<String, String>,
lifetime_type_names: &HashSet<String>,
) -> String {
use crate::core::ir::TypeRef;
let base = if param.is_ref {
let mutability = if param.is_mut { "mut " } else { "" };
match ¶m.ty {
TypeRef::String => format!("&{mutability}str"),
TypeRef::Bytes => format!("&{mutability}[u8]"),
TypeRef::Path => format!("&{mutability}std::path::Path"),
TypeRef::Vec(inner) => format!("&{mutability}[{}]", format_type_ref(inner, type_paths)),
TypeRef::Named(name) => {
let qualified = type_paths.get(name.as_str()).cloned().unwrap_or_else(|| name.clone());
let qualified = if lifetime_type_names.contains(name.as_str()) {
format!("{qualified}<'_>")
} else {
qualified
};
format!("&{mutability}{qualified}")
}
TypeRef::Optional(inner) => {
let inner_type_str = match inner.as_ref() {
TypeRef::String => format!("&{mutability}str"),
TypeRef::Bytes => format!("&{mutability}[u8]"),
TypeRef::Path => format!("&{mutability}std::path::Path"),
TypeRef::Vec(v) => format!("&{mutability}[{}]", format_type_ref(v, type_paths)),
TypeRef::Named(name) => {
let qualified = type_paths.get(name.as_str()).cloned().unwrap_or_else(|| name.clone());
let qualified = if lifetime_type_names.contains(name.as_str()) {
format!("{qualified}<'_>")
} else {
qualified
};
format!("&{mutability}{qualified}")
}
other => format_type_ref(other, type_paths),
};
return format!("Option<{inner_type_str}>");
}
other => format_type_ref(other, type_paths),
}
} else {
format_type_ref(¶m.ty, type_paths)
};
if param.optional {
format!("Option<{base}>")
} else {
base
}
}
pub fn prim(p: &PrimitiveType) -> &'static str {
use PrimitiveType::*;
match p {
Bool => "bool",
U8 => "u8",
U16 => "u16",
U32 => "u32",
U64 => "u64",
I8 => "i8",
I16 => "i16",
I32 => "i32",
I64 => "i64",
F32 => "f32",
F64 => "f64",
Usize => "usize",
Isize => "isize",
}
}
pub fn bridge_param_type(ty: &TypeRef, ci: &str, is_ref: bool, tp: &HashMap<String, String>) -> String {
match ty {
TypeRef::Bytes if is_ref => "&[u8]".into(),
TypeRef::Bytes => "Vec<u8>".into(),
TypeRef::String if is_ref => "&str".into(),
TypeRef::String => "String".into(),
TypeRef::Path if is_ref => "&std::path::Path".into(),
TypeRef::Path => "std::path::PathBuf".into(),
TypeRef::Named(n) => {
let qualified = tp.get(n).cloned().unwrap_or_else(|| format!("{ci}::{n}"));
if is_ref { format!("&{qualified}") } else { qualified }
}
TypeRef::Vec(inner) => format!("Vec<{}>", bridge_param_type(inner, ci, false, tp)),
TypeRef::Optional(inner) => format!("Option<{}>", bridge_param_type(inner, ci, false, tp)),
TypeRef::Primitive(p) => prim(p).into(),
TypeRef::Unit => "()".into(),
TypeRef::Char => "char".into(),
TypeRef::Map(k, v) => format!(
"std::collections::HashMap<{}, {}>",
bridge_param_type(k, ci, false, tp),
bridge_param_type(v, ci, false, tp)
),
TypeRef::Json => "serde_json::Value".into(),
TypeRef::Duration => "std::time::Duration".into(),
}
}
pub fn visitor_param_type(ty: &TypeRef, is_ref: bool, optional: bool, tp: &HashMap<String, String>) -> String {
if optional && matches!(ty, TypeRef::String) && is_ref {
return "Option<&str>".to_string();
}
if is_ref {
if let TypeRef::Vec(inner) = ty {
let inner_str = bridge_param_type(inner, "", false, tp);
return format!("&[{inner_str}]");
}
}
bridge_param_type(ty, "", is_ref, tp)
}
pub fn to_camel_case(s: &str) -> String {
let mut result = String::new();
let mut capitalize_next = false;
for ch in s.chars() {
if ch == '_' {
capitalize_next = true;
} else if capitalize_next {
result.push(ch.to_ascii_uppercase());
capitalize_next = false;
} else {
result.push(ch);
}
}
result
}