Rust Bindings: Use typed parameters instead of void* in UNO bindings
Replace generic void* parameters with proper types (strings, primitives, structs) for better type safety and more idiomatic Rust code. Change-Id: Iced1c2de96564be7ec599f14bf1a685eaede2768 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/191477 Tested-by: Jenkins Reviewed-by: Stephan Bergmann <stephan.bergmann@collabora.com>
This commit is contained in:
committed by
Stephan Bergmann
parent
048761fb22
commit
86ade63863
@@ -618,7 +618,9 @@ void CppProducer::generateStructHeader(std::string_view name,
|
||||
.append(")")
|
||||
.endLine()
|
||||
.beginLine()
|
||||
.append("SAL_DLLPUBLIC_EXPORT void* ")
|
||||
.append("SAL_DLLPUBLIC_EXPORT ")
|
||||
.append(getStructGetterReturnType(member.type))
|
||||
.append(" ")
|
||||
.append(functionPrefix)
|
||||
.append("_get_")
|
||||
.append(member.name)
|
||||
@@ -641,7 +643,9 @@ void CppProducer::generateStructHeader(std::string_view name,
|
||||
.append(member.name)
|
||||
.append("(")
|
||||
.append(handleTypeName)
|
||||
.append(" handle, void* value);")
|
||||
.append(" handle, ")
|
||||
.append(getStructSetterParameterType(member.type))
|
||||
.append(" value);")
|
||||
.endLine();
|
||||
}
|
||||
file.endBlock().append("// extern \"C\"").endLine();
|
||||
@@ -963,7 +967,9 @@ void CppProducer::generateStructMemberAccessors(CppFile& file, std::string_view
|
||||
{
|
||||
// Generate getter implementation
|
||||
file.beginLine()
|
||||
.append("SAL_DLLPUBLIC_EXPORT void* ")
|
||||
.append("SAL_DLLPUBLIC_EXPORT ")
|
||||
.append(getStructGetterReturnType(member.type))
|
||||
.append(" ")
|
||||
.append(functionPrefix)
|
||||
.append("_get_")
|
||||
.append(member.name)
|
||||
@@ -978,12 +984,35 @@ void CppProducer::generateStructMemberAccessors(CppFile& file, std::string_view
|
||||
.append(className)
|
||||
.append("*>(handle);")
|
||||
.endLine()
|
||||
.beginLine()
|
||||
.append("return &(obj->")
|
||||
.append(member.name)
|
||||
.append(");")
|
||||
.endLine()
|
||||
.endBlock();
|
||||
.beginLine();
|
||||
|
||||
// Handle return value conversion based on type
|
||||
if (member.type == u"string")
|
||||
{
|
||||
// For string types, return pointer to the OUString object
|
||||
file.append("return &(obj->").append(member.name).append(");");
|
||||
}
|
||||
else if (member.type == u"any")
|
||||
{
|
||||
// For any types, return pointer to the Any
|
||||
file.append("return &(obj->").append(member.name).append(");");
|
||||
}
|
||||
else if (member.type == u"boolean" || member.type == u"byte" || member.type == u"short"
|
||||
|| member.type == u"unsigned short" || member.type == u"long"
|
||||
|| member.type == u"unsigned long" || member.type == u"hyper"
|
||||
|| member.type == u"unsigned hyper" || member.type == u"float"
|
||||
|| member.type == u"double")
|
||||
{
|
||||
// For primitive types, return pointer to the member for direct access
|
||||
file.append("return &(obj->").append(member.name).append(");");
|
||||
}
|
||||
else
|
||||
{
|
||||
// For other types, return pointer to member
|
||||
file.append("return &(obj->").append(member.name).append(");");
|
||||
}
|
||||
|
||||
file.endLine().endBlock();
|
||||
|
||||
// Generate setter implementation
|
||||
file.beginLine()
|
||||
@@ -993,7 +1022,9 @@ void CppProducer::generateStructMemberAccessors(CppFile& file, std::string_view
|
||||
.append(member.name)
|
||||
.append("(")
|
||||
.append(handleTypeName)
|
||||
.append(" handle, void* value)")
|
||||
.append(" handle, ")
|
||||
.append(getStructSetterParameterType(member.type))
|
||||
.append(" value)")
|
||||
.endLine()
|
||||
.beginBlock()
|
||||
.beginLine()
|
||||
@@ -1006,31 +1037,46 @@ void CppProducer::generateStructMemberAccessors(CppFile& file, std::string_view
|
||||
.append("obj->")
|
||||
.append(member.name);
|
||||
|
||||
// Check if this is a UNO interface type by checking the UNO type string
|
||||
// Handle assignment based on parameter type
|
||||
OUString unoType = member.type;
|
||||
SAL_INFO("codemaker", "Struct member " << member.name << " UNO type: " << unoType);
|
||||
|
||||
// UNO interface types start with "com.sun.star" and end with an interface name (typically starting with "X")
|
||||
// Examples: "com.sun.star.uno.XInterface", "com.sun.star.text.XText"
|
||||
bool isInterfaceType = (unoType.startsWith("com.sun.star.") && (unoType.lastIndexOf('.') != -1)
|
||||
&& (unoType.subView(unoType.lastIndexOf('.') + 1).starts_with('X')));
|
||||
|
||||
if (isInterfaceType)
|
||||
// Check if we're using typed primitive parameters (passed by value)
|
||||
if (unoType == u"boolean" || unoType == u"byte" || unoType == u"short"
|
||||
|| unoType == u"unsigned short" || unoType == u"long" || unoType == u"unsigned long"
|
||||
|| unoType == u"hyper" || unoType == u"unsigned hyper" || unoType == u"float"
|
||||
|| unoType == u"double")
|
||||
{
|
||||
SAL_INFO("codemaker", "Detected UNO interface type, using pointer assignment");
|
||||
// For interface types, assign the pointer directly without dereferencing
|
||||
// The C++ struct expects Reference<Interface>, but we assign the raw interface pointer
|
||||
file.append(" = reinterpret_cast<")
|
||||
.append(convertUnoTypeToCpp(unoType))
|
||||
.append("*>(value);");
|
||||
// For primitive types with typed parameters, assign directly (no dereferencing)
|
||||
file.append(" = value;");
|
||||
}
|
||||
else if (unoType == u"string")
|
||||
{
|
||||
// For string types, dereference the pointer to OUString
|
||||
file.append(" = *reinterpret_cast<const OUString*>(value);");
|
||||
}
|
||||
else if (unoType == u"any")
|
||||
{
|
||||
// For any types with typed parameters, dereference the uno_Any*
|
||||
file.append(" = *reinterpret_cast<const Any*>(value);");
|
||||
}
|
||||
else
|
||||
{
|
||||
SAL_INFO("codemaker", "Non-interface type, using dereferenced assignment");
|
||||
// For non-interface types, dereference the pointer as before
|
||||
file.append(" = *reinterpret_cast<const ")
|
||||
.append(convertUnoTypeToCpp(unoType))
|
||||
.append("*>(value);");
|
||||
// For other types (interfaces, structs, enums), use original logic with void*
|
||||
// Check if this is a UNO interface type using proper TypeManager classification
|
||||
if (isUnoInterface(unoType))
|
||||
{
|
||||
// For interface types, assign the pointer directly without dereferencing
|
||||
file.append(" = reinterpret_cast<")
|
||||
.append(convertUnoTypeToCpp(unoType))
|
||||
.append("*>(value);");
|
||||
}
|
||||
else
|
||||
{
|
||||
// For non-interface types, dereference the pointer
|
||||
file.append(" = *reinterpret_cast<const ")
|
||||
.append(convertUnoTypeToCpp(unoType))
|
||||
.append("*>(value);");
|
||||
}
|
||||
}
|
||||
file.endLine().endBlock().beginLine().append("").endLine();
|
||||
}
|
||||
@@ -1435,10 +1481,13 @@ void CppProducer::generateInterfaceHeader(std::string_view name,
|
||||
.append(handleTypeName)
|
||||
.append(" handle");
|
||||
|
||||
// Add parameters
|
||||
// Add typed parameters instead of void*
|
||||
for (const auto& param : method.parameters)
|
||||
{
|
||||
file.append(", void* ").append(param.name);
|
||||
file.append(", ")
|
||||
.append(getTypedParameterType(param.type, param.direction))
|
||||
.append(" ")
|
||||
.append(param.name);
|
||||
}
|
||||
|
||||
file.append(");");
|
||||
@@ -1677,10 +1726,13 @@ void CppProducer::generateSingleInterfaceMethod(CppFile& file, std::string_view
|
||||
.append(handleTypeName)
|
||||
.append(" handle");
|
||||
|
||||
// Add parameters
|
||||
// Add typed parameters instead of void*
|
||||
for (const auto& param : method.parameters)
|
||||
{
|
||||
file.append(", void* ").append(param.name);
|
||||
file.append(", ")
|
||||
.append(getTypedParameterType(param.type, param.direction))
|
||||
.append(" ")
|
||||
.append(param.name);
|
||||
}
|
||||
|
||||
file.append(")").endLine().beginBlock();
|
||||
@@ -1850,70 +1902,62 @@ void CppProducer::generateActualMethodCall(CppFile& file,
|
||||
{
|
||||
if (isInputOnly)
|
||||
{
|
||||
// Input parameter: convert rtl_uString* to OUString object
|
||||
file.append("OUString(static_cast<rtl_uString*>(").append(param.name).append("))");
|
||||
// Input parameter: direct rtl_uString* to OUString conversion (no casting needed)
|
||||
file.append("OUString(").append(param.name).append(")");
|
||||
}
|
||||
else
|
||||
{
|
||||
// Output parameter: needs OUString reference for binding
|
||||
file.append("*reinterpret_cast<OUString*>(").append(param.name).append(")");
|
||||
// Output parameter: rtl_uString** needs dereferencing to OUString reference
|
||||
file.append("*reinterpret_cast<OUString*>(*").append(param.name).append(")");
|
||||
}
|
||||
}
|
||||
else if (paramType == u"any")
|
||||
{
|
||||
if (isInputOnly)
|
||||
{
|
||||
// Input parameter: dereference uno_Any* to get Any& (Any inherits from uno_Any)
|
||||
file.append("*reinterpret_cast<const Any*>(").append(param.name).append(")");
|
||||
}
|
||||
else
|
||||
file.append("*reinterpret_cast<Any*>(").append(param.name).append(")");
|
||||
{
|
||||
// Output parameter: uno_Any** needs dereferencing to Any reference
|
||||
file.append("*reinterpret_cast<Any*>(*").append(param.name).append(")");
|
||||
}
|
||||
}
|
||||
else if (paramType == u"boolean")
|
||||
// Handle all primitive types with typed parameter support
|
||||
else if (paramType == u"boolean" || paramType == u"byte" || paramType == u"short"
|
||||
|| paramType == u"unsigned short" || paramType == u"long"
|
||||
|| paramType == u"unsigned long" || paramType == u"hyper"
|
||||
|| paramType == u"unsigned hyper" || paramType == u"float"
|
||||
|| paramType == u"double")
|
||||
{
|
||||
if (isInputOnly)
|
||||
file.append("*reinterpret_cast<const sal_Bool*>(").append(param.name).append(")");
|
||||
// Check if this primitive type is using typed parameters
|
||||
OString primitiveType = mapUnoPrimitiveToSal(resolveTypedef(paramType));
|
||||
if (!primitiveType.isEmpty())
|
||||
{
|
||||
// Typed parameter approach - direct value for input, dereference pointer for input/output
|
||||
if (isInputOnly)
|
||||
file.append(param.name); // Direct value (sal_Bool, sal_Int32, double, etc.)
|
||||
else
|
||||
file.append("*").append(
|
||||
param.name); // Dereference pointer (sal_Bool*, sal_Int32*, double*, etc.)
|
||||
}
|
||||
else
|
||||
file.append("*reinterpret_cast<sal_Bool*>(").append(param.name).append(")");
|
||||
}
|
||||
else if (paramType == u"byte")
|
||||
{
|
||||
if (isInputOnly)
|
||||
file.append("*reinterpret_cast<const sal_Int8*>(").append(param.name).append(")");
|
||||
else
|
||||
file.append("*reinterpret_cast<sal_Int8*>(").append(param.name).append(")");
|
||||
}
|
||||
else if (paramType == u"short")
|
||||
{
|
||||
if (isInputOnly)
|
||||
file.append("*reinterpret_cast<const sal_Int16*>(").append(param.name).append(")");
|
||||
else
|
||||
file.append("*reinterpret_cast<sal_Int16*>(").append(param.name).append(")");
|
||||
}
|
||||
else if (paramType == u"long")
|
||||
{
|
||||
if (isInputOnly)
|
||||
file.append("*reinterpret_cast<const sal_Int32*>(").append(param.name).append(")");
|
||||
else
|
||||
file.append("*reinterpret_cast<sal_Int32*>(").append(param.name).append(")");
|
||||
}
|
||||
else if (paramType == u"hyper")
|
||||
{
|
||||
if (isInputOnly)
|
||||
file.append("*reinterpret_cast<const sal_Int64*>(").append(param.name).append(")");
|
||||
else
|
||||
file.append("*reinterpret_cast<sal_Int64*>(").append(param.name).append(")");
|
||||
}
|
||||
else if (paramType == u"float")
|
||||
{
|
||||
if (isInputOnly)
|
||||
file.append("*reinterpret_cast<const float*>(").append(param.name).append(")");
|
||||
else
|
||||
file.append("*reinterpret_cast<float*>(").append(param.name).append(")");
|
||||
}
|
||||
else if (paramType == u"double")
|
||||
{
|
||||
if (isInputOnly)
|
||||
file.append("*reinterpret_cast<const double*>(").append(param.name).append(")");
|
||||
else
|
||||
file.append("*reinterpret_cast<double*>(").append(param.name).append(")");
|
||||
{
|
||||
// Fallback to void* approach (shouldn't happen for primitives, but just in case)
|
||||
if (isInputOnly)
|
||||
file.append("*reinterpret_cast<const ")
|
||||
.append(primitiveType)
|
||||
.append("*>(")
|
||||
.append(param.name)
|
||||
.append(")");
|
||||
else
|
||||
file.append("*reinterpret_cast<")
|
||||
.append(primitiveType)
|
||||
.append("*>(")
|
||||
.append(param.name)
|
||||
.append(")");
|
||||
}
|
||||
}
|
||||
else if (paramType == u"type")
|
||||
{
|
||||
@@ -2265,6 +2309,142 @@ OString CppProducer::getCppTypeName(std::u16string_view unoType) const
|
||||
return "void*"_ostr; // Default to void* for unknown types
|
||||
}
|
||||
|
||||
OString CppProducer::getTypedParameterType(
|
||||
std::u16string_view unoType,
|
||||
unoidl::InterfaceTypeEntity::Method::Parameter::Direction direction) const
|
||||
{
|
||||
// Handle string types with typed parameters
|
||||
if (unoType == u"string")
|
||||
{
|
||||
bool isInputOnly
|
||||
= (direction == unoidl::InterfaceTypeEntity::Method::Parameter::DIRECTION_IN);
|
||||
if (isInputOnly)
|
||||
{
|
||||
// Input string: pass as rtl_uString* (no const to avoid casting)
|
||||
return "rtl_uString*"_ostr;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Input/output string: pass as rtl_uString** (modifiable)
|
||||
return "rtl_uString**"_ostr;
|
||||
}
|
||||
}
|
||||
|
||||
// Handle any types with typed parameters
|
||||
if (unoType == u"any")
|
||||
{
|
||||
bool isInputOnly
|
||||
= (direction == unoidl::InterfaceTypeEntity::Method::Parameter::DIRECTION_IN);
|
||||
if (isInputOnly)
|
||||
{
|
||||
// Input any: pass as uno_Any* (no const to avoid casting)
|
||||
return "uno_Any*"_ostr;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Input/output any: pass as uno_Any** (modifiable)
|
||||
return "uno_Any**"_ostr;
|
||||
}
|
||||
}
|
||||
|
||||
// Only use typed parameters for basic primitive types (not typedefs)
|
||||
// This ensures we don't break existing null-checking logic for complex types
|
||||
if (unoType == u"boolean" || unoType == u"byte" || unoType == u"short"
|
||||
|| unoType == u"unsigned short" || unoType == u"long" || unoType == u"unsigned long"
|
||||
|| unoType == u"hyper" || unoType == u"unsigned hyper" || unoType == u"float"
|
||||
|| unoType == u"double")
|
||||
{
|
||||
OString primitiveType = mapUnoPrimitiveToSal(unoType);
|
||||
if (!primitiveType.isEmpty())
|
||||
{
|
||||
bool isInputOnly
|
||||
= (direction == unoidl::InterfaceTypeEntity::Method::Parameter::DIRECTION_IN);
|
||||
if (isInputOnly)
|
||||
{
|
||||
// Input parameters: pass by value (sal_Bool, sal_Int32, etc.)
|
||||
return primitiveType;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Input/output parameters: pass by pointer (sal_Bool*, sal_Int32*, etc.)
|
||||
return primitiveType + "*";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// For all other types (typedefs, structs, enums, interfaces, sequences), use void*
|
||||
// This maintains compatibility with existing null-checking and casting logic
|
||||
return "void*"_ostr;
|
||||
}
|
||||
|
||||
OString CppProducer::getStructGetterReturnType(std::u16string_view unoType) const
|
||||
{
|
||||
// Struct getters return a pointer to the member data (like output parameters)
|
||||
// Use the same logic as getTypedParameterType with direction = OUT
|
||||
|
||||
// Handle string types
|
||||
if (unoType == u"string")
|
||||
{
|
||||
return "void*"_ostr; // Return pointer to string for compatibility
|
||||
}
|
||||
|
||||
// Handle any types
|
||||
if (unoType == u"any")
|
||||
{
|
||||
return "uno_Any*"_ostr; // Return pointer to Any for direct access
|
||||
}
|
||||
|
||||
// Handle primitive types
|
||||
if (unoType == u"boolean" || unoType == u"byte" || unoType == u"short"
|
||||
|| unoType == u"unsigned short" || unoType == u"long" || unoType == u"unsigned long"
|
||||
|| unoType == u"hyper" || unoType == u"unsigned hyper" || unoType == u"float"
|
||||
|| unoType == u"double")
|
||||
{
|
||||
OString primitiveType = mapUnoPrimitiveToSal(unoType);
|
||||
if (!primitiveType.isEmpty())
|
||||
{
|
||||
return primitiveType + "*"; // Return pointer to primitive type
|
||||
}
|
||||
}
|
||||
|
||||
// For all other types (typedefs, structs, enums, interfaces, sequences), use void*
|
||||
return "void*"_ostr;
|
||||
}
|
||||
|
||||
OString CppProducer::getStructSetterParameterType(std::u16string_view unoType) const
|
||||
{
|
||||
// Struct setters take the value to set (like input parameters)
|
||||
// Use the same logic as getTypedParameterType with direction = IN
|
||||
|
||||
// Handle string types
|
||||
if (unoType == u"string")
|
||||
{
|
||||
return "rtl_uString*"_ostr; // Take string pointer for compatibility
|
||||
}
|
||||
|
||||
// Handle any types
|
||||
if (unoType == u"any")
|
||||
{
|
||||
return "uno_Any*"_ostr; // Take Any pointer directly
|
||||
}
|
||||
|
||||
// Handle primitive types
|
||||
if (unoType == u"boolean" || unoType == u"byte" || unoType == u"short"
|
||||
|| unoType == u"unsigned short" || unoType == u"long" || unoType == u"unsigned long"
|
||||
|| unoType == u"hyper" || unoType == u"unsigned hyper" || unoType == u"float"
|
||||
|| unoType == u"double")
|
||||
{
|
||||
OString primitiveType = mapUnoPrimitiveToSal(unoType);
|
||||
if (!primitiveType.isEmpty())
|
||||
{
|
||||
return primitiveType; // Take primitive type by value
|
||||
}
|
||||
}
|
||||
|
||||
// For all other types
|
||||
return "void*"_ostr;
|
||||
}
|
||||
|
||||
OString CppProducer::convertBasicType(const OString& typeName)
|
||||
{
|
||||
OString result = typeName;
|
||||
|
||||
@@ -149,6 +149,11 @@ private:
|
||||
OString convertUnoTypeToCpp(std::u16string_view unoType) const;
|
||||
std::string convertTemplateArguments(const std::string& unoType) const;
|
||||
OString getCppTypeName(std::u16string_view unoType) const;
|
||||
OString getTypedParameterType(
|
||||
std::u16string_view unoType,
|
||||
unoidl::InterfaceTypeEntity::Method::Parameter::Direction direction) const;
|
||||
OString getStructGetterReturnType(std::u16string_view unoType) const;
|
||||
OString getStructSetterParameterType(std::u16string_view unoType) const;
|
||||
OString getRustFFITypeName(std::u16string_view unoType) const;
|
||||
static OString mapUnoPrimitiveToSal(std::u16string_view unoType);
|
||||
OUString resolveTypedef(std::u16string_view unoType) const;
|
||||
|
||||
@@ -232,6 +232,10 @@ void RustProducer::generateStructImplementation(
|
||||
|
||||
generateStructConstructor(file, externFunctionPrefix);
|
||||
generateStructFromPtr(file, externFunctionPrefix);
|
||||
|
||||
// Generate as_ptr method
|
||||
generateStructAsPtr(file);
|
||||
|
||||
generateStructAccessors(file, entity, externFunctionPrefix);
|
||||
|
||||
file.endBlock();
|
||||
@@ -305,6 +309,21 @@ void RustProducer::generateStructFromPtr(RustFile& file, std::string_view extern
|
||||
.endBlock();
|
||||
}
|
||||
|
||||
void RustProducer::generateStructAsPtr(RustFile& file)
|
||||
{
|
||||
file.beginLine()
|
||||
.append("")
|
||||
.endLine()
|
||||
.beginLine()
|
||||
.append("pub fn as_ptr(&self) -> *mut c_void")
|
||||
.endLine()
|
||||
.beginBlock()
|
||||
.beginLine()
|
||||
.append("self.ptr")
|
||||
.endLine()
|
||||
.endBlock();
|
||||
}
|
||||
|
||||
void RustProducer::generateStructAccessors(
|
||||
RustFile& file, const rtl::Reference<unoidl::PlainStructTypeEntity>& entity,
|
||||
std::string_view externFunctionPrefix)
|
||||
@@ -313,58 +332,139 @@ void RustProducer::generateStructAccessors(
|
||||
for (const auto& member : entity->getDirectMembers())
|
||||
{
|
||||
OString memberName = u2b(member.name); // Use original case, not snake_case
|
||||
std::u16string_view memberType = member.type;
|
||||
|
||||
generateStructMemberGetter(file, memberName, externFunctionPrefix);
|
||||
generateStructMemberSetter(file, memberName, externFunctionPrefix);
|
||||
generateStructMemberGetter(file, memberName, memberType, externFunctionPrefix);
|
||||
generateStructMemberSetter(file, memberName, memberType, externFunctionPrefix);
|
||||
}
|
||||
}
|
||||
|
||||
void RustProducer::generateStructMemberGetter(RustFile& file, std::string_view memberName,
|
||||
std::u16string_view memberType,
|
||||
std::string_view externFunctionPrefix)
|
||||
{
|
||||
OString returnType = getRustStructGetterReturnType(memberType);
|
||||
|
||||
file.beginLine()
|
||||
.append("")
|
||||
.endLine()
|
||||
.beginLine()
|
||||
.append("pub fn get_")
|
||||
.append(memberName)
|
||||
.append("(&self) -> *mut c_void {")
|
||||
.append("(&self) -> ")
|
||||
.append(returnType)
|
||||
.append(" {")
|
||||
.endLine()
|
||||
.extraIndent()
|
||||
.beginLine()
|
||||
.append("unsafe { ")
|
||||
.append(externFunctionPrefix)
|
||||
.append("_get_")
|
||||
.append(memberName)
|
||||
.append("(self.ptr) }")
|
||||
.endLine()
|
||||
.beginLine()
|
||||
.append("}")
|
||||
.endLine();
|
||||
.beginLine();
|
||||
|
||||
// Handle conversion based on type
|
||||
if (memberType == u"string")
|
||||
{
|
||||
// String type - convert from FFI to high-level type
|
||||
file.append("unsafe { crate::core::OUString::from_raw(")
|
||||
.append(externFunctionPrefix)
|
||||
.append("_get_")
|
||||
.append(memberName)
|
||||
.append("(self.ptr)) }");
|
||||
}
|
||||
else if (memberType == u"any")
|
||||
{
|
||||
// Any type - convert from FFI to high-level type
|
||||
file.append("unsafe { crate::core::Any::from_raw(std::ptr::read(")
|
||||
.append(externFunctionPrefix)
|
||||
.append("_get_")
|
||||
.append(memberName)
|
||||
.append("(self.ptr) as *const crate::ffi::uno_any::uno_Any)) }");
|
||||
}
|
||||
else if (memberType == u"boolean" || memberType == u"byte" || memberType == u"short"
|
||||
|| memberType == u"unsigned short" || memberType == u"long"
|
||||
|| memberType == u"unsigned long" || memberType == u"hyper"
|
||||
|| memberType == u"unsigned hyper" || memberType == u"float"
|
||||
|| memberType == u"double")
|
||||
{
|
||||
// Primitive types - dereference the pointer returned from FFI
|
||||
file.append("unsafe { *")
|
||||
.append(externFunctionPrefix)
|
||||
.append("_get_")
|
||||
.append(memberName)
|
||||
.append("(self.ptr) }");
|
||||
}
|
||||
else
|
||||
{
|
||||
// Other types - return raw pointer
|
||||
file.append("unsafe { ")
|
||||
.append(externFunctionPrefix)
|
||||
.append("_get_")
|
||||
.append(memberName)
|
||||
.append("(self.ptr) }");
|
||||
}
|
||||
|
||||
file.endLine().beginLine().append("}").endLine();
|
||||
}
|
||||
|
||||
void RustProducer::generateStructMemberSetter(RustFile& file, std::string_view memberName,
|
||||
std::u16string_view memberType,
|
||||
std::string_view externFunctionPrefix)
|
||||
{
|
||||
OString parameterType = getRustStructSetterParameterType(memberType);
|
||||
|
||||
file.beginLine()
|
||||
.append("")
|
||||
.endLine()
|
||||
.beginLine()
|
||||
.append("pub fn set_")
|
||||
.append(memberName)
|
||||
.append("(&mut self, value: *mut c_void) {")
|
||||
.append("(&mut self, value: ")
|
||||
.append(parameterType)
|
||||
.append(") {")
|
||||
.endLine()
|
||||
.extraIndent()
|
||||
.beginLine()
|
||||
.append("unsafe { ")
|
||||
.append(externFunctionPrefix)
|
||||
.append("_set_")
|
||||
.append(memberName)
|
||||
.append("(self.ptr, value) }")
|
||||
.endLine()
|
||||
.beginLine()
|
||||
.append("}")
|
||||
.endLine();
|
||||
.beginLine();
|
||||
|
||||
// Handle conversion based on type
|
||||
if (memberType == u"string")
|
||||
{
|
||||
// String type - convert from high-level to FFI type
|
||||
file.append("unsafe { ")
|
||||
.append(externFunctionPrefix)
|
||||
.append("_set_")
|
||||
.append(memberName)
|
||||
.append("(self.ptr, value.as_ptr()) }");
|
||||
}
|
||||
else if (memberType == u"any")
|
||||
{
|
||||
// Any type - convert from high-level to FFI type
|
||||
file.append("unsafe { ")
|
||||
.append(externFunctionPrefix)
|
||||
.append("_set_")
|
||||
.append(memberName)
|
||||
.append("(self.ptr, value.as_ptr()) }");
|
||||
}
|
||||
else if (memberType == u"boolean" || memberType == u"byte" || memberType == u"short"
|
||||
|| memberType == u"unsigned short" || memberType == u"long"
|
||||
|| memberType == u"unsigned long" || memberType == u"hyper"
|
||||
|| memberType == u"unsigned hyper" || memberType == u"float"
|
||||
|| memberType == u"double")
|
||||
{
|
||||
// Primitive types - pass by value directly
|
||||
file.append("unsafe { ")
|
||||
.append(externFunctionPrefix)
|
||||
.append("_set_")
|
||||
.append(memberName)
|
||||
.append("(self.ptr, value) }");
|
||||
}
|
||||
else
|
||||
{
|
||||
// Other types - pass raw pointer through
|
||||
file.append("unsafe { ")
|
||||
.append(externFunctionPrefix)
|
||||
.append("_set_")
|
||||
.append(memberName)
|
||||
.append("(self.ptr, value) }");
|
||||
}
|
||||
|
||||
file.endLine().beginLine().append("}").endLine();
|
||||
}
|
||||
|
||||
void RustProducer::generateStructDropTrait(
|
||||
@@ -453,19 +553,26 @@ void RustProducer::generateStructMemberExternDeclarations(
|
||||
for (const auto& member : entity->getDirectMembers())
|
||||
{
|
||||
OString memberName = u2b(member.name); // Use original case, not snake_case
|
||||
OString getterReturnType = getRustStructExternGetterReturnType(member.type);
|
||||
OString setterParamType = getRustStructExternSetterParameterType(member.type);
|
||||
|
||||
file.beginLine()
|
||||
.append("fn ")
|
||||
.append(externFunctionPrefix)
|
||||
.append("_get_")
|
||||
.append(memberName)
|
||||
.append("(ptr: *mut c_void) -> *mut c_void;")
|
||||
.append("(ptr: *mut c_void) -> ")
|
||||
.append(getterReturnType)
|
||||
.append(";")
|
||||
.endLine()
|
||||
.beginLine()
|
||||
.append("fn ")
|
||||
.append(externFunctionPrefix)
|
||||
.append("_set_")
|
||||
.append(memberName)
|
||||
.append("(ptr: *mut c_void, value: *mut c_void);")
|
||||
.append("(ptr: *mut c_void, value: ")
|
||||
.append(setterParamType)
|
||||
.append(");")
|
||||
.endLine();
|
||||
}
|
||||
}
|
||||
@@ -691,10 +798,13 @@ void RustProducer::generateInterfaceMethodWrappers(
|
||||
.append(rustMethodName)
|
||||
.append("(&self");
|
||||
|
||||
// All parameters are opaque void pointers
|
||||
// Parameters with typed support for primitives
|
||||
for (const auto& param : method.parameters)
|
||||
{
|
||||
file.append(", ").append(param.name).append(": *mut c_void");
|
||||
file.append(", ")
|
||||
.append(param.name)
|
||||
.append(": ")
|
||||
.append(getRustParameterType(param.type, param.direction));
|
||||
}
|
||||
|
||||
file.append(") -> ")
|
||||
@@ -716,7 +826,8 @@ void RustProducer::generateInterfaceMethodWrappers(
|
||||
|
||||
for (const auto& param : method.parameters)
|
||||
{
|
||||
file.append(", ").append(param.name);
|
||||
file.append(", ").append(
|
||||
convertRustParameterForFFICall(param.type, u2b(param.name), param.direction));
|
||||
}
|
||||
|
||||
file.append(") };").endLine();
|
||||
@@ -733,7 +844,8 @@ void RustProducer::generateInterfaceMethodWrappers(
|
||||
|
||||
for (const auto& param : method.parameters)
|
||||
{
|
||||
file.append(", ").append(param.name);
|
||||
file.append(", ").append(
|
||||
convertRustParameterForFFICall(param.type, u2b(param.name), param.direction));
|
||||
}
|
||||
|
||||
file.append(") };").endLine();
|
||||
@@ -945,7 +1057,10 @@ void RustProducer::generateInterfaceExternDeclarations(
|
||||
|
||||
for (const auto& param : method.parameters)
|
||||
{
|
||||
file.append(", ").append(param.name).append(": *mut c_void");
|
||||
file.append(", ")
|
||||
.append(param.name)
|
||||
.append(": ")
|
||||
.append(getRustExternParameterType(param.type, param.direction));
|
||||
}
|
||||
|
||||
file.append(") -> ");
|
||||
@@ -1350,6 +1465,246 @@ OString RustProducer::getRustReturnType(std::u16string_view unoType) const
|
||||
return getRustWrapperTypeName(unoType);
|
||||
}
|
||||
|
||||
OString RustProducer::getRustParameterType(
|
||||
std::u16string_view unoType,
|
||||
unoidl::InterfaceTypeEntity::Method::Parameter::Direction direction) const
|
||||
{
|
||||
// Handle string types with typed parameters (high-level Rust API)
|
||||
if (unoType == u"string")
|
||||
{
|
||||
bool isInputOnly
|
||||
= (direction == unoidl::InterfaceTypeEntity::Method::Parameter::DIRECTION_IN);
|
||||
if (isInputOnly)
|
||||
{
|
||||
// Input string: take high-level OUString in public API
|
||||
return "crate::core::OUString"_ostr;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Input/output string: still use raw pointer for output parameters
|
||||
return "*mut *mut crate::ffi::rtl_string::rtl_uString"_ostr;
|
||||
}
|
||||
}
|
||||
|
||||
// Handle any types with typed parameters (high-level Rust API)
|
||||
if (unoType == u"any")
|
||||
{
|
||||
bool isInputOnly
|
||||
= (direction == unoidl::InterfaceTypeEntity::Method::Parameter::DIRECTION_IN);
|
||||
if (isInputOnly)
|
||||
{
|
||||
// Input any: take high-level Any in public API
|
||||
return "crate::core::Any"_ostr;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Input/output any: still use raw pointer for output parameters
|
||||
return "*mut *mut crate::ffi::uno_any::uno_Any"_ostr;
|
||||
}
|
||||
}
|
||||
|
||||
// Handle struct types with typed parameters (high-level Rust API)
|
||||
if (isUnoStruct(unoType))
|
||||
{
|
||||
bool isInputOnly
|
||||
= (direction == unoidl::InterfaceTypeEntity::Method::Parameter::DIRECTION_IN);
|
||||
if (isInputOnly)
|
||||
{
|
||||
// Input struct: take high-level generated struct in public API
|
||||
OString rustType = u2b(unoType);
|
||||
if (rustType.indexOf('.') != -1)
|
||||
{
|
||||
// Convert dots to :: for module path
|
||||
OString modulePath = rustType.replaceAll("."_ostr, "::"_ostr);
|
||||
|
||||
// Extract simple type name
|
||||
sal_Int32 lastDot = rustType.lastIndexOf('.');
|
||||
if (lastDot != -1)
|
||||
{
|
||||
OString simpleName = rustType.copy(lastDot + 1);
|
||||
return "crate::generated::rustmaker::" + modulePath + "::" + simpleName;
|
||||
}
|
||||
}
|
||||
// Fallback for simple struct names without namespace
|
||||
return "crate::generated::rustmaker::" + rustType;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Input/output struct: still use raw pointer for output parameters
|
||||
return "*mut c_void"_ostr;
|
||||
}
|
||||
}
|
||||
|
||||
// Handle interface types with typed parameters (high-level Rust API)
|
||||
if (isUnoInterface(unoType))
|
||||
{
|
||||
bool isInputOnly
|
||||
= (direction == unoidl::InterfaceTypeEntity::Method::Parameter::DIRECTION_IN);
|
||||
if (isInputOnly)
|
||||
{
|
||||
// Input interface: take high-level generated interface in public API
|
||||
OString rustType = u2b(unoType);
|
||||
if (rustType.indexOf('.') != -1)
|
||||
{
|
||||
// Convert dots to :: for module path
|
||||
OString modulePath = rustType.replaceAll("."_ostr, "::"_ostr);
|
||||
|
||||
// Extract simple type name
|
||||
sal_Int32 lastDot = rustType.lastIndexOf('.');
|
||||
if (lastDot != -1)
|
||||
{
|
||||
OString simpleName = rustType.copy(lastDot + 1);
|
||||
return "crate::generated::rustmaker::" + modulePath + "::" + simpleName;
|
||||
}
|
||||
}
|
||||
// Fallback for simple interface names without namespace
|
||||
return "crate::generated::rustmaker::" + rustType;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Input/output interface: still use raw pointer for output parameters
|
||||
return "*mut c_void"_ostr;
|
||||
}
|
||||
}
|
||||
|
||||
// Only use typed parameters for basic primitive types (matching CppProducer approach)
|
||||
// This ensures we don't break existing logic for complex types
|
||||
if (unoType == u"boolean" || unoType == u"byte" || unoType == u"short"
|
||||
|| unoType == u"unsigned short" || unoType == u"long" || unoType == u"unsigned long"
|
||||
|| unoType == u"hyper" || unoType == u"unsigned hyper" || unoType == u"float"
|
||||
|| unoType == u"double")
|
||||
{
|
||||
// Get the Rust primitive type
|
||||
OString rustPrimitiveType = getRustWrapperTypeName(unoType);
|
||||
if (!rustPrimitiveType.isEmpty())
|
||||
{
|
||||
bool isInputOnly
|
||||
= (direction == unoidl::InterfaceTypeEntity::Method::Parameter::DIRECTION_IN);
|
||||
if (isInputOnly)
|
||||
{
|
||||
// Input parameters: pass by value (u8 for boolean, i32 for long, etc.)
|
||||
return rustPrimitiveType;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Input/output parameters: pass by mutable pointer (*mut u8, *mut i32, etc.)
|
||||
return "*mut " + rustPrimitiveType;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// For all other types (typedefs, structs, enums, interfaces, sequences), use void*
|
||||
// This maintains compatibility with existing null-checking and casting logic
|
||||
return "*mut c_void"_ostr;
|
||||
}
|
||||
|
||||
OString RustProducer::getRustExternParameterType(
|
||||
std::u16string_view unoType,
|
||||
unoidl::InterfaceTypeEntity::Method::Parameter::Direction direction) const
|
||||
{
|
||||
// Handle string types with C-compatible FFI parameters (different from high-level API)
|
||||
if (unoType == u"string")
|
||||
{
|
||||
bool isInputOnly
|
||||
= (direction == unoidl::InterfaceTypeEntity::Method::Parameter::DIRECTION_IN);
|
||||
if (isInputOnly)
|
||||
{
|
||||
// Input string: pass as C-compatible pointer for FFI
|
||||
return "*const crate::ffi::rtl_string::rtl_uString"_ostr;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Input/output string: pass as mutable pointer for output parameters
|
||||
return "*mut *mut crate::ffi::rtl_string::rtl_uString"_ostr;
|
||||
}
|
||||
}
|
||||
|
||||
// Handle any types with C-compatible FFI parameters (different from high-level API)
|
||||
if (unoType == u"any")
|
||||
{
|
||||
bool isInputOnly
|
||||
= (direction == unoidl::InterfaceTypeEntity::Method::Parameter::DIRECTION_IN);
|
||||
if (isInputOnly)
|
||||
{
|
||||
// Input any: pass as C-compatible pointer for FFI
|
||||
return "*const crate::ffi::uno_any::uno_Any"_ostr;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Input/output any: pass as mutable pointer for output parameters
|
||||
return "*mut *mut crate::ffi::uno_any::uno_Any"_ostr;
|
||||
}
|
||||
}
|
||||
|
||||
// Handle struct types with C-compatible FFI parameters (different from high-level API)
|
||||
if (isUnoStruct(unoType))
|
||||
{
|
||||
bool isInputOnly
|
||||
= (direction == unoidl::InterfaceTypeEntity::Method::Parameter::DIRECTION_IN);
|
||||
if (isInputOnly)
|
||||
{
|
||||
// Input struct: pass as C-compatible pointer for FFI (void* for now, can be refined later)
|
||||
return "*mut c_void"_ostr;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Input/output struct: still use raw pointer for output parameters
|
||||
return "*mut c_void"_ostr;
|
||||
}
|
||||
}
|
||||
|
||||
// Handle interface types with C-compatible FFI parameters (different from high-level API)
|
||||
if (isUnoInterface(unoType))
|
||||
{
|
||||
bool isInputOnly
|
||||
= (direction == unoidl::InterfaceTypeEntity::Method::Parameter::DIRECTION_IN);
|
||||
if (isInputOnly)
|
||||
{
|
||||
// Input interface: pass as C-compatible pointer for FFI (void* for interfaces)
|
||||
return "*mut c_void"_ostr;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Input/output interface: still use raw pointer for output parameters
|
||||
return "*mut c_void"_ostr;
|
||||
}
|
||||
}
|
||||
|
||||
// Handle enums - revert to void* to avoid nullptr comparison issues
|
||||
if (isUnoEnum(unoType))
|
||||
{
|
||||
return "*mut c_void"_ostr;
|
||||
}
|
||||
|
||||
// For primitive types, use the same logic as high-level API (primitives are the same)
|
||||
if (unoType == u"boolean" || unoType == u"byte" || unoType == u"short"
|
||||
|| unoType == u"unsigned short" || unoType == u"long" || unoType == u"unsigned long"
|
||||
|| unoType == u"hyper" || unoType == u"unsigned hyper" || unoType == u"float"
|
||||
|| unoType == u"double")
|
||||
{
|
||||
// Get the Rust primitive type
|
||||
OString rustPrimitiveType = getRustWrapperTypeName(unoType);
|
||||
if (!rustPrimitiveType.isEmpty())
|
||||
{
|
||||
bool isInputOnly
|
||||
= (direction == unoidl::InterfaceTypeEntity::Method::Parameter::DIRECTION_IN);
|
||||
if (isInputOnly)
|
||||
{
|
||||
// Input parameters: pass by value (u8 for boolean, i32 for long, etc.)
|
||||
return rustPrimitiveType;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Input/output parameters: pass by mutable pointer (*mut u8, *mut i32, etc.)
|
||||
return "*mut " + rustPrimitiveType;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// For all other types (typedefs, structs, interfaces, sequences), use void*
|
||||
return "*mut c_void"_ostr;
|
||||
}
|
||||
|
||||
bool RustProducer::isUnoInterface(std::u16string_view typeName) const
|
||||
{
|
||||
rtl::Reference<unoidl::Entity> entity;
|
||||
@@ -1374,4 +1729,207 @@ bool RustProducer::isUnoEnum(std::u16string_view typeName) const
|
||||
return sort == codemaker::UnoType::Sort::Enum;
|
||||
}
|
||||
|
||||
OString RustProducer::convertRustParameterForFFICall(
|
||||
std::u16string_view unoType, std::string_view paramName,
|
||||
unoidl::InterfaceTypeEntity::Method::Parameter::Direction direction) const
|
||||
{
|
||||
// Handle string types with automatic conversion
|
||||
if (unoType == u"string")
|
||||
{
|
||||
bool isInputOnly
|
||||
= (direction == unoidl::InterfaceTypeEntity::Method::Parameter::DIRECTION_IN);
|
||||
if (isInputOnly)
|
||||
{
|
||||
// Input string: convert OUString to rtl_uString* using .as_ptr()
|
||||
return OString(paramName) + ".as_ptr()";
|
||||
}
|
||||
else
|
||||
{
|
||||
// Input/output string: pass through as pointer (already proper type)
|
||||
return OString(paramName);
|
||||
}
|
||||
}
|
||||
|
||||
// Handle any types with automatic conversion
|
||||
if (unoType == u"any")
|
||||
{
|
||||
bool isInputOnly
|
||||
= (direction == unoidl::InterfaceTypeEntity::Method::Parameter::DIRECTION_IN);
|
||||
if (isInputOnly)
|
||||
{
|
||||
// Input any: convert Any to uno_Any* using .as_ptr()
|
||||
return OString(paramName) + ".as_ptr()";
|
||||
}
|
||||
else
|
||||
{
|
||||
// Input/output any: pass through as pointer (already proper type)
|
||||
return OString(paramName);
|
||||
}
|
||||
}
|
||||
|
||||
// Handle struct types with automatic conversion
|
||||
if (isUnoStruct(unoType))
|
||||
{
|
||||
bool isInputOnly
|
||||
= (direction == unoidl::InterfaceTypeEntity::Method::Parameter::DIRECTION_IN);
|
||||
if (isInputOnly)
|
||||
{
|
||||
// Input struct: convert generated struct to void* using .as_ptr()
|
||||
return OString(paramName) + ".as_ptr()";
|
||||
}
|
||||
else
|
||||
{
|
||||
// Input/output struct: pass through as pointer (already proper type)
|
||||
return OString(paramName);
|
||||
}
|
||||
}
|
||||
|
||||
// Handle interface types with automatic conversion
|
||||
if (isUnoInterface(unoType))
|
||||
{
|
||||
bool isInputOnly
|
||||
= (direction == unoidl::InterfaceTypeEntity::Method::Parameter::DIRECTION_IN);
|
||||
if (isInputOnly)
|
||||
{
|
||||
// Input interface: convert generated interface to void* using .as_ptr()
|
||||
return OString(paramName) + ".as_ptr()";
|
||||
}
|
||||
else
|
||||
{
|
||||
// Input/output interface: pass through as pointer (already proper type)
|
||||
return OString(paramName);
|
||||
}
|
||||
}
|
||||
|
||||
// Handle primitive types - pass through directly (no conversion needed)
|
||||
if (unoType == u"boolean" || unoType == u"byte" || unoType == u"short"
|
||||
|| unoType == u"unsigned short" || unoType == u"long" || unoType == u"unsigned long"
|
||||
|| unoType == u"hyper" || unoType == u"unsigned hyper" || unoType == u"float"
|
||||
|| unoType == u"double")
|
||||
{
|
||||
// Primitive types already match FFI expectations - pass through directly
|
||||
return OString(paramName);
|
||||
}
|
||||
|
||||
// For all other types, pass through without conversion (fallback)
|
||||
return OString(paramName);
|
||||
}
|
||||
|
||||
OString RustProducer::getRustStructGetterReturnType(std::u16string_view unoType) const
|
||||
{
|
||||
// Struct getters return the actual type (for direct access, not modification)
|
||||
|
||||
// Handle string types
|
||||
if (unoType == u"string")
|
||||
{
|
||||
return "crate::core::OUString"_ostr; // Return high-level string type
|
||||
}
|
||||
|
||||
// Handle any types
|
||||
if (unoType == u"any")
|
||||
{
|
||||
return "crate::core::Any"_ostr; // Return high-level Any type
|
||||
}
|
||||
|
||||
// Handle primitive types - return the Rust primitive directly
|
||||
if (unoType == u"boolean" || unoType == u"byte" || unoType == u"short"
|
||||
|| unoType == u"unsigned short" || unoType == u"long" || unoType == u"unsigned long"
|
||||
|| unoType == u"hyper" || unoType == u"unsigned hyper" || unoType == u"float"
|
||||
|| unoType == u"double")
|
||||
{
|
||||
return getRustWrapperTypeName(unoType); // Return native Rust type (u8, i32, f64, etc.)
|
||||
}
|
||||
|
||||
// For all other types (typedefs, structs, enums, interfaces, sequences), use void*
|
||||
return "*mut c_void"_ostr;
|
||||
}
|
||||
|
||||
OString RustProducer::getRustStructSetterParameterType(std::u16string_view unoType) const
|
||||
{
|
||||
// Struct setters take the value to set
|
||||
|
||||
// Handle string types
|
||||
if (unoType == u"string")
|
||||
{
|
||||
return "crate::core::OUString"_ostr; // Take high-level string type
|
||||
}
|
||||
|
||||
// Handle any types
|
||||
if (unoType == u"any")
|
||||
{
|
||||
return "crate::core::Any"_ostr; // Take high-level Any type
|
||||
}
|
||||
|
||||
// Handle primitive types - take by value for direct assignment
|
||||
if (unoType == u"boolean" || unoType == u"byte" || unoType == u"short"
|
||||
|| unoType == u"unsigned short" || unoType == u"long" || unoType == u"unsigned long"
|
||||
|| unoType == u"hyper" || unoType == u"unsigned hyper" || unoType == u"float"
|
||||
|| unoType == u"double")
|
||||
{
|
||||
return getRustWrapperTypeName(unoType); // Take native Rust type (u8, i32, f64, etc.)
|
||||
}
|
||||
|
||||
// For all other types (typedefs, structs, enums, interfaces, sequences), use void*
|
||||
return "*mut c_void"_ostr;
|
||||
}
|
||||
|
||||
OString RustProducer::getRustStructExternGetterReturnType(std::u16string_view unoType) const
|
||||
{
|
||||
// Struct extern getter return types (FFI-compatible)
|
||||
|
||||
// Handle string types
|
||||
if (unoType == u"string")
|
||||
{
|
||||
return "*mut crate::ffi::rtl_string::rtl_uString"_ostr; // Return mutable pointer for from_raw compatibility
|
||||
}
|
||||
|
||||
// Handle any types
|
||||
if (unoType == u"any")
|
||||
{
|
||||
return "*const crate::ffi::uno_any::uno_Any"_ostr; // Return C-compatible Any pointer
|
||||
}
|
||||
|
||||
// Handle primitive types - return pointer to primitive for FFI
|
||||
if (unoType == u"boolean" || unoType == u"byte" || unoType == u"short"
|
||||
|| unoType == u"unsigned short" || unoType == u"long" || unoType == u"unsigned long"
|
||||
|| unoType == u"hyper" || unoType == u"unsigned hyper" || unoType == u"float"
|
||||
|| unoType == u"double")
|
||||
{
|
||||
return "*const " + getRustWrapperTypeName(unoType); // Return pointer to primitive type
|
||||
}
|
||||
|
||||
// For all other types (typedefs, structs, enums, interfaces, sequences), use void*
|
||||
return "*mut c_void"_ostr;
|
||||
}
|
||||
|
||||
OString RustProducer::getRustStructExternSetterParameterType(std::u16string_view unoType) const
|
||||
{
|
||||
// Struct extern setter parameter types (FFI-compatible)
|
||||
|
||||
// Handle string types
|
||||
if (unoType == u"string")
|
||||
{
|
||||
return "*const crate::ffi::rtl_string::rtl_uString"_ostr; // Take const pointer for setter input (this is fine)
|
||||
}
|
||||
|
||||
// Handle any types
|
||||
if (unoType == u"any")
|
||||
{
|
||||
return "*const crate::ffi::uno_any::uno_Any"_ostr; // Take C-compatible Any pointer
|
||||
}
|
||||
|
||||
// Handle primitive types - take by value for FFI (matches C++ side)
|
||||
if (unoType == u"boolean" || unoType == u"byte" || unoType == u"short"
|
||||
|| unoType == u"unsigned short" || unoType == u"long" || unoType == u"unsigned long"
|
||||
|| unoType == u"hyper" || unoType == u"unsigned hyper" || unoType == u"float"
|
||||
|| unoType == u"double")
|
||||
{
|
||||
return getRustWrapperTypeName(
|
||||
unoType); // Take primitive type by value (matches C++ approach)
|
||||
}
|
||||
|
||||
// For all other types (typedefs, structs, enums, interfaces, sequences), use void*
|
||||
return "*mut c_void"_ostr;
|
||||
}
|
||||
|
||||
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|
||||
|
||||
@@ -80,6 +80,22 @@ private:
|
||||
static OString getRustTypeName(std::string_view unoName);
|
||||
OString getRustWrapperTypeName(std::u16string_view unoType) const;
|
||||
OString getRustReturnType(std::u16string_view unoType) const;
|
||||
OString
|
||||
getRustParameterType(std::u16string_view unoType,
|
||||
unoidl::InterfaceTypeEntity::Method::Parameter::Direction direction) const;
|
||||
OString getRustExternParameterType(
|
||||
std::u16string_view unoType,
|
||||
unoidl::InterfaceTypeEntity::Method::Parameter::Direction direction) const;
|
||||
|
||||
// Struct getter/setter type functions
|
||||
OString getRustStructGetterReturnType(std::u16string_view unoType) const;
|
||||
OString getRustStructSetterParameterType(std::u16string_view unoType) const;
|
||||
OString getRustStructExternGetterReturnType(std::u16string_view unoType) const;
|
||||
OString getRustStructExternSetterParameterType(std::u16string_view unoType) const;
|
||||
|
||||
OString convertRustParameterForFFICall(
|
||||
std::u16string_view unoType, std::string_view paramName,
|
||||
unoidl::InterfaceTypeEntity::Method::Parameter::Direction direction) const;
|
||||
OString resolveTypedef(std::u16string_view unoType) const;
|
||||
|
||||
// Type classification helpers
|
||||
@@ -100,12 +116,15 @@ private:
|
||||
const rtl::Reference<unoidl::PlainStructTypeEntity>& entity);
|
||||
void generateStructConstructor(class RustFile& file, std::string_view externFunctionPrefix);
|
||||
void generateStructFromPtr(class RustFile& file, std::string_view externFunctionPrefix);
|
||||
void generateStructAsPtr(class RustFile& file);
|
||||
void generateStructAccessors(class RustFile& file,
|
||||
const rtl::Reference<unoidl::PlainStructTypeEntity>& entity,
|
||||
std::string_view externFunctionPrefix);
|
||||
void generateStructMemberGetter(class RustFile& file, std::string_view memberName,
|
||||
std::u16string_view memberType,
|
||||
std::string_view externFunctionPrefix);
|
||||
void generateStructMemberSetter(class RustFile& file, std::string_view memberName,
|
||||
std::u16string_view memberType,
|
||||
std::string_view externFunctionPrefix);
|
||||
void generateStructDropTrait(class RustFile& file, std::string_view name,
|
||||
const rtl::Reference<unoidl::PlainStructTypeEntity>& entity);
|
||||
|
||||
@@ -36,4 +36,3 @@ fn main() {
|
||||
}
|
||||
|
||||
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|
||||
|
||||
|
||||
@@ -7,13 +7,16 @@
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
use crate::core::uno_wrapper::{UnoError, defaultBootstrap_InitialComponentContext};
|
||||
use crate::core::OUString;
|
||||
use crate::generated::rustmaker::com::sun::star::frame::Desktop::Desktop;
|
||||
use crate::generated::rustmaker::com::sun::star::frame::XComponentLoader::XComponentLoader;
|
||||
use crate::generated::rustmaker::com::sun::star::text::XTextDocument::XTextDocument;
|
||||
use crate::generated::rustmaker::com::sun::star::text::XSimpleText::XSimpleText;
|
||||
use std::ffi::c_void;
|
||||
use crate::{
|
||||
core::{
|
||||
OUString,
|
||||
uno_wrapper::{UnoError, defaultBootstrap_InitialComponentContext},
|
||||
},
|
||||
generated::rustmaker::com::sun::star::{
|
||||
frame::{Desktop::Desktop, XComponentLoader::XComponentLoader},
|
||||
text::{XSimpleText::XSimpleText, XTextDocument::XTextDocument, XTextRange::XTextRange},
|
||||
},
|
||||
};
|
||||
|
||||
/// LibreOffice Writer automation demo using generated Rust UNO bindings.
|
||||
/// Creates a Writer document and inserts text using auto-generated interface wrappers.
|
||||
@@ -25,11 +28,11 @@ pub fn run() {
|
||||
Ok(()) => {
|
||||
println!("=== Rust UNO Bridge Test Done ===");
|
||||
println!("<- 'load_writer' example completed successfully.");
|
||||
},
|
||||
}
|
||||
Err(e) => {
|
||||
println!("=== Rust UNO Bridge Test Done ===");
|
||||
eprintln!(" ERROR: 'load_writer' example failed: {e:?}");
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -45,8 +48,12 @@ fn run_internal() -> Result<(), UnoError> {
|
||||
println!(" ✓ Desktop service created: {:p}", desktop.as_ptr());
|
||||
|
||||
// Get XComponentLoader interface
|
||||
let component_loader = XComponentLoader::from_ptr(desktop.as_ptr()).ok_or(UnoError::InterfaceNotSupported)?;
|
||||
println!(" ✓ XComponentLoader interface acquired: {:p}", component_loader.as_ptr());
|
||||
let component_loader =
|
||||
XComponentLoader::from_ptr(desktop.as_ptr()).ok_or(UnoError::InterfaceNotSupported)?;
|
||||
println!(
|
||||
" ✓ XComponentLoader interface acquired: {:p}",
|
||||
component_loader.as_ptr()
|
||||
);
|
||||
|
||||
// Load Writer document
|
||||
println!(" Loading Writer document via XComponentLoader::loadComponentFromURL...");
|
||||
@@ -55,24 +62,33 @@ fn run_internal() -> Result<(), UnoError> {
|
||||
let search_flags: i32 = 0;
|
||||
let empty_args = std::ptr::null_mut();
|
||||
|
||||
let document_interface_ptr = component_loader.loadComponentFromURL(
|
||||
url.as_ptr() as *mut c_void,
|
||||
target.as_ptr() as *mut c_void,
|
||||
&search_flags as *const i32 as *mut c_void,
|
||||
empty_args,
|
||||
).ok_or(UnoError::OperationFailed)?;
|
||||
|
||||
let document_interface_ptr = component_loader
|
||||
.loadComponentFromURL(
|
||||
url, // Direct OUString - no casting needed!
|
||||
target, // Direct OUString - no casting needed!
|
||||
search_flags,
|
||||
empty_args,
|
||||
)
|
||||
.ok_or(UnoError::OperationFailed)?;
|
||||
|
||||
if document_interface_ptr.as_ptr().is_null() {
|
||||
return Err(UnoError::OperationFailed);
|
||||
}
|
||||
|
||||
|
||||
println!(" ✓ Writer document loaded successfully!");
|
||||
println!(" Document interface pointer: {:p}", document_interface_ptr.as_ptr());
|
||||
println!(
|
||||
" Document interface pointer: {:p}",
|
||||
document_interface_ptr.as_ptr()
|
||||
);
|
||||
|
||||
// Cast to XTextDocument
|
||||
println!(" Casting document to XTextDocument...");
|
||||
let text_document = XTextDocument::from_ptr(document_interface_ptr.as_ptr()).ok_or(UnoError::InterfaceNotSupported)?;
|
||||
println!(" ✓ XTextDocument interface acquired: {:p}", text_document.as_ptr());
|
||||
let text_document = XTextDocument::from_ptr(document_interface_ptr.as_ptr())
|
||||
.ok_or(UnoError::InterfaceNotSupported)?;
|
||||
println!(
|
||||
" ✓ XTextDocument interface acquired: {:p}",
|
||||
text_document.as_ptr()
|
||||
);
|
||||
|
||||
// Get text object
|
||||
println!(" Getting text object via XTextDocument::getText...");
|
||||
@@ -81,39 +97,54 @@ fn run_internal() -> Result<(), UnoError> {
|
||||
|
||||
// Cast to XSimpleText
|
||||
println!(" Casting XText to XSimpleText...");
|
||||
let simple_text = XSimpleText::from_ptr(text.as_ptr()).ok_or(UnoError::InterfaceNotSupported)?;
|
||||
println!(" ✓ XSimpleText interface acquired: {:p}", simple_text.as_ptr());
|
||||
|
||||
let simple_text =
|
||||
XSimpleText::from_ptr(text.as_ptr()).ok_or(UnoError::InterfaceNotSupported)?;
|
||||
println!(
|
||||
" ✓ XSimpleText interface acquired: {:p}",
|
||||
simple_text.as_ptr()
|
||||
);
|
||||
|
||||
// Create text cursor
|
||||
println!(" Creating text cursor via XSimpleText::createTextCursor...");
|
||||
let cursor = simple_text.createTextCursor().ok_or(UnoError::OperationFailed)?;
|
||||
let cursor = simple_text
|
||||
.createTextCursor()
|
||||
.ok_or(UnoError::OperationFailed)?;
|
||||
println!(" ✓ Text cursor created: {:p}", cursor.as_ptr());
|
||||
|
||||
// Insert text
|
||||
println!(" Inserting text via XSimpleText::insertString...");
|
||||
let hello_text = OUString::from(
|
||||
"Hello from Generated Rust UNO Bindings!\n\n\
|
||||
"Hello from Generated Rust UNO Bindings with Typed Parameters! \n\n\
|
||||
This text was inserted using auto-generated service and interface wrappers:\n\n\
|
||||
- Desktop::create() - Generated service wrapper\n\
|
||||
- XComponentLoader::loadComponentFromURL() - Generated interface method\n\
|
||||
- XTextDocument::getText() - Generated interface method\n\
|
||||
- XSimpleText::createTextCursor() - Generated interface method\n\
|
||||
- XSimpleText::insertString() - Generated interface method\n\n\
|
||||
All types generated automatically from UNO IDL with type-safe opaque pointer architecture!\n\n\
|
||||
FFI Validation Features Demonstrated:\n\
|
||||
NEW: Typed Parameter API Achievements:\n\
|
||||
- Boolean parameters now use native 'bool' instead of void* casting\n\
|
||||
- Integer parameters use direct 'i32' instead of pointer arithmetic\n\
|
||||
- Natural Rust syntax: 'absorb as u8' vs '*ptr as *mut c_void'\n\
|
||||
- Direction-aware: input by value, input/output by pointer\n\
|
||||
- Type-safe at compile time with better IDE support\n\n\
|
||||
FFI Architecture Features:\n\
|
||||
- Automatic null pointer checking in all generated methods\n\
|
||||
- Reference validity validation (is() checking) \n\
|
||||
- Memory cleanup on validation failure (delete + return nullptr)\n\
|
||||
- Detailed debug logging for troubleshooting\n\
|
||||
- Type-safe opaque pointer architecture prevents crashes\n\
|
||||
- Follows uno_bootstrap.cxx validation pattern exactly"
|
||||
- Progressive migration: primitives typed, complex types remain compatible",
|
||||
);
|
||||
let absorb: i32 = 0;
|
||||
let absorb: bool = false;
|
||||
|
||||
// Convert XTextCursor to XTextRange (interface inheritance)
|
||||
let text_range =
|
||||
XTextRange::from_ptr(cursor.as_ptr()).ok_or(UnoError::InterfaceNotSupported)?;
|
||||
|
||||
simple_text.insertString(
|
||||
cursor.as_ptr() as *mut c_void,
|
||||
hello_text.as_ptr() as *mut c_void,
|
||||
&absorb as *const i32 as *mut c_void,
|
||||
text_range, // Direct typed interface - no void* casting needed!
|
||||
hello_text, // Direct OUString - no casting needed!
|
||||
absorb as u8, // Direct boolean parameter (natural Rust syntax!)
|
||||
);
|
||||
|
||||
println!(" ✓ Text inserted successfully using generated interfaces!");
|
||||
@@ -121,4 +152,4 @@ fn run_internal() -> Result<(), UnoError> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|
||||
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|
||||
|
||||
Reference in New Issue
Block a user