/* 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
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
use super ::*;
/// Implements renaming of items in the CI via toml configuration.
/// Intended to be called by bindings to update the local names of items
/// to be generated but not touching names in the ffi we need to use.
use crate ::VisitMut;
use std::collections::HashMap;
pub fn rename(ci: &
mut ComponentInterface, renames: &HashMap<String, to
ml::Table>) {
let this_module_path = ci.crate_name().to_string();
ci.visit_mut(&TomlRenamer {
this_module_path,
renames,
})
}
struct TomlRenamer<'a> {
this_module_path: String,
renames: &'a HashMap<String, toml::Table>,
}
impl TomlRenamer<'_> {
fn new_name(&self , module_path: &str, name: &str) -> Option<String> {
self .renames
.get(module_path)
.and_then(|rename_table| rename_table.get(name))
.and_then(|v| v.as_str())
.map(|s| s.to_string())
}
}
impl VisitMut for TomlRenamer<'_> {
fn visit_record(&self , record: &mut Record) {
let module_path = &record.module_path;
let record_name = record.name().to_string();
// fields
for field in &mut record.fields {
let field_path = format!("{}.{}" , record_name, field.name);
if let Some(new_name) = self .new_name(module_path, &field_path) {
field.name = new_name;
}
}
// the record type itself
if let Some(new_name) = self .new_name(module_path, &record_name) {
record.name = new_name;
}
}
fn visit_object(&self , object: &mut Object) {
let module_path = &object.module_path;
if let Some(new_name) = self .new_name(module_path, object.name()) {
object.name = new_name;
}
}
fn visit_callback_interface(&self , iface: &mut CallbackInterface) {
let module_path = &iface.module_path;
if let Some(new_name) = self .new_name(module_path, &iface.name) {
iface.name = new_name;
}
}
fn visit_enum(&self , _is_error: bool, enum_: &mut Enum ) {
let module_path = &enum_.module_path;
let enum_name = enum_.name().to_string();
// enum variants
for variant in &mut enum_.variants {
let variant_name = variant.name.clone();
let variant_path = format!("{}.{}" , enum_name, variant_name);
for field in &mut variant.fields {
let field_path = format!("{}.{}" , variant_path, field.name);
if let Some(new_name) = self .new_name(module_path, &field_path) {
field.name = new_name;
}
}
if let Some(new_name) = self .new_name(module_path, &variant_path) {
variant.name = new_name;
}
}
// the enum type itself
if let Some(new_name) = self .new_name(module_path, &enum_name) {
enum_.name = new_name;
}
}
fn visit_type(&self , type_: &mut Type ) {
let module_path = type_.module_path().unwrap_or(&self .this_module_path);
let self_renames = self .renames.get(module_path);
type_.rename_recursive(&|name| {
self_renames
.and_then(|renames| renames.get(name))
.and_then(|value| value.as_str())
.unwrap_or(name)
.to_string()
});
}
fn visit_method(&self , object_name: &str, method: &mut Method) {
let method_name = format!("{}.{}" , object_name, method.name());
// Rename the method
if let Some(new_name) = self .new_name(&self .this_module_path, &method_name) {
method.name = new_name;
}
// args
for arg in &mut method.arguments {
let arg_path = format!("{}.{}" , method_name, arg.name);
if let Some(new_name) = self .new_name(&self .this_module_path, &arg_path) {
arg.name = new_name;
}
}
}
fn visit_constructor(&self , object_name: &str, constructor: &n style='color:red'>mut Constructor) {
// ctor is the same as a method.
let method_name = format!("{}.{}" , object_name, constructor.name());
if let Some(new_name) = self .new_name(&self .this_module_path, &method_name) {
constructor.name = new_name;
}
for arg in &mut constructor.arguments {
let arg_path = format!("{}.{}" , method_name, arg.name);
if let Some(new_name) = self .new_name(&self .this_module_path, &arg_path) {
arg.name = new_name;
}
}
}
fn visit_function(&self , function: &mut Function) {
let original_function_name = function.name.clone();
if let Some(new_name) = self .new_name(&self .this_module_path, &function.name) {
function.name = new_name;
}
// args
for arg in &mut function.arguments {
let arg_path = format!("{}.{}" , original_function_name, arg.name);
if let Some(new_name) = self .new_name(&self .this_module_path, &arg_path) {
arg.name = new_name;
}
}
}
fn visit_error_name(&self , name: &mut String) {
if let Some(new_name) = self .new_name(&self .this_module_path, name) {
*name = new_name;
}
}
}
#[ cfg(test)]
mod tests {
use super ::*;
use crate ::interface::{ComponentInterface, Enum , Function, Object, Record};
use uniffi_meta::{
EnumMetadata, EnumShape, FieldMetadata, FnMetadata, FnParamMetadata, ObjectImpl,
ObjectMetadata, RecordMetadata, Type , VariantMetadata,
};
fn create_test_ci() -> ComponentInterface {
let mut ci = ComponentInterface::new("test_crate" );
// Add test record with Option<OldEnum> field
let record_meta = RecordMetadata {
module_path: "test_crate" .to_string(),
name: "OldRecord" .to_string(),
remote: false ,
fields: vec![FieldMetadata {
name: "field" .to_string(),
ty: Type ::Optional {
inner_type: Box ::new(Type ::Enum {
module_path: "test_crate" .to_string(),
name: "OldEnum" .to_string(),
}),
},
default: None,
docstring: None,
}],
docstring: None,
};
let record = Record::try_from(record_meta).unwrap();
ci.add_record_definition(record).unwrap();
// Add test object using metadata
let object_meta = ObjectMetadata {
module_path: "test_crate" .to_string(),
name: "OldObject" .to_string(),
imp: ObjectImpl::Struct ,
remote: false ,
docstring: None,
};
let object = Object::from(object_meta);
ci.add_object_definition(object).unwrap();
// Add test enum with Option<OldRecord> variant
let enum_meta = EnumMetadata {
module_path: "test_crate" .to_string(),
name: "OldEnum" .to_string(),
shape: EnumShape::Enum ,
discr_type: None,
non_exhaustive: false ,
remote: false ,
variants: vec![VariantMetadata {
name: "WithRecord" .to_string(),
fields: vec![FieldMetadata {
name: "record" .to_string(),
ty: Type ::Optional {
inner_type: Box ::new(Type ::Record {
module_path: "test_crate" .to_string(),
name: "OldRecord" .to_string(),
}),
},
default: None,
docstring: None,
}],
docstring: None,
discr: None,
}],
docstring: None,
};
let enum_ = Enum ::try_from(enum_meta).unwrap();
ci.add_enum_definition(enum_).unwrap();
// Add test function with Option<OldRecord> argument
let function_meta = FnMetadata {
module_path: "test_crate" .to_string(),
name: "old_function" .to_string(),
is_async: false ,
inputs: vec![FnParamMetadata {
name: "arg" .to_string(),
ty: Type ::Optional {
inner_type: Box ::new(Type ::Record {
module_path: "test_crate" .to_string(),
name: "OldRecord" .to_string(),
}),
},
by_ref: false ,
optional: false ,
default: None,
}],
return_type: None,
throws: None,
checksum: None,
docstring: None,
};
let function = Function::from(function_meta);
ci.add_function_definition(function).unwrap();
ci
}
#[ test]
fn test_dot_notation_renaming() {
let mut ci = create_test_ci();
// Test dot notation for field and variant renaming
let toml_str = r#"
OldRecord = "NewRecord"
"OldRecord.field" = "new_field"
OldEnum = "NewEnum"
"OldEnum.WithRecord" = "WithNewRecord"
"OldEnum.WithRecord.record" = "new_record"
old_function = "new_function"
"old_function.arg" = "new_arg"
"#;
let renames: toml::Table = toml::from_str(toml_str).unwrap();
let mut renames_map = HashMap::new();
renames_map.insert("test_crate" .to_string(), renames);
rename(&mut ci, &renames_map);
// Check that types were renamed
assert_eq!(ci.record_definitions()[0 ].name(), "NewRecord" );
assert_eq!(ci.enum_definitions()[0 ].name(), "NewEnum" );
assert_eq!(ci.function_definitions()[0 ].name(), "new_function" );
// Check that field was renamed
assert_eq!(ci.record_definitions()[0 ].fields()[0 ].name, "new_field" );
// Check that enum variant was renamed
assert_eq!(ci.enum_definitions()[0 ].variants()[0 ].name, "WithNewRecord" );
// Check that variant field was renamed
assert_eq!(
ci.enum_definitions()[0 ].variants()[0 ].fields()[0 ].name,
"new_record"
);
// Check that function argument was renamed
assert_eq!(ci.function_definitions()[0 ].arguments()[0 ].name, "new_arg" );
}
#[ test]
fn test_callback_interface_renaming() {
use crate ::interface::callbacks::CallbackInterface;
use crate ::interface::ffi::FfiFunction;
let mut ci = ComponentInterface::new("test_crate" );
// Add a callback interface (trait)
let callback_interface = CallbackInterface {
name: "OldTrait" .to_string(),
module_path: "test_crate" .to_string(),
methods: vec![],
docstring: None,
ffi_init_callback: FfiFunction {
name: "init" .to_string(),
arguments: vec![],
return_type: None,
is_async: false ,
has_rust_call_status_arg: true ,
is_object_free_function: false ,
},
};
ci.callback_interfaces.push(callback_interface);
// Test callback interface renaming
let toml_str = r#"
OldTrait = "NewTrait"
"#;
let renames: toml::Table = toml::from_str(toml_str).unwrap();
let mut renames_map = HashMap::new();
renames_map.insert("test_crate" .to_string(), renames);
rename(&mut ci, &renames_map);
// Check that callback interface was renamed
assert_eq!(ci.callback_interfaces[0 ].name, "NewTrait" );
}
}
Messung V0.5 in Prozent C=93 H=100 G=96
¤ Dauer der Verarbeitung: 0.1 Sekunden
(vorverarbeitet am 2026-08-25)
¤
*© Formatika GbR, Deutschland