Source code
Revision control
Copy as Markdown
Other Tools
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
use heck::{ToShoutySnakeCase, ToSnakeCase, ToUpperCamelCase};
use once_cell::sync::Lazy;
use std::collections::HashSet;
use super::*;
// Taken from Python's `keyword.py` module.
static KEYWORDS: Lazy<HashSet<String>> = Lazy::new(|| {
let kwlist = vec![
"False",
"None",
"True",
"__peg_parser__",
"and",
"as",
"assert",
"async",
"await",
"break",
"class",
"continue",
"def",
"del",
"elif",
"else",
"except",
"finally",
"for",
"from",
"global",
"if",
"import",
"in",
"is",
"lambda",
"nonlocal",
"not",
"or",
"pass",
"raise",
"return",
"try",
"while",
"with",
"yield",
];
HashSet::from_iter(kwlist.into_iter().map(|s| s.to_string()))
});
/// Convert strings to follow Python naming guidelines
pub fn pass(namespace: &mut Namespace) -> Result<()> {
namespace.visit_mut(|struct_name: &mut FfiStructName| {
struct_name.0 = format!("_Uniffi{}", struct_name.0.to_upper_camel_case())
});
namespace.visit_mut(|function_type: &mut FfiFunctionTypeName| {
function_type.0 = format!("_UNIFFI_{}", function_type.0.to_shouty_snake_case())
});
namespace.visit_mut(|rec: &mut Record| {
rec.name = fixup_keyword(rec.name.to_upper_camel_case());
});
namespace.visit_mut(|e: &mut Enum| {
e.name = fixup_keyword(e.name.to_upper_camel_case());
match &e.shape {
EnumShape::Error { .. } => {
e.visit_mut(|v: &mut Variant| {
v.name = fixup_keyword(v.name.to_upper_camel_case());
});
}
_ => {
e.visit_mut(|v: &mut Variant| {
v.name = fixup_keyword(v.name.to_shouty_snake_case());
});
}
}
});
namespace.visit_mut(|int: &mut Interface| {
int.name = fixup_keyword(int.name.to_upper_camel_case());
});
namespace.visit_mut(|cbi: &mut CallbackInterface| {
cbi.name = fixup_keyword(cbi.name.to_upper_camel_case());
});
namespace.visit_mut(|custom: &mut CustomType| {
custom.name = fixup_keyword(custom.name.to_upper_camel_case());
});
namespace.visit_mut(|arg: &mut Argument| {
arg.name = fixup_keyword(arg.name.to_snake_case());
});
namespace.visit_mut(|field: &mut Field| {
field.name = fixup_keyword(field.name.to_snake_case());
});
namespace.visit_mut(|callable: &mut Callable| {
if callable.is_primary_constructor() {
callable.name = "__init__".to_string()
} else {
callable.name = fixup_keyword(callable.name.to_snake_case());
}
});
namespace.visit_mut(|ty: &mut Type| {
match ty {
Type::Enum { name, .. }
| Type::Record { name, .. }
| Type::Interface { name, .. }
| Type::CallbackInterface { name, .. }
| Type::Custom { name, .. } => {
*name = fixup_keyword(name.to_upper_camel_case());
}
_ => (),
};
});
namespace.try_visit_mut(|lit: &mut Literal| {
if let Literal::Enum(variant, ty) = lit {
match &mut ty.ty {
Type::Enum { name, .. } => {
*name = fixup_keyword(name.to_upper_camel_case());
// Assume enum literals are not error types and use `to_shouty_snake_case()`
// rather than `to_upper_camel_case()`
*variant = fixup_keyword(variant.to_shouty_snake_case());
}
type_kind => {
bail!("Invalid type for enum literal: {type_kind:?}")
}
}
}
Ok(())
})?;
Ok(())
}
/// Fixup a name by ensuring it's not a keyword
fn fixup_keyword(name: String) -> String {
if KEYWORDS.contains(&name) {
format!("_{name}")
} else {
name
}
}