pub(crate) fn snake_to_camel(s: &str) -> String {
let mut out = String::with_capacity(s.len());
let mut upper_next = false;
for (i, c) in s.chars().enumerate() {
if c == '_' {
upper_next = true;
} else if upper_next {
out.extend(c.to_uppercase());
upper_next = false;
} else if i == 0 {
out.extend(c.to_lowercase());
} else {
out.push(c);
}
}
out
}
pub(crate) fn camel_to_screaming_snake(s: &str) -> String {
let mut out = String::with_capacity(s.len() + 2);
for (i, c) in s.chars().enumerate() {
if c.is_uppercase() && i > 0 {
out.push('_');
}
out.extend(c.to_uppercase());
}
out
}
pub(crate) fn is_unit(ty: &syn::Type) -> bool {
matches!(ty, syn::Type::Tuple(t) if t.elems.is_empty())
}
#[cfg(test)]
mod tests;
pub(crate) fn head_type(
t: &prebindgen_registry::flat::TypeRef,
) -> &prebindgen_registry::flat::TypeRef {
use prebindgen_registry::flat::TypeKind;
match t.kind() {
TypeKind::Ref { inner, .. } | TypeKind::Optional(inner) | TypeKind::Vec(inner) => {
head_type(inner)
}
_ => t,
}
}
pub(crate) fn head_name(t: &prebindgen_registry::flat::TypeRef) -> Option<String> {
use prebindgen_registry::flat::TypeKind;
Some(match t.kind() {
TypeKind::Named { id, .. } => id
.name
.rsplit("::")
.next()
.expect("a name has a last segment")
.to_string(),
TypeKind::Scalar(s) => s.as_str().to_string(),
TypeKind::Str => "str".to_string(),
TypeKind::String => "String".to_string(),
TypeKind::Optional(_) => "Option".to_string(),
TypeKind::Vec(_) => "Vec".to_string(),
TypeKind::Boxed(_) => "Box".to_string(),
TypeKind::Cow { .. } => "Cow".to_string(),
TypeKind::Uninit(_) => "MaybeUninit".to_string(),
TypeKind::Fallible { .. } => "Result".to_string(),
TypeKind::Ref { .. }
| TypeKind::Slice(_)
| TypeKind::Array { .. }
| TypeKind::Callback { .. }
| TypeKind::Unit => return None,
})
}