Repository.mk                               |    1 
 RepositoryModule_host.mk                    |    1 
 desktop/Executable_soffice_bin.mk           |    1 
 rust_uno/.gitignore                         |    3 
 rust_uno/Cargo.toml                         |   20 
 rust_uno/CustomTarget_cargo.mk              |   18 
 rust_uno/CustomTarget_rustmaker.mk          |   31 +
 rust_uno/Extension_rust_uno-example.mk      |   26 
 rust_uno/Library_rust_uno-cpp.mk            |   41 +
 rust_uno/Library_rust_uno-example.mk        |   37 +
 rust_uno/Makefile                           |   14 
 rust_uno/Module_rust_uno.mk                 |   22 
 rust_uno/build.rs                           |   39 +
 rust_uno/example/Addons.xcu                 |   43 +
 rust_uno/example/META-INF/manifest.xml      |   28 
 rust_uno/example/ProtocolHandler.xcu        |   29 
 rust_uno/example/description.xml            |   26 
 rust_uno/example/example.component          |   28 
 rust_uno/example/example.cxx                |  243 ++++++++
 rust_uno/example/rust_uno_hook.hxx          |   17 
 rust_uno/src/core/any.rs                    |  257 ++++++++
 rust_uno/src/core/mod.rs                    |   37 +
 rust_uno/src/core/oustring.rs               |  256 ++++++++
 rust_uno/src/core/sequence.rs               |  245 ++++++++
 rust_uno/src/core/tests/string_tests.rs     |  387 +++++++++++++
 rust_uno/src/core/tests/type_tests.rs       |  520 +++++++++++++++++
 rust_uno/src/core/type.rs                   |  328 +++++++++++
 rust_uno/src/core/uno_wrapper.rs            |   59 +
 rust_uno/src/examples/any_example.rs        |  158 +++++
 rust_uno/src/examples/basic_example.rs      |  120 ++++
 rust_uno/src/examples/load_writer.rs        |  124 ++++
 rust_uno/src/examples/mod.rs                |   41 +
 rust_uno/src/examples/string_example.rs     |  131 ++++
 rust_uno/src/examples/type_example.rs       |  324 ++++++++++
 rust_uno/src/ffi/mod.rs                     |   27 
 rust_uno/src/ffi/rtl_string.rs              |   87 ++
 rust_uno/src/ffi/sal_types.rs               |   50 +
 rust_uno/src/ffi/tests/integration_tests.rs |  828 ++++++++++++++++++++++++++++
 rust_uno/src/ffi/type_ffi.rs                |  173 +++++
 rust_uno/src/ffi/uno_any.rs                 |  108 +++
 rust_uno/src/ffi/uno_bridge.rs              |   37 +
 rust_uno/src/ffi/uno_sequence.rs            |   54 +
 rust_uno/src/lib.rs                         |   24 
 rust_uno/uno_bootstrap.cxx                  |   86 ++
 44 files changed, 5129 insertions(+)

New commits:
commit 3d75577640a345327122d8a89a2206831eba4019
Author:     Mohamed Ali <[email protected]>
AuthorDate: Thu Jun 12 18:52:45 2025 +0300
Commit:     Stephan Bergmann <[email protected]>
CommitDate: Thu Sep 11 21:39:08 2025 +0200

    Rust Bindings: Add extension-based UNO integration with FFI architecture
    
    Implements LibreOffice extension providing Rust language binding for UNO API
    using opaque pointer FFI architecture with type-safe handles.
    
    Extension Features:
    - User-controlled execution via "Rust UNO → Example" menu
    - Optional installation/removal through LibreOffice extension system
    - Complete Writer document manipulation example
    
    Technical Implementation:
    - Generated Rust wrappers for all UNO types via rustmaker
    - C++ extern "C" bridges with proper UNO integration
    - Type-safe opaque handles (XTextDocumentHandle, etc.)
    - Extension architecture following LibreOffice standards
    - Menu integration via Addons.xcu and ProtocolHandler.xcu
    
    Architecture:
    - Rust RAII Wrappers ↔ C++ extern "C" Bridges ↔ LibreOffice UNO
    - Extension packaging with rust_uno-example.oxt
    - Integrated build system with CustomTarget and Library makefiles
    
    Build Commands:
    ./configure --enable-rust-uno
    
    Extension Structure:
    - rust_uno/example/ - Extension source files
    - workdir/Extension/rust_uno-example.oxt - Packaged extension
    - Automatic installation during LibreOffice build
    
    Runtime Validation:
    Successfully demonstrates complete UNO integration:
    - Desktop service creation and XComponentLoader interface
    - Writer document loading via loadComponentFromURL
    - Text manipulation through XTextDocument and XSimpleText
    - Proper interface querying and method invocation
    
    GSoC 2025: Rust UNO Language Binding
    
    Change-Id: I5cecb8ebd05aab396f444488c0ee2a9d483a9f62
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/186425
    Tested-by: Jenkins
    Reviewed-by: Stephan Bergmann <[email protected]>

diff --git a/Repository.mk b/Repository.mk
index 25f8e9213085..3f5d69b0ddc4 100644
--- a/Repository.mk
+++ b/Repository.mk
@@ -779,6 +779,7 @@ $(eval $(call gb_Helper_register_libraries,EXTENSIONLIBS, \
        active_native \
        passive_native \
        crashextension \
+       rust_uno-example \
 ))
 
 ifneq ($(ENABLE_JAVA),)
diff --git a/RepositoryModule_host.mk b/RepositoryModule_host.mk
index 8d23ee960f68..bb5add564c0c 100644
--- a/RepositoryModule_host.mk
+++ b/RepositoryModule_host.mk
@@ -126,6 +126,7 @@ $(eval $(call gb_Module_add_moduledirs,libreoffice,\
        reportbuilder \
        $(call gb_Helper_optional,DBCONNECTIVITY,reportdesign) \
        ridljar \
+       rust_uno \
        sal \
        salhelper \
        sax \
diff --git a/desktop/Executable_soffice_bin.mk 
b/desktop/Executable_soffice_bin.mk
index 5838572d16fa..5987a9a4d456 100644
--- a/desktop/Executable_soffice_bin.mk
+++ b/desktop/Executable_soffice_bin.mk
@@ -19,6 +19,7 @@ $(eval $(call gb_Executable_add_defs,soffice_bin,\
 ))
 
 $(eval $(call gb_Executable_use_libraries,soffice_bin,\
+    $(if $(ENABLE_RUST_UNO),rust_uno-cpp) \
     sal \
     sofficeapp \
 ))
diff --git a/rust_uno/.gitignore b/rust_uno/.gitignore
new file mode 100644
index 000000000000..310213a05bc3
--- /dev/null
+++ b/rust_uno/.gitignore
@@ -0,0 +1,3 @@
+/target
+Cargo.lock
+generated/
diff --git a/rust_uno/Cargo.toml b/rust_uno/Cargo.toml
new file mode 100644
index 000000000000..f54f9bc3c85e
--- /dev/null
+++ b/rust_uno/Cargo.toml
@@ -0,0 +1,20 @@
+# -*- Mode: toml; tab-width: 4; indent-tabs-mode: nil; fill-column: 100 -*-
+#
+# This file is part of the LibreOffice project.
+#
+# 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/.
+#
+
+[package]
+name = "rust_uno"
+version = "0.1.0"
+edition = "2024"
+description = "Rust FFI binding for LibreOffice UNO API"
+
+[lib]
+name = "rust_uno"
+crate-type = ["cdylib"]
+
+# vim: set noet sw=4 ts=4:
diff --git a/rust_uno/CustomTarget_cargo.mk b/rust_uno/CustomTarget_cargo.mk
new file mode 100644
index 000000000000..d27ec0b0797a
--- /dev/null
+++ b/rust_uno/CustomTarget_cargo.mk
@@ -0,0 +1,18 @@
+# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t; fill-column: 
100 -*-
+#
+# This file is part of the LibreOffice project.
+#
+# 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/.
+#
+
+$(eval $(call gb_CustomTarget_CustomTarget,rust_uno/cargo))
+
+.PHONY: $(call gb_CustomTarget_get_target,rust_uno/cargo)
+$(call gb_CustomTarget_get_target,rust_uno/cargo): \
+        $(call gb_Library_get_target,rust_uno-cpp) \
+        $(gb_CustomTarget_workdir)/rust_uno/rustmaker/cpp
+       cd $(SRCDIR)/rust_uno && cargo build $(if $(verbose),--verbose,) 
--release
+
+# vim: set noet sw=4 ts=4:
diff --git a/rust_uno/CustomTarget_rustmaker.mk 
b/rust_uno/CustomTarget_rustmaker.mk
new file mode 100644
index 000000000000..b519be3c627c
--- /dev/null
+++ b/rust_uno/CustomTarget_rustmaker.mk
@@ -0,0 +1,31 @@
+# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t; fill-column: 
100 -*-
+#
+# This file is part of the LibreOffice project.
+#
+# 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/.
+#
+
+$(eval $(call gb_CustomTarget_CustomTarget,rust_uno/rustmaker))
+
+$(call gb_CustomTarget_get_target,rust_uno/rustmaker): \
+        $(gb_CustomTarget_workdir)/rust_uno/rustmaker/cpp
+
+$(gb_CustomTarget_workdir)/rust_uno/rustmaker/cpp: \
+        $(call gb_Executable_get_target,rustmaker) \
+        $(call gb_Executable_get_runtime_dependencies,rustmaker) \
+        $(call gb_UnoApi_get_target,offapi) \
+        $(call gb_UnoApi_get_target,udkapi) \
+        $(gb_CustomTarget_workdir)/rust_uno/rustmaker/.dir
+       rm -fr $(SRCDIR)/rust_uno/src/generated
+       mkdir $(SRCDIR)/rust_uno/src/generated
+       rm -fr $(gb_CustomTarget_workdir)/rust_uno/rustmaker/cpp
+       mkdir $(gb_CustomTarget_workdir)/rust_uno/rustmaker/cpp
+       $(call gb_Helper_abbreviate_dirs, \
+        $(call gb_Helper_execute,rustmaker $(if $(verbose),--verbose,) -Ocpp 
$(gb_CustomTarget_workdir)/rust_uno/rustmaker/cpp \
+        $(if $(verbose),--verbose,) -Orust $(SRCDIR)/rust_uno/src/generated \
+        $(call gb_UnoApi_get_target,offapi) $(call 
gb_UnoApi_get_target,udkapi)))
+       touch $@
+
+# vim: set noet sw=4 ts=4:
diff --git a/rust_uno/Extension_rust_uno-example.mk 
b/rust_uno/Extension_rust_uno-example.mk
new file mode 100644
index 000000000000..fea1677e1966
--- /dev/null
+++ b/rust_uno/Extension_rust_uno-example.mk
@@ -0,0 +1,26 @@
+# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t; fill-column: 
100 -*-
+#
+# This file is part of the LibreOffice project.
+#
+# 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/.
+#
+
+$(eval $(call 
gb_Extension_Extension,rust_uno-example,rust_uno/example,nodeliver))
+
+$(eval $(call 
gb_Extension_add_file,rust_uno-example,platform.components,$(call 
gb_Rdb_get_target,rust_uno-example)))
+
+$(eval $(call gb_Extension_add_files,rust_uno-example,, \
+    $(SRCDIR)/rust_uno/example/Addons.xcu \
+    $(SRCDIR)/rust_uno/example/ProtocolHandler.xcu \
+    $(SRCDIR)/rust_uno/target/release/librust_uno.so \
+))
+
+$(eval $(call gb_Extension_add_libraries,rust_uno-example, \
+    rust_uno-example \
+))
+
+$(SRCDIR)/rust_uno/target/release/librust_uno.so: $(call 
gb_CustomTarget_get_target,rust_uno/cargo)
+
+# vim: set noet sw=4 ts=4:
diff --git a/rust_uno/Library_rust_uno-cpp.mk b/rust_uno/Library_rust_uno-cpp.mk
new file mode 100644
index 000000000000..4a1875015b7f
--- /dev/null
+++ b/rust_uno/Library_rust_uno-cpp.mk
@@ -0,0 +1,41 @@
+# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t; fill-column: 
100 -*-
+#
+# This file is part of the LibreOffice project.
+#
+# 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/.
+#
+
+$(eval $(call gb_Library_Library,rust_uno-cpp))
+
+$(eval $(call gb_Library_use_libraries,rust_uno-cpp, \
+    cppu \
+    cppuhelper \
+    sal \
+))
+
+$(eval $(call gb_Library_use_sdk_api,rust_uno-cpp))
+
+# Add the uno_bootstrap.cxx file for bootstrap functionality
+$(eval $(call gb_Library_add_exception_objects,rust_uno-cpp, \
+    rust_uno/uno_bootstrap \
+))
+
+# Combined generated files instead of thousands of individual files
+rust_uno_generated_cxx = \
+    rust_uno_bindings
+
+define rust_uno_add_generated_cxx
+$(gb_CustomTarget_workdir)/rust_uno/rustmaker/cpp/$(1).cxx: \
+        $(call gb_CustomTarget_get_target,rust_uno/rustmaker)
+
+$(eval $(call gb_Library_add_generated_exception_objects,rust_uno-cpp, \
+    CustomTarget/rust_uno/rustmaker/cpp/$(1) \
+))
+
+endef
+
+$(foreach gencxx,$(rust_uno_generated_cxx),$(eval $(call 
rust_uno_add_generated_cxx,$(gencxx))))
+
+# vim: set noet sw=4 ts=4:
diff --git a/rust_uno/Library_rust_uno-example.mk 
b/rust_uno/Library_rust_uno-example.mk
new file mode 100644
index 000000000000..bee03c23c3b6
--- /dev/null
+++ b/rust_uno/Library_rust_uno-example.mk
@@ -0,0 +1,37 @@
+# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t; fill-column: 
100 -*-
+#
+# This file is part of the LibreOffice project.
+#
+# 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/.
+#
+
+$(eval $(call gb_Library_Library,rust_uno-example))
+
+$(eval $(call gb_Library_add_exception_objects,rust_uno-example, \
+    rust_uno/example/example \
+))
+
+$(eval $(call 
gb_Library_set_componentfile,rust_uno-example,rust_uno/example/example,rust_uno-example))
+
+$(eval $(call gb_Library_set_external_code,rust_uno-example))
+
+$(eval $(call gb_Library_use_externals,rust_uno-example, \
+    boost_headers \
+))
+
+$(eval $(call gb_Library_use_libraries,rust_uno-example, \
+    cppu \
+    cppuhelper \
+    sal \
+))
+
+$(eval $(call gb_Library_use_sdk_api,rust_uno-example))
+
+$(call gb_Library_get_target,rust_uno-example): $(call 
gb_CustomTarget_get_target,rust_uno/cargo)
+$(eval $(call gb_Library_add_libs,rust_uno-example,\
+    $(SRCDIR)/rust_uno/target/release/librust_uno.so \
+))
+
+# vim: set noet sw=4 ts=4:
diff --git a/rust_uno/Makefile b/rust_uno/Makefile
new file mode 100644
index 000000000000..d5aa252aa8c3
--- /dev/null
+++ b/rust_uno/Makefile
@@ -0,0 +1,14 @@
+# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t; fill-column: 
100 -*-
+#
+# This file is part of the LibreOffice project.
+#
+# 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/.
+#
+
+module_directory:=$(dir $(realpath $(firstword $(MAKEFILE_LIST))))
+
+include $(module_directory)/../solenv/gbuild/partial_build.mk
+
+# vim: set noet sw=4 ts=4:
diff --git a/rust_uno/Module_rust_uno.mk b/rust_uno/Module_rust_uno.mk
new file mode 100644
index 000000000000..ab6fa695a0cc
--- /dev/null
+++ b/rust_uno/Module_rust_uno.mk
@@ -0,0 +1,22 @@
+# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t; fill-column: 
100 -*-
+#
+# This file is part of the LibreOffice project.
+#
+# 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/.
+#
+
+$(eval $(call gb_Module_Module,rust_uno))
+
+ifeq ($(ENABLE_RUST_UNO),TRUE)
+$(eval $(call gb_Module_add_targets,rust_uno, \
+    CustomTarget_cargo \
+    CustomTarget_rustmaker \
+    Extension_rust_uno-example \
+    Library_rust_uno-cpp \
+    Library_rust_uno-example \
+))
+endif
+
+# vim: set noet sw=4 ts=4:
diff --git a/rust_uno/build.rs b/rust_uno/build.rs
new file mode 100644
index 000000000000..5d25a125b4fc
--- /dev/null
+++ b/rust_uno/build.rs
@@ -0,0 +1,39 @@
+/* -*- Mode: rust; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- 
*/
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * 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/.
+ */
+
+//! Build script for rust_uno crate
+//!
+//! Links the generated C++ bridge library (librust_uno-cpp.so) to the Rust 
cdylib
+
+fn main() {
+    // Tell cargo to link against the rust_uno-cpp library
+    // This library contains the generated C++ bridge functions
+    println!("cargo:rustc-link-lib=rust_uno-cpplo");
+
+    // Add the LibreOffice instdir/program directory to the library search path
+    // This is where librust_uno-cpplo.so is located
+    if let Ok(instdir) = std::env::var("INSTDIR") {
+        println!("cargo:rustc-link-search=native={}/program", instdir);
+    }
+
+    // Also try the workdir path where the library might be during build
+    if let Ok(workdir) = std::env::var("WORKDIR") {
+        println!(
+            "cargo:rustc-link-search=native={}/LinkTarget/Library",
+            workdir
+        );
+    }
+
+    // Fallback: try relative paths from the rust_uno directory
+    println!("cargo:rustc-link-search=native=../instdir/program");
+    println!("cargo:rustc-link-search=native=../workdir/LinkTarget/Library");
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
+
diff --git a/rust_uno/example/Addons.xcu b/rust_uno/example/Addons.xcu
new file mode 100644
index 000000000000..9d906a2a4e9f
--- /dev/null
+++ b/rust_uno/example/Addons.xcu
@@ -0,0 +1,43 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ * This file is part of the LibreOffice project.
+ *
+ * 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/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ *   Licensed to the Apache Software Foundation (ASF) under one or more
+ *   contributor license agreements. See the NOTICE file distributed
+ *   with this work for additional information regarding copyright
+ *   ownership. The ASF licenses this file to you under the Apache
+ *   License, Version 2.0 (the "License"); you may not use this file
+ *   except in compliance with the License. You may obtain a copy of
+ *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ -->
+
+<o:items xmlns:o="http://openoffice.org/2001/registry";>
+  <item o:path="/org.openoffice.Office.Addons">
+    <node o:name="AddonUI">
+      <node o:name="OfficeMenuBar">
+        <node o:name="org.libreoffice.rust_uno.example"
+            o:op="replace">
+          <prop o:name="Title" xml:lang="en-US">
+            <value>Rust UNO</value>
+          </prop>
+          <node o:name="Submenu">
+            <node o:name="1" o:op="replace">
+              <prop o:name="URL">
+                <value>vnd.org.libreoffice.rust_uno.example:</value>
+              </prop>
+              <prop o:name="Title" xml:lang="en-US">
+                <value>Example</value>
+              </prop>
+            </node>
+          </node>
+        </node>
+      </node>
+    </node>
+  </item>
+</o:items>
diff --git a/rust_uno/example/META-INF/manifest.xml 
b/rust_uno/example/META-INF/manifest.xml
new file mode 100644
index 000000000000..51af7893f844
--- /dev/null
+++ b/rust_uno/example/META-INF/manifest.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ * This file is part of the LibreOffice project.
+ *
+ * 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/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ *   Licensed to the Apache Software Foundation (ASF) under one or more
+ *   contributor license agreements. See the NOTICE file distributed
+ *   with this work for additional information regarding copyright
+ *   ownership. The ASF licenses this file to you under the Apache
+ *   License, Version 2.0 (the "License"); you may not use this file
+ *   except in compliance with the License. You may obtain a copy of
+ *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ -->
+
+<m:manifest xmlns:m="http://openoffice.org/2001/manifest";>
+  <m:file-entry m:media-type="application/vnd.sun.star.configuration-data"
+      m:full-path="Addons.xcu"/>
+  <m:file-entry m:media-type="application/vnd.sun.star.configuration-data"
+      m:full-path="ProtocolHandler.xcu"/>
+  <m:file-entry
+      
m:media-type="application/vnd.sun.star.uno-components;platform=@PLATFORM@"
+      m:full-path="platform.components"/>
+</m:manifest>
diff --git a/rust_uno/example/ProtocolHandler.xcu 
b/rust_uno/example/ProtocolHandler.xcu
new file mode 100644
index 000000000000..2d205f7f878f
--- /dev/null
+++ b/rust_uno/example/ProtocolHandler.xcu
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ * This file is part of the LibreOffice project.
+ *
+ * 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/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ *   Licensed to the Apache Software Foundation (ASF) under one or more
+ *   contributor license agreements. See the NOTICE file distributed
+ *   with this work for additional information regarding copyright
+ *   ownership. The ASF licenses this file to you under the Apache
+ *   License, Version 2.0 (the "License"); you may not use this file
+ *   except in compliance with the License. You may obtain a copy of
+ *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ -->
+
+<o:component-data xmlns:o="http://openoffice.org/2001/registry";
+    o:package="org.openoffice.Office" o:name="ProtocolHandler">
+  <node o:name="HandlerSet">
+    <node o:name="org.libreoffice.rust_uno.example" o:op="replace">
+      <prop o:name="Protocols">
+        <value>vnd.org.libreoffice.rust_uno.example:*</value>
+      </prop>
+    </node>
+  </node>
+</o:component-data>
diff --git a/rust_uno/example/description.xml b/rust_uno/example/description.xml
new file mode 100644
index 000000000000..526680a84dbd
--- /dev/null
+++ b/rust_uno/example/description.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ * This file is part of the LibreOffice project.
+ *
+ * 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/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ *   Licensed to the Apache Software Foundation (ASF) under one or more
+ *   contributor license agreements. See the NOTICE file distributed
+ *   with this work for additional information regarding copyright
+ *   ownership. The ASF licenses this file to you under the Apache
+ *   License, Version 2.0 (the "License"); you may not use this file
+ *   except in compliance with the License. You may obtain a copy of
+ *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ -->
+
+<d:description xmlns:d="http://openoffice.org/extensions/description/2006";>
+  <d:identifier value="org.libreoffice/rust_uno/example"/>
+  <d:version value="1"/>
+  <d:dependencies>
+    <d:OpenOffice.org-minimal-version d:name="OpenOffice.org 3.4" value="3.4"/>
+  </d:dependencies>
+</d:description>
diff --git a/rust_uno/example/example.component 
b/rust_uno/example/example.component
new file mode 100644
index 000000000000..da779dac84c0
--- /dev/null
+++ b/rust_uno/example/example.component
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ * This file is part of the LibreOffice project.
+ *
+ * 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/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ *   Licensed to the Apache Software Foundation (ASF) under one or more
+ *   contributor license agreements. See the NOTICE file distributed
+ *   with this work for additional information regarding copyright
+ *   ownership. The ASF licenses this file to you under the Apache
+ *   License, Version 2.0 (the "License"); you may not use this file
+ *   except in compliance with the License. You may obtain a copy of
+ *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ -->
+
+<component loader="com.sun.star.loader.SharedLibrary"
+    xmlns="http://openoffice.org/2010/uno-components";>
+  <implementation name="org.libreoffice.comp.rust_uno.example">
+    <service name="org.libreoffice.rust_uno.example"/>
+  </implementation>
+  <implementation name="org.libreoffice.comp.rust_uno.example_singleton">
+    <singleton name="org.libreoffice.rust_uno.example_singleton"/>
+  </implementation>
+</component>
diff --git a/rust_uno/example/example.cxx b/rust_uno/example/example.cxx
new file mode 100644
index 000000000000..5fc0279281d5
--- /dev/null
+++ b/rust_uno/example/example.cxx
@@ -0,0 +1,243 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; 
fill-column: 100 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * 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/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ *   Licensed to the Apache Software Foundation (ASF) under one or more
+ *   contributor license agreements. See the NOTICE file distributed
+ *   with this work for additional information regarding copyright
+ *   ownership. The ASF licenses this file to you under the Apache
+ *   License, Version 2.0 (the "License"); you may not use this file
+ *   except in compliance with the License. You may obtain a copy of
+ *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sal/config.h>
+
+#include <cassert>
+
+#include <com/sun/star/beans/PropertyValue.hpp>
+#include <com/sun/star/frame/DispatchDescriptor.hpp>
+#include <com/sun/star/frame/Desktop.hpp>
+#include <com/sun/star/frame/XDispatch.hpp>
+#include <com/sun/star/frame/XDispatchProvider.hpp>
+#include <com/sun/star/frame/XStatusListener.hpp>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include <com/sun/star/uno/DeploymentException.hpp>
+#include <com/sun/star/uno/Exception.hpp>
+#include <com/sun/star/uno/Reference.hxx>
+#include <com/sun/star/uno/RuntimeException.hpp>
+#include <com/sun/star/uno/Sequence.hxx>
+#include <com/sun/star/uno/XComponentContext.hpp>
+#include <com/sun/star/uno/XInterface.hpp>
+#include <com/sun/star/util/URL.hpp>
+#include <cppuhelper/factory.hxx>
+#include <cppuhelper/implbase2.hxx>
+#include <cppuhelper/implementationentry.hxx>
+#include <cppuhelper/supportsservice.hxx>
+#include <cppuhelper/weak.hxx>
+#include <rtl/ustring.hxx>
+#include <sal/log.hxx>
+#include <sal/types.h>
+#include <uno/lbnames.h>
+
+#include "rust_uno_hook.hxx"
+
+namespace
+{
+class Provider
+    : public cppu::WeakImplHelper2<css::lang::XServiceInfo, 
css::frame::XDispatchProvider>
+{
+public:
+    Provider(const Provider&) = delete;
+    const Provider& operator=(const Provider&) = delete;
+
+    static css::uno::Reference<css::uno::XInterface>
+        SAL_CALL 
static_create(css::uno::Reference<css::uno::XComponentContext> const& xContext)
+    {
+        return static_cast<cppu::OWeakObject*>(new Provider(xContext));
+    }
+
+    static rtl::OUString SAL_CALL static_getImplementationName();
+
+    static css::uno::Sequence<rtl::OUString> SAL_CALL 
static_getSupportedServiceNames();
+
+private:
+    explicit Provider(css::uno::Reference<css::uno::XComponentContext> const& 
context)
+        : context_(context)
+    {
+        assert(context.is());
+    }
+
+    virtual ~Provider() {}
+
+    virtual rtl::OUString SAL_CALL getImplementationName() override
+    {
+        return static_getImplementationName();
+    }
+
+    virtual sal_Bool SAL_CALL supportsService(rtl::OUString const& 
ServiceName) override
+    {
+        return cppu::supportsService(this, ServiceName);
+    }
+
+    virtual css::uno::Sequence<rtl::OUString> SAL_CALL 
getSupportedServiceNames() override
+    {
+        return static_getSupportedServiceNames();
+    }
+
+    virtual css::uno::Reference<css::frame::XDispatch>
+        SAL_CALL queryDispatch(css::util::URL const&, rtl::OUString const&, 
sal_Int32) override;
+
+    virtual css::uno::Sequence<css::uno::Reference<css::frame::XDispatch>> 
SAL_CALL
+    queryDispatches(css::uno::Sequence<css::frame::DispatchDescriptor> const& 
Requests) override;
+
+    css::uno::Reference<css::uno::XComponentContext> context_;
+};
+
+rtl::OUString Provider::static_getImplementationName()
+{
+    return rtl::OUString("org.libreoffice.comp.rust_uno.example");
+}
+
+css::uno::Sequence<rtl::OUString> Provider::static_getSupportedServiceNames()
+{
+    rtl::OUString name("org.libreoffice.rust_uno.example");
+    return css::uno::Sequence<rtl::OUString>(&name, 1);
+}
+
+css::uno::Reference<css::frame::XDispatch> 
Provider::queryDispatch(css::util::URL const&,
+                                                                   
rtl::OUString const&, sal_Int32)
+{
+    css::uno::Reference<css::frame::XDispatch> dispatch;
+    if 
(!(context_->getValueByName("/singletons/org.libreoffice.rust_uno.example_singleton")
+          >>= dispatch)
+        || !dispatch.is())
+    {
+        throw css::uno::DeploymentException("component context fails to supply 
singleton "
+                                            
"org.libreoffice.rust_uno.example_singleton of type "
+                                            "com.sun.star.frame.XDispatch",
+                                            context_);
+    }
+    return dispatch;
+}
+
+css::uno::Sequence<css::uno::Reference<css::frame::XDispatch>>
+Provider::queryDispatches(css::uno::Sequence<css::frame::DispatchDescriptor> 
const& Requests)
+{
+    css::uno::Sequence<css::uno::Reference<css::frame::XDispatch>> 
s(Requests.getLength());
+    for (sal_Int32 i = 0; i < s.getLength(); ++i)
+    {
+        s[i]
+            = queryDispatch(Requests[i].FeatureURL, Requests[i].FrameName, 
Requests[i].SearchFlags);
+    }
+    return s;
+}
+
+class Dispatch : public cppu::WeakImplHelper2<css::lang::XServiceInfo, 
css::frame::XDispatch>
+{
+public:
+    Dispatch(const Dispatch&) = delete;
+    const Dispatch& operator=(const Dispatch&) = delete;
+
+    static css::uno::Reference<css::uno::XInterface>
+        SAL_CALL 
static_create(css::uno::Reference<css::uno::XComponentContext> const& xContext)
+    {
+        return static_cast<cppu::OWeakObject*>(new Dispatch(xContext));
+    }
+
+    static rtl::OUString SAL_CALL static_getImplementationName();
+
+    static css::uno::Sequence<rtl::OUString> SAL_CALL 
static_getSupportedServiceNames()
+    {
+        return css::uno::Sequence<rtl::OUString>();
+    }
+
+private:
+    explicit Dispatch(css::uno::Reference<css::uno::XComponentContext> const& 
context)
+        : context_(context)
+    {
+        assert(context.is());
+    }
+
+    virtual ~Dispatch() {}
+
+    virtual rtl::OUString SAL_CALL getImplementationName() override
+    {
+        return static_getImplementationName();
+    }
+
+    virtual sal_Bool SAL_CALL supportsService(rtl::OUString const& 
ServiceName) override
+    {
+        return cppu::supportsService(this, ServiceName);
+    }
+
+    virtual css::uno::Sequence<rtl::OUString> SAL_CALL 
getSupportedServiceNames() override
+    {
+        return static_getSupportedServiceNames();
+    }
+
+    virtual void SAL_CALL dispatch(css::util::URL const&,
+                                   
css::uno::Sequence<css::beans::PropertyValue> const&) override;
+
+    virtual void SAL_CALL 
addStatusListener(css::uno::Reference<css::frame::XStatusListener> const&,
+                                            css::util::URL const&) override
+    {
+    }
+
+    virtual void SAL_CALL removeStatusListener(
+        css::uno::Reference<css::frame::XStatusListener> const&, 
css::util::URL const&) override
+    {
+    }
+
+    css::uno::Reference<css::uno::XComponentContext> context_;
+};
+
+rtl::OUString Dispatch::static_getImplementationName()
+{
+    return rtl::OUString("org.libreoffice.comp.rust_uno.example_singleton");
+}
+
+void Dispatch::dispatch(css::util::URL const&, 
css::uno::Sequence<css::beans::PropertyValue> const&)
+{
+    // === RUST UNO BINDING TEST ===
+    // Call our Rust UNO binding to test it works within LibreOffice
+    SAL_INFO("desktop.app", "Testing Rust UNO binding...");
+    try
+    {
+        run_rust_uno_test();
+        SAL_INFO("desktop.app", "Rust UNO binding test completed 
successfully!");
+    }
+    catch (...)
+    {
+        SAL_WARN("desktop.app", "Rust UNO binding test failed!");
+    }
+}
+
+cppu::ImplementationEntry const services[] = {
+    { &Provider::static_create, &Provider::static_getImplementationName,
+      &Provider::static_getSupportedServiceNames, 
&cppu::createSingleComponentFactory, nullptr, 0 },
+    { &Dispatch::static_create, &Dispatch::static_getImplementationName,
+      &Dispatch::static_getSupportedServiceNames, 
&cppu::createSingleComponentFactory, nullptr, 0 },
+    { nullptr, nullptr, nullptr, nullptr, nullptr, 0 }
+};
+}
+
+extern "C" SAL_DLLPUBLIC_EXPORT void*
+component_getFactory(char const* pImplName, void* pServiceManager, void* 
pRegistryKey)
+{
+    return cppu::component_getFactoryHelper(pImplName, pServiceManager, 
pRegistryKey, services);
+}
+
+extern "C" SAL_DLLPUBLIC_EXPORT void
+component_getImplementationEnvironment(char const** ppEnvTypeName, 
uno_Environment**)
+{
+    *ppEnvTypeName = CPPU_CURRENT_LANGUAGE_BINDING_NAME;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s 
cinkeys+=0=break: */
diff --git a/rust_uno/example/rust_uno_hook.hxx 
b/rust_uno/example/rust_uno_hook.hxx
new file mode 100644
index 000000000000..8987ffeb8b4f
--- /dev/null
+++ b/rust_uno/example/rust_uno_hook.hxx
@@ -0,0 +1,17 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * 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/.
+ */
+
+#pragma once
+
+extern "C" {
+/// Function from the Rust UNO binding library that we'll call from LibreOffice
+void run_rust_uno_test();
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/rust_uno/src/core/any.rs b/rust_uno/src/core/any.rs
new file mode 100644
index 000000000000..7e307239720b
--- /dev/null
+++ b/rust_uno/src/core/any.rs
@@ -0,0 +1,257 @@
+/* -*- Mode: rust; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- 
*/
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * 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/.
+ */
+
+//! UNO Any Types and Functions
+//!
+//! This module provides the high-level safe Rust wrapper around LibreOffice's 
uno_Any.
+//! It includes automatic memory management and safe conversions to/from Rust 
values.
+//!
+//! ## Key Components
+//! - `Any` - Safe Rust wrapper around LibreOffice's uno_Any
+//! - Value conversion functions with automatic type handling
+//! - Memory management with automatic cleanup
+//!
+//! ## Features
+//! - Safe construction from various Rust types
+//! - Automatic memory management via RAII
+//! - Safe value extraction with type checking
+//! - Clone, equality, and display trait implementations
+//! - Direct FFI interop with raw pointer access methods
+
+use crate::ffi::uno_any::*;
+// Interface operations now use generated XInterface wrapper methods
+// TODO: Replace with generated XInterface::from_ptr(ptr).acquire() pattern
+
+// === Safe UNO Any Wrapper ===
+
+/// UNO Any wrapper - a safe Rust wrapper around LibreOffice's uno_Any
+///
+/// Any provides a safe, memory-managed interface to LibreOffice's native
+/// any type. It automatically handles reference counting and memory cleanup.
+pub struct Any {
+    inner: uno_Any,
+}
+
+impl Any {
+    /// Create a new empty UNO Any (void type)
+    ///
+    /// This creates an empty Any that contains no value (void type).
+    pub fn new() -> Self {
+        unsafe {
+            let mut any = Any {
+                inner: uno_Any {
+                    pType: std::ptr::null_mut(),
+                    pData: std::ptr::null_mut(),
+                    pReserved: std::ptr::null_mut(),
+                },
+            };
+
+            // Initialize as void using uno_any_construct
+            uno_any_construct(
+                &mut any.inner,
+                std::ptr::null_mut(), // pSource (null for void)
+                std::ptr::null_mut(), // pTypeDescr (null for void)
+                None,
+            );
+            any
+        }
+    }
+
+    /// Create Any from a boolean value
+    ///
+    /// This creates an Any containing a boolean value.
+    pub fn from_bool(value: bool) -> Self {
+        unsafe {
+            let mut any = Any {
+                inner: uno_Any {
+                    pType: std::ptr::null_mut(),
+                    pData: std::ptr::null_mut(),
+                    pReserved: std::ptr::null_mut(),
+                },
+            };
+
+            let bool_val = if value { 1u8 } else { 0u8 };
+
+            // Initialize with boolean data using uno_type_any_construct
+            uno_type_any_construct(
+                &mut any.inner,
+                &bool_val as *const u8 as *mut std::ffi::c_void,
+                get_boolean_type(),
+                None,
+            );
+            any
+        }
+    }
+
+    /// Create Any from a 32-bit integer
+    ///
+    /// This creates an Any containing a 32-bit signed integer.
+    pub fn from_i32(value: i32) -> Self {
+        unsafe {
+            let mut any = Any {
+                inner: uno_Any {
+                    pType: std::ptr::null_mut(),
+                    pData: std::ptr::null_mut(),
+                    pReserved: std::ptr::null_mut(),
+                },
+            };
+
+            // Initialize with integer data using uno_type_any_construct
+            uno_type_any_construct(
+                &mut any.inner,
+                &value as *const i32 as *mut std::ffi::c_void,
+                get_long_type(),
+                None,
+            );
+
+            any
+        }
+    }
+
+    /// Create Any from raw uno_Any (takes ownership)
+    ///
+    /// # Safety
+    /// The caller must ensure that:
+    /// - The uno_Any is valid and properly initialized
+    /// - The uno_Any is not used elsewhere after this call
+    /// - Proper reference counting is maintained
+    pub unsafe fn from_raw(any: uno_Any) -> Self {
+        Any { inner: any }
+    }
+
+    /// Convert to raw uno_Any (releases ownership)
+    ///
+    /// The caller becomes responsible for calling uno_any_destruct
+    pub fn into_raw(self) -> uno_Any {
+        unsafe {
+            let inner = std::ptr::read(&self.inner);
+            std::mem::forget(self); // Don't run destructor
+            inner
+        }
+    }
+
+    /// Get the raw pointer for FFI calls (retains ownership)
+    pub fn as_ptr(&self) -> *const uno_Any {
+        &self.inner
+    }
+
+    /// Get the mutable raw pointer for FFI calls (retains ownership)
+    pub fn as_mut_ptr(&mut self) -> *mut uno_Any {
+        &mut self.inner
+    }
+
+    /// Check if the Any contains a value (not void)
+    pub fn has_value(&self) -> bool {
+        !self.inner.pType.is_null()
+    }
+
+    /// Clear the Any (set to void)
+    pub fn clear(&mut self) {
+        unsafe {
+            uno_any_clear(&mut self.inner, None);
+        }
+    }
+}
+
+impl Default for Any {
+    fn default() -> Self {
+        Self::new()
+    }
+}
+
+/// Clone implementation: Create a copy of another Any
+///
+/// This creates a new Any that contains the same value but is independently
+/// managed (proper deep copy with reference counting).
+impl Clone for Any {
+    fn clone(&self) -> Self {
+        let mut new_any = Any::new();
+
+        if self.has_value() {
+            unsafe {
+                // Clone by assigning from the existing any's data using type 
reference
+                uno_type_any_assign(
+                    &mut new_any.inner,
+                    self.inner.pData,
+                    self.inner.pType,
+                    None,
+                    None,
+                );
+            }
+        }
+
+        new_any
+    }
+}
+
+/// Comparison with other Any
+impl PartialEq for Any {
+    fn eq(&self, other: &Self) -> bool {
+        // Handle cases where one or both are void
+        match (self.has_value(), other.has_value()) {
+            (false, false) => true,                 // Both void = equal
+            (false, true) | (true, false) => false, // One void, one not = not 
equal
+            (true, true) => {
+                // Both have values - basic pointer comparison for now
+                self.inner.pType == other.inner.pType && self.inner.pData == 
other.inner.pData
+            }
+        }
+    }
+}
+
+impl Eq for Any {}
+
+/// From trait implementation for bool
+impl From<bool> for Any {
+    fn from(value: bool) -> Self {
+        Self::from_bool(value)
+    }
+}
+
+/// From trait implementation for i32
+impl From<i32> for Any {
+    fn from(value: i32) -> Self {
+        Self::from_i32(value)
+    }
+}
+
+/// Display trait for printing
+impl std::fmt::Display for Any {
+    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+        if !self.has_value() {
+            write!(f, "Any(void)")
+        } else {
+            write!(f, "Any(<value>)")
+        }
+    }
+}
+
+/// Debug trait for debugging
+impl std::fmt::Debug for Any {
+    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+        f.debug_struct("Any")
+            .field("has_value", &self.has_value())
+            .field("pType", &self.inner.pType)
+            .field("pData", &self.inner.pData)
+            .finish()
+    }
+}
+
+/// Destructor: Automatic cleanup when Any goes out of scope
+impl Drop for Any {
+    fn drop(&mut self) {
+        if self.has_value() {
+            unsafe {
+                uno_any_destruct(&mut self.inner, None);
+            }
+        }
+    }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/rust_uno/src/core/mod.rs b/rust_uno/src/core/mod.rs
new file mode 100644
index 000000000000..0546fdf51917
--- /dev/null
+++ b/rust_uno/src/core/mod.rs
@@ -0,0 +1,37 @@
+/* -*- Mode: rust; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- 
*/
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * 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/.
+ */
+
+//! Core Module
+//!
+//! This module contains the high-level safe Rust wrappers for LibreOffice UNO 
types.
+//! These provide memory-safe, idiomatic Rust interfaces to the underlying C 
APIs.
+
+pub mod any;
+pub mod oustring;
+pub mod sequence;
+pub mod r#type;
+pub mod uno_wrapper;
+
+// Re-export the main types for convenience
+pub use crate::ffi::type_ffi::typelib_TypeClass;
+pub use any::Any;
+pub use oustring::OUString;
+pub use sequence::Sequence;
+pub use r#type::Type;
+// UnoInterface replaced with generated XInterface from rustmaker
+pub use uno_wrapper::{UnoError, UnoResult, 
defaultBootstrap_InitialComponentContext};
+
+// Include unit tests
+#[cfg(test)]
+mod tests {
+    mod string_tests;
+    mod type_tests;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/rust_uno/src/core/oustring.rs b/rust_uno/src/core/oustring.rs
new file mode 100644
index 000000000000..8be5188168e1
--- /dev/null
+++ b/rust_uno/src/core/oustring.rs
@@ -0,0 +1,256 @@
+/* -*- Mode: rust; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- 
*/
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * 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/.
+ */
+
+//! UNO String Types and Functions
+//!
+//! This module provides the high-level safe Rust wrapper around LibreOffice's 
rtl_uString.
+//! It includes automatic memory management and safe conversions to/from Rust 
strings.
+//!
+//! ## Key Components
+//! - `OUString` - Safe Rust wrapper around LibreOffice's rtl_uString
+//! - String conversion functions with automatic encoding handling
+//! - Memory management with automatic reference counting
+//!
+//! ## Features
+//! - UTF-8, UTF-16, and ASCII string creation methods
+//! - Automatic memory management via RAII
+//! - Safe conversion to/from Rust strings
+//! - Clone, equality, and display trait implementations
+//! - Direct FFI interop with raw pointer access methods
+
+use std::ptr::NonNull;
+
+use crate::ffi::rtl_string::*;
+use crate::ffi::sal_types::*;
+
+// === Safe UNO String Wrapper ===
+
+/// UNO String wrapper - a safe Rust wrapper around LibreOffice's rtl_uString
+///
+/// OUString provides a safe, memory-managed interface to LibreOffice's native
+/// string type. It automatically handles reference counting and memory 
cleanup,
+/// and provides conversions to/from standard Rust string types.
+pub struct OUString {
+    inner: NonNull<rtl_uString>,
+}
+
+impl OUString {
+    /// Create a new empty UNO string
+    ///
+    /// This creates an empty OUString with zero length.
+    pub fn new() -> Self {
+        unsafe {
+            let mut ptr: *mut rtl_uString = std::ptr::null_mut();
+            rtl_uString_new(&mut ptr);
+
+            // Convert to NonNull, panic if allocation failed
+            let inner =
+                NonNull::new(ptr).expect("RTL string allocation failed - 
system out of memory");
+
+            OUString { inner }
+        }
+    }
+
+    /// Create a UNO string from UTF-8 text
+    ///
+    /// This uses LibreOffice's direct UTF-8 to UString conversion function,
+    /// which is more efficient than converting through UTF-16. Handles all
+    /// valid UTF-8 including Unicode characters and emojis.
+    pub fn from_utf8(text: &str) -> Self {
+        unsafe {
+            let mut ptr: *mut rtl_uString = std::ptr::null_mut();
+            rtl_string2UString(
+                &mut ptr,
+                text.as_ptr() as *const std::os::raw::c_char,
+                text.len() as sal_Int32,
+                RTL_TEXTENCODING_UTF8,
+                OSTRING_TO_OUSTRING_CVTFLAGS,
+            );
+
+            let inner = NonNull::new(ptr).expect("RTL UTF-8 string creation 
failed");
+
+            OUString { inner }
+        }
+    }
+
+    /// Create a UNO string from ASCII text
+    ///
+    /// This method uses LibreOffice's native ASCII conversion function for
+    /// actual ASCII text (7-bit characters only). More efficient than UTF-8
+    /// conversion when you know the text is pure ASCII.
+    pub fn from_ascii(text: &str) -> Self {
+        unsafe {
+            let mut ptr: *mut rtl_uString = std::ptr::null_mut();
+            // Ensure the string is null-terminated for the C function
+            let c_string = std::ffi::CString::new(text).expect("CString 
creation failed");
+            rtl_uString_newFromAscii(&mut ptr, c_string.as_ptr());
+
+            let inner = NonNull::new(ptr).expect("RTL ASCII string creation 
failed");
+
+            OUString { inner }
+        }
+    }
+
+    /// Create OUString from UTF-16 data
+    ///
+    /// Creates a UNO string directly from UTF-16 data. This is the most 
efficient
+    /// method when you already have UTF-16 data, since LibreOffice uses UTF-16
+    /// internally (sal_Unicode is UTF-16 code units).
+    pub fn from_utf16(data: &[sal_Unicode]) -> Self {
+        unsafe {
+            let mut ptr: *mut rtl_uString = std::ptr::null_mut();
+            rtl_uString_newFromStr_WithLength(&mut ptr, data.as_ptr(), 
data.len() as sal_Int32);
+
+            let inner = NonNull::new(ptr).expect("RTL UTF-16 string creation 
failed");
+
+            OUString { inner }
+        }
+    }
+
+    /// Create OUString from raw rtl_uString pointer (takes ownership)
+    ///
+    /// # Safety
+    /// The caller must ensure that:
+    /// - The pointer is valid and points to a properly initialized rtl_uString
+    /// - The pointer is not used elsewhere after this call
+    /// - The rtl_uString has the correct reference count
+    pub unsafe fn from_raw(str: *mut rtl_uString) -> Self {
+        let inner = NonNull::new(str).expect("Cannot create OUString from null 
pointer");
+
+        unsafe {
+            rtl_uString_acquire(inner.as_ptr());
+        }
+        OUString { inner }
+    }
+
+    /// Convert to raw rtl_uString pointer (releases ownership)
+    ///
+    /// The caller becomes responsible for calling rtl_uString_release
+    pub fn into_raw(self) -> *mut rtl_uString {
+        let ptr = self.inner.as_ptr();
+        std::mem::forget(self); // Don't run destructor
+        ptr
+    }
+
+    /// Get the raw pointer for FFI calls (retains ownership)
+    pub fn as_ptr(&self) -> *const rtl_uString {
+        self.inner.as_ptr() as *const _
+    }
+
+    /// Get the mutable raw pointer for FFI calls (retains ownership)
+    pub fn as_mut_ptr(&mut self) -> *mut rtl_uString {
+        self.inner.as_ptr()
+    }
+
+    /// Get the length of the string
+    pub fn len(&self) -> usize {
+        unsafe { rtl_uString_getLength(self.inner.as_ptr()) as usize }
+    }
+
+    /// Check if the string is empty
+    pub fn is_empty(&self) -> bool {
+        self.len() == 0
+    }
+}
+
+impl Default for OUString {
+    fn default() -> Self {
+        Self::new()
+    }
+}
+
+/// Clone implementation: Create a copy of another OUString
+///
+/// This creates a new OUString that shares the same content but is 
independently
+/// managed (proper deep copy with reference counting).
+impl Clone for OUString {
+    fn clone(&self) -> Self {
+        unsafe {
+            rtl_uString_acquire(self.inner.as_ptr());
+            OUString { inner: self.inner }
+        }
+    }
+}
+
+/// From trait implementation for &str (UTF-8)
+///
+/// Convenient conversion from string slices to OUString using UTF-8 encoding.
+impl<T: AsRef<str>> From<T> for OUString {
+    fn from(text: T) -> Self {
+        Self::from_utf8(text.as_ref())
+    }
+}
+
+/// Comparison with other OUString
+impl PartialEq for OUString {
+    fn eq(&self, other: &Self) -> bool {
+        unsafe {
+            // Compare lengths first (fast check)
+            let self_len = rtl_uString_getLength(self.inner.as_ptr());
+            let other_len = rtl_uString_getLength(other.inner.as_ptr());
+
+            if self_len != other_len {
+                return false;
+            }
+
+            // If lengths are equal, compare UTF-16 data directly
+            if self_len == 0 {
+                return true; // Both empty strings
+            }
+
+            let self_ptr = rtl_uString_getStr(self.inner.as_ptr());
+            let other_ptr = rtl_uString_getStr(other.inner.as_ptr());
+
+            // Compare UTF-16 data byte by byte
+            let self_slice = std::slice::from_raw_parts(self_ptr, self_len as 
usize);
+            let other_slice = std::slice::from_raw_parts(other_ptr, other_len 
as usize);
+
+            self_slice == other_slice
+        }
+    }
+}
+
+impl Eq for OUString {}
+
+/// Display trait for printing
+impl std::fmt::Display for OUString {
+    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+        if self.is_empty() {
+            return Ok(());
+        }
+
+        unsafe {
+            let ptr = rtl_uString_getStr(self.inner.as_ptr());
+            let len = rtl_uString_getLength(self.inner.as_ptr()) as usize;
+
+            // Convert from UTF-16 to UTF-8
+            let utf16_slice = std::slice::from_raw_parts(ptr, len);
+            let string = String::from_utf16_lossy(utf16_slice);
+            write!(f, "{string}")
+        }
+    }
+}
+
+/// Debug trait for debugging - shows type and content for UNO string 
identification
+impl std::fmt::Debug for OUString {
+    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+        f.debug_tuple("OUString").field(&self.to_string()).finish()
+    }
+}
+
+/// Destructor: Automatic cleanup when OUString goes out of scope
+impl Drop for OUString {
+    fn drop(&mut self) {
+        unsafe {
+            rtl_uString_release(self.inner.as_ptr());
+        }
+    }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/rust_uno/src/core/sequence.rs b/rust_uno/src/core/sequence.rs
new file mode 100644
index 000000000000..f9d8a237b0a2
--- /dev/null
+++ b/rust_uno/src/core/sequence.rs
@@ -0,0 +1,245 @@
+/* -*- Mode: rust; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- 
*/
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * 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/.
+ */
+
+//! UNO Sequence Types and Functions
+//!
+//! This module provides the high-level safe Rust wrapper around LibreOffice's 
uno_Sequence.
+//! It includes automatic memory management and safe conversions to/from Rust 
values.
+//!
+//! ## Key Components
+//! - `Sequence` - Safe Rust wrapper around LibreOffice's uno_Sequence
+//! - Value conversion functions with automatic type handling
+//! - Memory management with automatic cleanup
+//!
+//! ## Features
+//! - Safe construction from various Rust types
+//! - Automatic memory management via RAII
+//! - Safe value extraction with type checking
+//! - Clone, equality, and display trait implementations
+//! - Direct FFI interop with raw pointer access methods
+
+use crate::core::r#type::*;
+use crate::ffi::type_ffi::*;
+// Interface operations now use generated XInterface wrapper methods
+// TODO: Replace with generated XInterface::from_ptr(ptr).acquire() pattern
+use crate::ffi::uno_sequence::*;
+use std::ptr::NonNull;
+
+// === Safe UNO Sequence Wrapper ===
+
+/// UNO Sequence wrapper - a safe Rust wrapper around LibreOffice's 
uno_Sequence
+///
+/// Sequence provides a safe, memory-managed interface to LibreOffice's native
+/// Sequence type. It automatically handles reference counting and memory 
cleanup.
+pub struct Sequence {
+    inner: NonNull<uno_Sequence>,
+}
+
+impl Sequence {
+    /// Create a new empty Sequence
+    ///
+    /// Creates an empty sequence of Any elements, similar to the C++ default 
constructor.
+    /// The sequence will be empty (0 elements) and uses the Any type as the 
element type.
+    pub fn new() -> Self {
+        Self::with_capacity(0)
+    }
+
+    pub fn with_capacity(capacity: i32) -> Self {
+        if capacity < 0 {
+            panic!("Sequence capacity cannot be negative: {}", capacity);
+        }
+        unsafe {
+            let mut ptr: *mut uno_Sequence = std::ptr::null_mut();
+
+            // Create an Any type for the sequence elements
+            let element_type = Type::new();
+
+            // Get the type description from the type reference
+            let mut type_desc = std::ptr::null_mut();
+            typelib_typedescriptionreference_getDescription(
+                &mut type_desc,
+                element_type.get_typelib_type(),
+            );
+
+            // Construct empty sequence
+            let success = uno_type_sequence_construct(
+                &mut ptr,
+                type_desc,
+                std::ptr::null(),
+                capacity,
+                None, // TODO: Replace with generated XInterface acquire 
wrapper
+            );
+
+            // Check for construction success
+            if success == 0 {
+                panic!("Failed to construct UNO sequence");
+            }
+
+            Sequence {
+                inner: NonNull::new(ptr)
+                    .expect("uno_type_sequence_construct returned null 
pointer"),
+            }
+        }
+    }
+
+    /// Get the length of the sequence
+    ///
+    /// Returns the number of elements in this sequence.
+    /// Equivalent to C++ `getLength()` method.
+    pub fn get_length(&self) -> i32 {
+        unsafe { self.inner.as_ref().nElements }
+    }
+
+    /// Check if the sequence has elements
+    ///
+    /// Returns true if the sequence contains at least one element.
+    /// Equivalent to C++ `hasElements()` method.
+    pub fn has_elements(&self) -> bool {
+        self.get_length() > 0
+    }
+
+    /// Get the length as usize for Rust iterator compatibility
+    ///
+    /// Returns the length as usize, which is commonly used in Rust.
+    pub fn len(&self) -> usize {
+        self.get_length() as usize
+    }
+
+    /// Check if the sequence is empty
+    ///
+    /// Returns true if the sequence has no elements.
+    pub fn is_empty(&self) -> bool {
+        self.get_length() == 0
+    }
+
+    /// Get raw pointer to the underlying uno_Sequence
+    ///
+    /// This provides direct access to the underlying UNO sequence for FFI 
interop.
+    /// The returned pointer remains valid as long as this Sequence instance 
exists.
+    pub fn as_raw(&self) -> *mut uno_Sequence {
+        self.inner.as_ptr()
+    }
+
+    /// Get the raw pointer for FFI calls (retains ownership)
+    pub fn as_ptr(&self) -> *const uno_Sequence {
+        self.inner.as_ptr() as *const _
+    }
+
+    /// Get the mutable raw pointer for FFI calls (retains ownership)
+    pub fn as_mut_ptr(&mut self) -> *mut uno_Sequence {
+        self.inner.as_ptr()
+    }
+}
+
+impl Default for Sequence {
+    fn default() -> Self {
+        Self::new()
+    }
+}
+
+/// Clone implementation: Create an independent copy of another Sequence
+///
+/// This creates a new Sequence that references the same sequence data but is
+/// independently managed. The clone operation increments the reference count
+/// of the underlying sequence, ensuring proper memory management.
+impl Clone for Sequence {
+    fn clone(&self) -> Self {
+        unsafe {
+            let ptr = self.inner.as_ptr();
+            // Increment reference count
+            (*ptr).nRefCount += 1;
+
+            Sequence {
+                inner: NonNull::new(ptr).expect("Cloning sequence with invalid 
pointer"),
+            }
+        }
+    }
+}
+
+/// Equality comparison with other Sequence instances
+///
+/// Two Sequence instances are considered equal if they have the same length
+/// and contain the same elements in the same order. This uses pointer 
comparison
+/// for efficiency when both sequences reference the same underlying data.
+impl PartialEq for Sequence {
+    fn eq(&self, other: &Self) -> bool {
+        unsafe {
+            let self_ptr = self.inner.as_ptr();
+            let other_ptr = other.inner.as_ptr();
+
+            // Fast path: same pointer
+            if self_ptr == other_ptr {
+                return true;
+            }
+
+            let self_seq = self.inner.as_ref();
+            let other_seq = other.inner.as_ref();
+
+            // Different lengths means not equal
+            if self_seq.nElements != other_seq.nElements {
+                return false;
+            }
+
+            // For now, do basic comparison - in a full implementation,
+            // this would need to compare actual element values
+            self_seq.nElements == other_seq.nElements
+        }
+    }
+}
+
+impl Eq for Sequence {}
+
+/// Debug trait for debugging - shows sequence length and type for UNO 
sequence identification
+impl std::fmt::Debug for Sequence {
+    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+        f.debug_tuple("Sequence")
+            .field(&format!("length={}", self.get_length()))
+            .finish()
+    }
+}
+
+/// Display trait for printing sequences
+///
+/// Provides a user-friendly string representation of the sequence.
+impl std::fmt::Display for Sequence {
+    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+        if self.is_empty() {
+            write!(f, "Sequence[]")
+        } else {
+            write!(f, "Sequence[{}]", self.get_length())
+        }
+    }
+}
+
+/// Destructor: Automatic cleanup when Sequence goes out of scope
+impl Drop for Sequence {
+    fn drop(&mut self) {
+        unsafe {
+            let ptr = self.inner.as_ptr();
+            let seq = &mut *ptr;
+            seq.nRefCount -= 1;
+
+            // If reference count reaches zero, destroy the sequence
+            if seq.nRefCount == 0 {
+                // Get the element type for proper cleanup
+                let element_type = Type::new();
+                let mut type_desc = std::ptr::null_mut();
+                typelib_typedescriptionreference_getDescription(
+                    &mut type_desc,
+                    element_type.get_typelib_type(),
+                );
+
+                // Call UNO sequence destructor
+                uno_type_sequence_destroy(ptr, type_desc, None); // TODO: 
Replace with generated XInterface release wrapper
+            }
+        }
+    }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/rust_uno/src/core/tests/string_tests.rs 
b/rust_uno/src/core/tests/string_tests.rs
new file mode 100644
index 000000000000..b931dfa6a2ba
--- /dev/null
+++ b/rust_uno/src/core/tests/string_tests.rs
@@ -0,0 +1,387 @@
+/* -*- Mode: rust; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- 
*/
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * 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/.
+ */
+
+//! Unit tests for OUString (Rust-side functionality)
+//!
+//! These tests verify OUString's Rust implementation including:
+//! - Creation methods (new, from_utf8, from_ascii, from_utf16)
+//! - Trait implementations (Clone, PartialEq, From, Display, Debug, Default)
+//! - Instance methods (len, is_empty, as_ptr, etc.)
+//! - Memory management and safety (RAII, reference counting)
+//! - FFI interop (from_raw, into_raw)
+//!
+//! These tests do NOT require LibreOffice UNO components and test
+//! only the Rust-side implementation and FFI safety.
+
+use crate::core::OUString;
+
+// === Creation Method Tests ===
+
+#[test]
+fn test_oustring_new() {
+    let s = OUString::new();
+    assert_eq!(s.len(), 0);
+    assert!(s.is_empty());
+    assert_eq!(s.to_string(), "");
+}
+
+#[test]
+fn test_oustring_default() {
+    let s = OUString::default();
+    assert_eq!(s.len(), 0);
+    assert!(s.is_empty());
+    assert_eq!(s.to_string(), "");
+}
+
+#[test]
+fn test_oustring_from_utf8() {
+    let s = OUString::from_utf8("Hello, 世界!");
+    assert!(!s.is_empty());
+    assert_eq!(s.to_string(), "Hello, 世界!");
+
+    // Test empty string
+    let empty = OUString::from_utf8("");
+    assert!(empty.is_empty());
+    assert_eq!(empty.len(), 0);
+
+    // Test with Unicode characters
+    let unicode = OUString::from_utf8("Ñiño 🦀 café");
+    assert_eq!(unicode.to_string(), "Ñiño 🦀 café");
+}
+
+#[test]
+fn test_oustring_from_ascii() {
+    let s = OUString::from_ascii("Hello, World!");
+    assert_eq!(s.to_string(), "Hello, World!");
+    assert!(!s.is_empty());
+
+    // Test empty ASCII string
+    let empty = OUString::from_ascii("");
+    assert!(empty.is_empty());
+    assert_eq!(empty.len(), 0);
+}
+
+// === Trait Implementation Tests ===
+
+#[test]
+fn test_oustring_clone() {
+    let original = OUString::from_utf8("Test string for cloning");
+    let cloned = original.clone();
+
+    // They should be equal
+    assert_eq!(original, cloned);
+    assert_eq!(original.to_string(), cloned.to_string());
+    assert_eq!(original.len(), cloned.len());
+
+    // Test cloning empty string
+    let empty = OUString::new();
+    let empty_clone = empty.clone();
+    assert_eq!(empty, empty_clone);
+    assert!(empty_clone.is_empty());
+}
+
+#[test]
+fn test_oustring_partial_eq() {
+    let s1 = OUString::from_utf8("Hello");
+    let s2 = OUString::from_utf8("Hello");
+    let s3 = OUString::from_utf8("World");
+    let empty1 = OUString::new();
+    let empty2 = OUString::new();
+
+    // Equal strings
+    assert_eq!(s1, s2);
+    assert_eq!(empty1, empty2);
+
+    // Different strings
+    assert_ne!(s1, s3);
+    assert_ne!(s1, empty1);
+    assert_ne!(empty1, s1);
+
+    // Test with Unicode
+    let unicode1 = OUString::from_utf8("café");
+    let unicode2 = OUString::from_utf8("café");
+    let unicode3 = OUString::from_utf8("cafe"); // without accent
+
+    assert_eq!(unicode1, unicode2);
+    assert_ne!(unicode1, unicode3);
+}
+
+#[test]
+fn test_oustring_from_str() {
+    let s = OUString::from("Hello from &str");
+    assert_eq!(s.to_string(), "Hello from &str");
+
+    // Test with Unicode
+    let unicode: OUString = "Héllo wørld 🌍".into();
+    assert_eq!(unicode.to_string(), "Héllo wørld 🌍");
+}
+
+#[test]
+fn test_oustring_from_string() {
+    let rust_string = String::from("Hello from String");
+    let s = OUString::from(rust_string);
+    assert_eq!(s.to_string(), "Hello from String");
+
+    // Test with owned Unicode String
+    let unicode_string = "Ñiño 🦀".to_string();
+    let unicode_oustring = OUString::from(unicode_string);
+    assert_eq!(unicode_oustring.to_string(), "Ñiño 🦀");
+}
+
+#[test]
+fn test_oustring_display() {
+    let s = OUString::from_utf8("Display test");
+    assert_eq!(format!("{s}"), "Display test");
+
+    // Test empty string display
+    let empty = OUString::new();
+    assert_eq!(format!("{empty}"), "");
+
+    // Test Unicode display
+    let unicode = OUString::from_utf8("Display 测试 🦀");
+    assert_eq!(format!("{unicode}"), "Display 测试 🦀");
+}
+
+#[test]
+fn test_oustring_debug() {
+    let s = OUString::from_utf8("Debug test");
+    let debug_output = format!("{s:?}");
+    assert!(debug_output.contains("OUString"));
+    assert!(debug_output.contains("Debug test"));
+
+    // Test empty string debug
+    let empty = OUString::new();
+    let empty_debug = format!("{empty:?}");
+    assert!(empty_debug.contains("OUString"));
+}
+
+// === Method Tests ===
+
+#[test]
+fn test_oustring_len() {
+    let empty = OUString::new();
+    assert_eq!(empty.len(), 0);
+
+    let ascii = OUString::from_utf8("Hello");
+    assert_eq!(ascii.len(), 5);
+
+    // Note: len() returns UTF-16 code units, not Unicode codepoints
+    let unicode = OUString::from_utf8("café"); // 'é' is one UTF-16 unit
+    assert_eq!(unicode.len(), 4);
+
+    // Emoji takes 2 UTF-16 code units (surrogate pair)
+    let emoji = OUString::from_utf8("🦀");
+    assert_eq!(emoji.len(), 2);
+}
+
+#[test]
+fn test_oustring_is_empty() {
+    let empty = OUString::new();
+    assert!(empty.is_empty());
+
+    let non_empty = OUString::from_utf8("Not empty");
+    assert!(!non_empty.is_empty());
+
+    let empty_from_str = OUString::from_utf8("");
+    assert!(empty_from_str.is_empty());
+}
+
+// === Special Cases and Edge Cases ===
+
+#[test]
+fn test_oustring_special_characters() {
+    // Test various special Unicode characters
+    let special_chars = vec![
+        "
+        "
",   // Newline
+        "
", // Windows line ending
+        "      ",   // Tab
+        "\"",   // Quote
+        "\",   // Backslash
+        "©",    // Copyright symbol
+        "€",    // Euro symbol
+        "™",    // Trademark
+        "🦀",   // Rust crab emoji
+        "👨‍💻",   // Man technologist (complex emoji)
+    ];
+
+    for special in special_chars {
+        let s = OUString::from_utf8(special);
+        assert_eq!(s.to_string(), special);
+    }
+}
+
+#[test]
+fn test_oustring_long_strings() {
+    // Test with long strings to ensure proper memory management
+    let long_text = "A".repeat(10000);
+    let s = OUString::from_utf8(&long_text);
+    assert_eq!(s.len(), 10000);
+    assert_eq!(s.to_string(), long_text);
+
+    // Test cloning long strings
+    let cloned = s.clone();
+    assert_eq!(cloned, s);
+    assert_eq!(cloned.len(), 10000);
+}
+
+#[test]
+fn test_oustring_multilingual() {
+    // Test various languages and scripts
+    let multilingual = "English, 中文, العربية, Русский, ελληνικά, עברית";
+    let s = OUString::from_utf8(multilingual);
+    assert_eq!(s.to_string(), multilingual);
+    assert!(!s.is_empty());
+}
+
+#[test]
+fn test_oustring_consistency_across_constructors() {
+    let text = "Test consistency";
+
+    let from_utf8 = OUString::from_utf8(text);
+    let from_str: OUString = text.into();
+    let from_string = OUString::from(text.to_string());
+
+    // All should produce equivalent strings
+    assert_eq!(from_utf8, from_str);
+    assert_eq!(from_utf8, from_string);
+    assert_eq!(from_str, from_string);
+
+    // All should have same content
+    assert_eq!(from_utf8.to_string(), text);
+    assert_eq!(from_str.to_string(), text);
+    assert_eq!(from_string.to_string(), text);
+}
+
+#[test]
+fn test_oustring_memory_safety() {
+    // Test that dropping strings doesn't cause issues
+    {
+        let s1 = OUString::from_utf8("Temporary string 1");
+        let s2 = s1.clone();
+        let s3 = OUString::from_utf8("Temporary string 2");
+
+        assert_eq!(s1, s2);
+        assert_ne!(s1, s3);
+
+        // Strings will be dropped here - this should not cause issues
+    }
+
+    // Create new strings after the previous ones were dropped
+    let s4 = OUString::from_utf8("After drop test");
+    assert_eq!(s4.to_string(), "After drop test");
+}
+
+#[test]
+fn test_oustring_memory_release() {
+    // Simple memory release test - create and drop many strings
+    // If memory isn't released properly, this would cause memory leaks
+
+    // Create many strings in a loop and let them drop
+    for i in 0..1000 {
+        let s = OUString::from_utf8(&format!("Test string number {i}"));
+        assert_eq!(s.to_string(), format!("Test string number {i}"));
+        // String automatically drops here
+    }
+
+    // Create and explicitly drop strings
+    for _ in 0..1000 {
+        let s1 = OUString::from_utf8("Temporary string");
+        let s2 = s1.clone(); // This should increase ref count
+        let s3 = s2.clone(); // This should increase ref count more
+
+        // All should be equal
+        assert_eq!(s1, s2);
+        assert_eq!(s2, s3);
+
+        // All will be dropped here - ref counts should decrease properly
+    }
+
+    // If we reach here without crashes or memory issues, memory management is 
working
+}
+
+#[test]
+fn test_oustring_reference_counting_behavior() {
+    // Test that cloning works properly with reference counting
+    let original = OUString::from_utf8("Reference counted string");
+
+    // Create multiple references
+    let clone1 = original.clone();
+    let clone2 = original.clone();
+    let clone3 = clone1.clone();
+
+    // All should be equal
+    assert_eq!(original, clone1);
+    assert_eq!(original, clone2);
+    assert_eq!(original, clone3);
+    assert_eq!(clone1, clone2);
+    assert_eq!(clone1, clone3);
+    assert_eq!(clone2, clone3);
+
+    // All have same content
+    assert_eq!(original.to_string(), "Reference counted string");
+    assert_eq!(clone1.to_string(), "Reference counted string");
+    assert_eq!(clone2.to_string(), "Reference counted string");
+    assert_eq!(clone3.to_string(), "Reference counted string");
+
+    // When this function ends, all clones should be properly released
+}
+
+#[test]
+fn test_oustring_memory_from_raw_into_raw() {
+    // Test raw pointer ownership transfer (unique functionality)
+    for i in 0..100 {
+        let original = OUString::from_utf8(&format!("Raw pointer test {i}"));
+        let original_content = original.to_string();
+
+        // Transfer ownership to raw pointer
+        let raw_ptr = original.into_raw();
+
+        // Create new OUString from raw pointer (takes ownership back)
+        let restored = unsafe { OUString::from_raw(raw_ptr) };
+
+        assert_eq!(restored.to_string(), original_content);
+    }
+}
+
+#[test]
+fn test_oustring_memory_mixed_operations() {
+    // Test complex combinations of operations (not covered by existing tests)
+    for i in 0..50 {
+        // Create initial string
+        let s1 = OUString::from_utf8(&format!("Mixed test {i}"));
+
+        // Convert through different types
+        let s2 = OUString::from(s1.to_string());
+        let s3: OUString = s1.to_string().as_str().into();
+
+        // Clone operations
+        let c1 = s1.clone();
+        let c2 = s2.clone();
+        let c3 = s3.clone();
+
+        // Verify equality
+        assert_eq!(s1, s2);
+        assert_eq!(s2, s3);
+        assert_eq!(c1, c2);
+        assert_eq!(c2, c3);
+
+        // Raw pointer operations
+        let raw1 = c1.into_raw();
+        let raw2 = c2.into_raw();
+
+        let restored1 = unsafe { OUString::from_raw(raw1) };
+        let restored2 = unsafe { OUString::from_raw(raw2) };
+
+        assert_eq!(restored1, restored2);
+        assert_eq!(restored1.to_string(), format!("Mixed test {i}"));
+    }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/rust_uno/src/core/tests/type_tests.rs 
b/rust_uno/src/core/tests/type_tests.rs
new file mode 100644
index 000000000000..3248ac372175
--- /dev/null
+++ b/rust_uno/src/core/tests/type_tests.rs
@@ -0,0 +1,520 @@
+/* -*- Mode: rust; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- 
*/
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * 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/.
+ */
+
+//! Unit tests for Type (Rust-side functionality)
+//!
+//! These tests verify Type's Rust implementation including:
+//! - Creation methods (new, new_with_name, from_typelib_ref, 
from_typelib_ref_no_acquire)
+//! - Trait implementations (Clone, PartialEq, From, Default)
+//! - Instance methods (get_type_class, get_type_name, equals, 
is_assignable_from)
+//! - Memory management and safety (RAII, reference counting)
+//! - FFI interop (get_typelib_type)
+//! - Ergonomic API (generic string parameters)
+//!
+//! These tests do NOT require LibreOffice UNO components and test
+//! only the Rust-side implementation and FFI safety.
+
+use crate::core::{OUString, Type, typelib_TypeClass};
+
+// === Creation Method Tests ===
+
+#[test]
+fn test_type_new() {
+    let void_type = Type::new();
+    assert_eq!(
+        void_type.get_type_class(),
+        typelib_TypeClass::typelib_TypeClass_VOID
+    );
+    assert_eq!(void_type.get_type_name().to_string(), "void");
+}
+
+#[test]
+fn test_type_default() {
+    let default_type = Type::default();
+    assert_eq!(
+        default_type.get_type_class(),
+        typelib_TypeClass::typelib_TypeClass_VOID
+    );
+    assert_eq!(default_type.get_type_name().to_string(), "void");
+
+    // Test that default equals new()
+    let new_type = Type::new();
+    assert!(default_type.equals(&new_type));
+}
+
+#[test]
+fn test_type_new_with_name_str() {
+    let void_type = 
Type::new_with_name(typelib_TypeClass::typelib_TypeClass_VOID, "void");
+    assert_eq!(
+        void_type.get_type_class(),
+        typelib_TypeClass::typelib_TypeClass_VOID
+    );
+    assert_eq!(void_type.get_type_name().to_string(), "void");
+
+    let int_type = 
Type::new_with_name(typelib_TypeClass::typelib_TypeClass_LONG, "sal_Int32");
+    assert_eq!(
+        int_type.get_type_class(),
+        typelib_TypeClass::typelib_TypeClass_LONG
+    );
+    assert_eq!(int_type.get_type_name().to_string(), "sal_Int32");
+
+    let interface_type = Type::new_with_name(
+        typelib_TypeClass::typelib_TypeClass_INTERFACE,
+        "com.sun.star.lang.XComponent",
+    );
+    assert_eq!(
+        interface_type.get_type_class(),
+        typelib_TypeClass::typelib_TypeClass_INTERFACE
+    );
+    assert_eq!(
+        interface_type.get_type_name().to_string(),
+        "com.sun.star.lang.XComponent"
+    );
+}
+
+#[test]
+fn test_type_new_with_name_string() {
+    let type_name = "com.sun.star.text.XText".to_string();
+    let text_type = 
Type::new_with_name(typelib_TypeClass::typelib_TypeClass_INTERFACE, type_name);
+    assert_eq!(
+        text_type.get_type_class(),
+        typelib_TypeClass::typelib_TypeClass_INTERFACE
+    );
+    assert_eq!(
+        text_type.get_type_name().to_string(),
+        "com.sun.star.text.XText"
+    );
+}
+
+#[test]
+fn test_type_new_with_name_oustring() {
+    let oustring_name = OUString::from("com.sun.star.beans.XPropertySet");
+    let prop_type = Type::new_with_name(
+        typelib_TypeClass::typelib_TypeClass_INTERFACE,
+        oustring_name,
+    );
+    assert_eq!(
+        prop_type.get_type_class(),
+        typelib_TypeClass::typelib_TypeClass_INTERFACE
+    );
+    assert_eq!(
+        prop_type.get_type_name().to_string(),
+        "com.sun.star.beans.XPropertySet"
+    );
+}
+
+// === From Trait Tests ===
+
+#[test]
+fn test_type_from_typelib_typeclass() {
+    let string_type = Type::from(typelib_TypeClass::typelib_TypeClass_STRING);
+    assert_eq!(
+        string_type.get_type_class(),
+        typelib_TypeClass::typelib_TypeClass_STRING
+    );
+
+    let boolean_type = 
Type::from(typelib_TypeClass::typelib_TypeClass_BOOLEAN);
+    assert_eq!(
+        boolean_type.get_type_class(),
+        typelib_TypeClass::typelib_TypeClass_BOOLEAN
+    );
+
+    let double_type = Type::from(typelib_TypeClass::typelib_TypeClass_DOUBLE);
+    assert_eq!(
+        double_type.get_type_class(),
+        typelib_TypeClass::typelib_TypeClass_DOUBLE
+    );
+}
+
+#[test]
+fn test_type_from_tuple_with_str() {
+    let primitive_types = vec![
+        ("void", typelib_TypeClass::typelib_TypeClass_VOID),
+        ("boolean", typelib_TypeClass::typelib_TypeClass_BOOLEAN),
+        ("byte", typelib_TypeClass::typelib_TypeClass_BYTE),
+        ("short", typelib_TypeClass::typelib_TypeClass_SHORT),
+        (
+            "unsigned short",
+            typelib_TypeClass::typelib_TypeClass_UNSIGNED_SHORT,
+        ),
+        ("long", typelib_TypeClass::typelib_TypeClass_LONG),
+        (
+            "unsigned long",
+            typelib_TypeClass::typelib_TypeClass_UNSIGNED_LONG,
+        ),
+        ("hyper", typelib_TypeClass::typelib_TypeClass_HYPER),
+        (
+            "unsigned hyper",
+            typelib_TypeClass::typelib_TypeClass_UNSIGNED_HYPER,
+        ),
+        ("float", typelib_TypeClass::typelib_TypeClass_FLOAT),
+        ("double", typelib_TypeClass::typelib_TypeClass_DOUBLE),
+        ("char", typelib_TypeClass::typelib_TypeClass_CHAR),
+        ("string", typelib_TypeClass::typelib_TypeClass_STRING),
+        ("type", typelib_TypeClass::typelib_TypeClass_TYPE),
+        ("any", typelib_TypeClass::typelib_TypeClass_ANY),
+    ];
+
+    for (type_name, expected_class) in primitive_types {
+        let type_obj = Type::from((expected_class, type_name));
+        assert_eq!(
+            type_obj.get_type_class(),
+            expected_class,
+            "Failed for type: {}",
+            type_name
+        );
+        assert_eq!(type_obj.get_type_name().to_string(), type_name);
+    }
+}
+
+#[test]
+fn test_type_from_tuple_with_string() {
+    let type_name = "com.sun.star.awt.XControl".to_string();
+    let control_type = 
Type::from((typelib_TypeClass::typelib_TypeClass_INTERFACE, type_name));
+    assert_eq!(
+        control_type.get_type_class(),
+        typelib_TypeClass::typelib_TypeClass_INTERFACE
+    );
+    assert_eq!(
+        control_type.get_type_name().to_string(),
+        "com.sun.star.awt.XControl"
+    );
+}
+
+#[test]
+fn test_type_from_tuple_with_oustring() {
+    let type_name = OUString::from("com.sun.star.beans.XPropertySet");
+    let prop_type = 
Type::from((typelib_TypeClass::typelib_TypeClass_INTERFACE, type_name));
+    assert_eq!(
+        prop_type.get_type_class(),
+        typelib_TypeClass::typelib_TypeClass_INTERFACE
+    );
+    assert_eq!(
+        prop_type.get_type_name().to_string(),
+        "com.sun.star.beans.XPropertySet"
+    );
+}
+
+// === Trait Implementation Tests ===
+
+#[test]
+fn test_type_clone() {
+    let original = Type::new_with_name(
+        typelib_TypeClass::typelib_TypeClass_INTERFACE,
+        "com.sun.star.lang.XComponent",
+    );
+    let cloned = original.clone();
+
+    // They should be equal
+    assert!(original.equals(&cloned));
+    assert_eq!(original.get_type_class(), cloned.get_type_class());
+    assert_eq!(
+        original.get_type_name().to_string(),
+        cloned.get_type_name().to_string()
+    );
+
+    // Test cloning void type
+    let void_original = Type::new();
+    let void_clone = void_original.clone();
+    assert!(void_original.equals(&void_clone));
+}
+
+#[test]
+fn test_type_partial_eq() {
+    let type1 = Type::new_with_name(typelib_TypeClass::typelib_TypeClass_LONG, 
"sal_Int32");
+    let type2 = Type::new_with_name(typelib_TypeClass::typelib_TypeClass_LONG, 
"sal_Int32");
+    let type3 = 
Type::new_with_name(typelib_TypeClass::typelib_TypeClass_SHORT, "sal_Int16");
+    let void1 = Type::new();
+    let void2 = Type::new();
+
+    // Equal types
+    assert_eq!(type1, type2);
+    assert_eq!(void1, void2);
+
+    // Different types
+    assert_ne!(type1, type3);
+    assert_ne!(type1, void1);
+
+    // Test with interface types
+    let interface1 = Type::from((
+        typelib_TypeClass::typelib_TypeClass_INTERFACE,
+        "com.sun.star.lang.XComponent",
+    ));
+    let interface2 = Type::from((
+        typelib_TypeClass::typelib_TypeClass_INTERFACE,
+        "com.sun.star.lang.XComponent",
+    ));
+    let interface3 = Type::from((
+        typelib_TypeClass::typelib_TypeClass_INTERFACE,
+        "com.sun.star.uno.XInterface",
+    ));
+
+    assert_eq!(interface1, interface2);
+    assert_ne!(interface1, interface3);
+}
+
+// === Method Tests ===
+
+#[test]
+fn test_type_get_type_class() {
+    let void_type = Type::new();
+    assert_eq!(
+        void_type.get_type_class(),
+        typelib_TypeClass::typelib_TypeClass_VOID
+    );
+
+    let string_type = Type::from(typelib_TypeClass::typelib_TypeClass_STRING);
+    assert_eq!(
+        string_type.get_type_class(),
+        typelib_TypeClass::typelib_TypeClass_STRING
+    );
+
+    let interface_type = Type::from((
+        typelib_TypeClass::typelib_TypeClass_INTERFACE,
+        "com.sun.star.lang.XComponent",
+    ));
+    assert_eq!(
+        interface_type.get_type_class(),
+        typelib_TypeClass::typelib_TypeClass_INTERFACE
+    );
+}
+
+#[test]
+fn test_type_get_type_name() {
+    let void_type = Type::new();
+    assert_eq!(void_type.get_type_name().to_string(), "void");
+
+    let int_type = 
Type::new_with_name(typelib_TypeClass::typelib_TypeClass_LONG, "sal_Int32");
+    assert_eq!(int_type.get_type_name().to_string(), "sal_Int32");
+
+    let interface_type = Type::from((
+        typelib_TypeClass::typelib_TypeClass_INTERFACE,
+        "com.sun.star.text.XTextDocument",
+    ));
+    assert_eq!(
+        interface_type.get_type_name().to_string(),
+        "com.sun.star.text.XTextDocument"
+    );
+}
+
+#[test]
+fn test_type_equals() {
+    let type1 = Type::new_with_name(typelib_TypeClass::typelib_TypeClass_LONG, 
"sal_Int32");
+    let type2 = Type::new_with_name(typelib_TypeClass::typelib_TypeClass_LONG, 
"sal_Int32");
+    let type3 = 
Type::new_with_name(typelib_TypeClass::typelib_TypeClass_SHORT, "sal_Int16");
+
+    // Test equality
+    assert!(type1.equals(&type2));
+    assert!(type2.equals(&type1)); // Symmetry
+
+    // Test inequality
+    assert!(!type1.equals(&type3));
+    assert!(!type3.equals(&type1)); // Symmetry
+
+    // Test self-equality
+    assert!(type1.equals(&type1));
+}
+
+#[test]
+fn test_type_is_assignable_from() {
+    // Create different types for testing assignment compatibility
+    let long_type = 
Type::new_with_name(typelib_TypeClass::typelib_TypeClass_LONG, "sal_Int32");
+    let short_type = 
Type::new_with_name(typelib_TypeClass::typelib_TypeClass_SHORT, "sal_Int16");
+    let byte_type = 
Type::new_with_name(typelib_TypeClass::typelib_TypeClass_BYTE, "sal_Int8");
+
+    // Test self-assignment (should always be true)
+    assert!(long_type.is_assignable_from(&long_type));
+    assert!(short_type.is_assignable_from(&short_type));
+    assert!(byte_type.is_assignable_from(&byte_type));
+
+    // These tests depend on UNO's specific assignment rules
+    // Note: The actual behavior depends on LibreOffice's typelib 
implementation
+    // We're just testing that the method calls work correctly
+    let _long_from_short = long_type.is_assignable_from(&short_type);
+    let _long_from_byte = long_type.is_assignable_from(&byte_type);
+    let _short_from_byte = short_type.is_assignable_from(&byte_type);
+}
+
+#[test]
+fn test_type_get_typelib_type() {
+    let type_obj = 
Type::new_with_name(typelib_TypeClass::typelib_TypeClass_STRING, "string");
+    let raw_ptr = type_obj.get_typelib_type();
+
+    // Should return a non-null pointer
+    assert!(!raw_ptr.is_null());
+
+    // Test with void type
+    let void_type = Type::new();
+    let void_ptr = void_type.get_typelib_type();
+    assert!(!void_ptr.is_null());
+}
+
+// === Special Cases and Edge Cases ===
+
+#[test]
+fn test_type_primitive_type_classes() {
+    // Test creating types for primitive type classes that have static type 
references
+    let primitive_type_classes = vec![
+        typelib_TypeClass::typelib_TypeClass_VOID,
+        typelib_TypeClass::typelib_TypeClass_CHAR,
+        typelib_TypeClass::typelib_TypeClass_BOOLEAN,
+        typelib_TypeClass::typelib_TypeClass_BYTE,
+        typelib_TypeClass::typelib_TypeClass_SHORT,
+        typelib_TypeClass::typelib_TypeClass_UNSIGNED_SHORT,
+        typelib_TypeClass::typelib_TypeClass_LONG,
+        typelib_TypeClass::typelib_TypeClass_UNSIGNED_LONG,
+        typelib_TypeClass::typelib_TypeClass_HYPER,
+        typelib_TypeClass::typelib_TypeClass_UNSIGNED_HYPER,
+        typelib_TypeClass::typelib_TypeClass_FLOAT,
+        typelib_TypeClass::typelib_TypeClass_DOUBLE,
+        typelib_TypeClass::typelib_TypeClass_STRING,
+        typelib_TypeClass::typelib_TypeClass_TYPE,
+        typelib_TypeClass::typelib_TypeClass_ANY,
+    ];
+
+    for type_class in primitive_type_classes {
+        let type_obj = Type::from(type_class);
+        assert_eq!(type_obj.get_type_class(), type_class);
+    }
+}
+
+#[test]
+fn test_type_complex_interface_names() {
+    let complex_names = vec![
+        "com.sun.star.lang.XComponent",
+        "com.sun.star.uno.XInterface",
+        "com.sun.star.text.XTextDocument",
+        "com.sun.star.beans.XPropertySet",
+        "com.sun.star.awt.XControl",
+        "com.sun.star.frame.XController",
+    ];
+
+    for name in complex_names {
+        let type_obj = 
Type::from((typelib_TypeClass::typelib_TypeClass_INTERFACE, name));
+        assert_eq!(
+            type_obj.get_type_class(),
+            typelib_TypeClass::typelib_TypeClass_INTERFACE
+        );
+        assert_eq!(type_obj.get_type_name().to_string(), name);
+    }
+}
+
+#[test]
+fn test_type_consistency_across_creation_methods() {
+    // Test that different creation methods produce equivalent results for 
same type
+
+    // String type via different methods
+    let string_from_class = 
Type::from(typelib_TypeClass::typelib_TypeClass_STRING);
+    let string_from_tuple = 
Type::from((typelib_TypeClass::typelib_TypeClass_STRING, "string"));
+    let string_from_new_with_name =
+        Type::new_with_name(typelib_TypeClass::typelib_TypeClass_STRING, 
"string");
+
+    assert!(string_from_class.equals(&string_from_tuple));
+    assert!(string_from_tuple.equals(&string_from_new_with_name));
+    assert!(string_from_class.equals(&string_from_new_with_name));
+
+    // Interface type via different methods
+    let interface_name = "com.sun.star.lang.XComponent";
+    let interface_from_tuple = Type::from((
+        typelib_TypeClass::typelib_TypeClass_INTERFACE,
+        interface_name,
+    ));
+    let interface_from_new_with_name = Type::new_with_name(
+        typelib_TypeClass::typelib_TypeClass_INTERFACE,
+        interface_name,
+    );
+
+    assert!(interface_from_tuple.equals(&interface_from_new_with_name));
+}
+
+// === Memory Management Tests ===
+
+#[test]
+fn test_type_memory_safety() {
+    // Test that Types can be created and dropped without issues
+
+    {
+        let _type1 = Type::new();
+        let _type2 = Type::from(typelib_TypeClass::typelib_TypeClass_STRING);
+        let _type3 = 
Type::new_with_name(typelib_TypeClass::typelib_TypeClass_LONG, "sal_Int32");
+    } // Types should be properly cleaned up here
+
+    // Create more types after the previous ones were dropped
+    let type4 = Type::from((
+        typelib_TypeClass::typelib_TypeClass_INTERFACE,
+        "com.sun.star.lang.XComponent",
+    ));
+    let type5 = type4.clone();
+
+    assert!(type4.equals(&type5));
+}
+
+#[test]
+fn test_type_multiple_references() {
+    // Test that multiple references to the same logical type work correctly
+    let name = "com.sun.star.text.XTextDocument";
+
+    let type1 = Type::from((typelib_TypeClass::typelib_TypeClass_INTERFACE, 
name));
+    let type2 = Type::from((typelib_TypeClass::typelib_TypeClass_INTERFACE, 
name));
+    let type3 = type1.clone();
+
+    // All should be equal
+    assert!(type1.equals(&type2));
+    assert!(type2.equals(&type3));
+    assert!(type1.equals(&type3));
+
+    // All should have same properties
+    assert_eq!(type1.get_type_class(), type2.get_type_class());
+    assert_eq!(type2.get_type_class(), type3.get_type_class());
+
+    assert_eq!(
+        type1.get_type_name().to_string(),
+        type2.get_type_name().to_string()
+    );
+    assert_eq!(
+        type2.get_type_name().to_string(),
+        type3.get_type_name().to_string()
+    );
+}
+
+#[test]
+fn test_type_mixed_operations() {
+    // Test mixing different operations
+    let original = Type::new_with_name(
+        typelib_TypeClass::typelib_TypeClass_INTERFACE,
+        "com.sun.star.lang.XComponent",
+    );
+
+    // Clone and compare
+    let cloned = original.clone();
+    assert!(original.equals(&cloned));
+
+    // Create equivalent via From trait
+    let from_tuple = Type::from((
+        typelib_TypeClass::typelib_TypeClass_INTERFACE,
+        "com.sun.star.lang.XComponent",
+    ));
+    assert!(original.equals(&from_tuple));
+
+    // Test assignment compatibility with itself
+    assert!(original.is_assignable_from(&original));
+    assert!(cloned.is_assignable_from(&from_tuple));
+
+    // Check type information
+    assert_eq!(
+        original.get_type_class(),
+        typelib_TypeClass::typelib_TypeClass_INTERFACE
+    );
+    assert_eq!(
+        original.get_type_name().to_string(),
+        "com.sun.star.lang.XComponent"
+    );
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/rust_uno/src/core/type.rs b/rust_uno/src/core/type.rs
new file mode 100644
index 000000000000..21363952ddcf
--- /dev/null
+++ b/rust_uno/src/core/type.rs
@@ -0,0 +1,328 @@
+/* -*- Mode: rust; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- 
*/
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * 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/.
+ */
+
+//! UNO Type System and Type References
+//!
+//! This module provides the high-level safe Rust wrapper around LibreOffice's 
type system.
+//! It includes safe type creation, automatic memory management, and type 
compatibility testing.
+//!
+//! ## Key Components
+//! - `Type` - Safe Rust wrapper around LibreOffice's 
typelib_TypeDescriptionReference
+//!
+//! ## Features
+//! - Safe type creation with automatic memory management via RAII
+//! - Type equality and assignment compatibility testing
+//! - Type class and name retrieval
+//! - Clone, equality, and default trait implementations
+//! - Direct FFI interop with raw pointer access methods
+//! - Support for all UNO type classes (void, primitive types, interfaces, 
etc.)
+//! - Safe From trait implementations for creating types from type classes and 
explicit type/name tuples
+
+use crate::core::oustring::*;
+use crate::ffi::type_ffi::*;
+use std::ptr;
+
+// === Safe Type Wrapper ===
+
+/// Safe Rust wrapper for UNO Type
+///
+/// This struct provides a safe, ergonomic interface to UNO's type system.
+/// It handles memory management automatically and provides idiomatic Rust
+/// methods for type operations and comparisons.
+///
+/// # Examples
+///
+/// ```rust
+/// use rust_uno::{Type, typelib_TypeClass};
+///
+/// // Create a void type
+/// let void_type = Type::new();
+///
+/// // Create a primitive type
+/// let int_type = Type::from(typelib_TypeClass::typelib_TypeClass_LONG);
+///
+/// // Create an interface type
+/// let interface_type = Type::from((
+///     typelib_TypeClass::typelib_TypeClass_INTERFACE,
+///     "com.sun.star.lang.XComponent"
+/// ));
+/// ```
+#[allow(non_snake_case)] // _pType follows FFI naming conventions
+pub struct Type {
+    /// C typelib reference pointer
+    _pType: *mut typelib_TypeDescriptionReference,
+}
+
+impl Type {
+    /// Create a new Type set to void
+    ///
+    /// Creates the default UNO type (void). This is equivalent to the default
+    /// constructor in C++ com::sun::star::uno::Type.
+    pub fn new() -> Self {
+        unsafe {
+            let void_type_ref =
+                
typelib_static_type_getByTypeClass(typelib_TypeClass::typelib_TypeClass_VOID);
+            typelib_typedescriptionreference_acquire(*void_type_ref);
+            Type {
+                _pType: *void_type_ref,
+            }
+        }
+    }
+
+    /// Create a Type from type class and name
+    ///
+    /// Creates a new Type from the specified type class and a string that 
will be
+    /// converted to OUString. Accepts any type that can be converted to 
OUString
+    /// (such as &str, String, etc.) through the Into trait. This is the most 
common
+    /// way to create custom types with specific names.
+    ///
+    /// # Arguments
+    /// * `type_class` - The UNO type class (VOID, STRING, INTERFACE, etc.)
+    /// * `type_name` - The fully qualified type name (convertible to OUString)
+    pub fn new_with_name<T: Into<OUString>>(type_class: typelib_TypeClass, 
type_name: T) -> Self {
+        let mut oustring_name = type_name.into();
+        let mut type_ref: *mut typelib_TypeDescriptionReference = 
ptr::null_mut();
+
+        unsafe {
+            typelib_typedescriptionreference_new(
+                &mut type_ref,
+                type_class,
+                oustring_name.as_mut_ptr(),
+            );
+        }
+
+        Type { _pType: type_ref }
+    }
+
+    /// Create Type from existing typelib reference (acquires reference)
+    ///
+    /// Takes ownership of an existing type reference by incrementing its 
reference count.
+    /// This is useful when interfacing with C code that provides type 
references.
+    ///
+    /// # Safety
+    /// The caller must ensure that `type_ref` points to a valid 
typelib_TypeDescriptionReference.
+    pub unsafe fn from_typelib_ref(type_ref: *mut 
typelib_TypeDescriptionReference) -> Self {
+        unsafe {
+            typelib_typedescriptionreference_acquire(type_ref);
+        }
+        Type { _pType: type_ref }
+    }
+
+    /// Create Type from existing typelib reference (no acquire)
+    ///
+    /// Takes ownership of an existing type reference without incrementing 
reference count.
+    /// Use this when transferring ownership from C code that already has a 
reference.
+    /// This avoids unnecessary reference count manipulation when you know the 
ownership
+    /// is being transferred.
+    ///
+    /// # Safety
+    /// The caller must ensure that:
+    /// - `type_ref` points to a valid typelib_TypeDescriptionReference
+    /// - The reference count is properly managed (caller transfers ownership)
+    pub unsafe fn from_typelib_ref_no_acquire(
+        type_ref: *mut typelib_TypeDescriptionReference,
+    ) -> Self {
+        Type { _pType: type_ref }
+    }
+
+    /// Get the type class of this type
+    ///
+    /// Returns the UNO type class (VOID, STRING, INTERFACE, etc.) that 
categorizes
+    /// this type within the UNO type system. This is used for type checking 
and
+    /// dispatch in UNO method calls.
+    pub fn get_type_class(&self) -> typelib_TypeClass {
+        unsafe { (*self._pType).eTypeClass }
+    }
+
+    /// Get the fully qualified name of this type
+    ///
+    /// Returns an OUString containing the type name (e.g., 
"com.sun.star.lang.XComponent").
+    /// For primitive types, returns the type name (e.g., "long", "string"). 
The returned
+    /// string is a copy, so it can be safely used without worrying about the 
lifetime
+    /// of the original Type instance.
+    pub fn get_type_name(&self) -> OUString {
+        unsafe {
+            let name_ptr = (*self._pType).pTypeName;
+            if name_ptr.is_null() {
+                return OUString::new();
+            }
+            // Use OUString::from_raw which handles the acquisition internally
+            OUString::from_raw(name_ptr)
+        }
+    }
+
+    /// Get the raw typelib reference pointer for FFI calls
+    ///
+    /// Returns the underlying pointer for FFI interoperability. The returned
+    /// pointer remains owned by this Type instance and should not be freed
+    /// by the caller. Useful when calling LibreOffice C APIs directly.
+    pub fn get_typelib_type(&self) -> *mut typelib_TypeDescriptionReference {
+        self._pType
+    }
+
+    /// Convert Type into raw pointer (releases Rust ownership)
+    ///
+    /// Transfers ownership of the underlying type reference to the caller.
+    /// The caller becomes responsible for calling 
typelib_typedescriptionreference_release
+    /// when done with the pointer. The Type instance is consumed and cannot 
be used
+    /// after this call.
+    pub fn into_raw(self) -> *mut typelib_TypeDescriptionReference {
+        let ptr = self._pType;
+        std::mem::forget(self); // Don't run destructor since we're 
transferring ownership
+        ptr
+    }
+
+    /// Test if values of this type can be assigned from values of the given 
type
+    ///
+    /// This includes widening conversions (e.g., long assignable from short)
+    /// as long as there is no data loss. The test follows UNO assignment rules
+    /// and is used in method dispatch to determine if argument types are 
compatible.
+    ///
+    /// # Arguments
+    /// * `other` - The source type to test assignment compatibility from
+    ///
+    /// # Returns
+    /// `true` if values of `other` type can be assigned to this type, `false` 
otherwise
+    pub fn is_assignable_from(&self, other: &Type) -> bool {
+        unsafe { 
typelib_typedescriptionreference_isAssignableFrom(self._pType, other._pType) != 
0 }
+    }
+
+    /// Test if this type is equal to another type
+    ///
+    /// Two types are equal if they have the same type class and fully 
qualified name.
+    /// This is used for type matching in UNO method dispatch and interface 
queries.
+    /// The comparison is efficient and uses LibreOffice's native type 
comparison.
+    ///
+    /// # Arguments
+    /// * `other` - The type to compare with
+    ///
+    /// # Returns
+    /// `true` if the types are equal, `false` otherwise
+    pub fn equals(&self, other: &Type) -> bool {
+        unsafe { typelib_typedescriptionreference_equals(self._pType, 
other._pType) != 0 }
+    }
+}
+
+/// Default implementation: Creates a void type
+///
+/// When a Type is created without explicit initialization, it defaults to
+/// the void type, which is the UNO equivalent of "no type" or "empty type".
+impl Default for Type {
+    fn default() -> Self {
+        Self::new()
+    }
+}
+
+/// Clone implementation: Create an independent copy of another Type
+///
+/// This creates a new Type that references the same type description but is
+/// independently managed. The clone operation increments the reference count
+/// of the underlying type description, ensuring proper memory management.
+impl Clone for Type {
+    fn clone(&self) -> Self {
+        unsafe {
+            typelib_typedescriptionreference_acquire(self._pType);
+        }
+        Type {
+            _pType: self._pType,
+        }
+    }
+}
+
+/// Equality comparison with other Type instances
+///
+/// Two Type instances are considered equal if they refer to the same type
+/// (same type class and name). This uses LibreOffice's native type comparison
+/// which is efficient and handles all type categories correctly.
+impl PartialEq for Type {
+    fn eq(&self, other: &Self) -> bool {
+        self.equals(other)
+    }
+}
+
+impl Eq for Type {}
+
+/// Debug trait for debugging - shows type class and name for UNO type 
identification
+///
+/// Displays the Type in a debug-friendly format showing both the type class
+/// and the type name, which is useful for debugging UNO type-related issues.
+impl std::fmt::Debug for Type {
+    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+        let type_class = self.get_type_class();
+        let type_name = self.get_type_name().to_string();
+        f.debug_struct("Type")
+            .field("type_class", &type_class)
+            .field("type_name", &type_name)
+            .finish()
+    }
+}
+
+/// Destructor: Automatic cleanup when Type goes out of scope
+///
+/// Automatically releases the reference to the underlying type description
+/// when the Type instance is dropped. This ensures proper memory management
+/// without manual intervention.
+impl Drop for Type {
+    fn drop(&mut self) {
+        unsafe {
+            typelib_typedescriptionreference_release(self._pType);
+        }
+    }
+}
+
+/// From trait implementation for typelib_TypeClass (primitive types)
+///
+/// Creates a Type from a primitive type class. This uses LibreOffice's static
+/// type system to get pre-defined type references for standard UNO types like
+/// void, boolean, string, etc. This is the most efficient way to create
-e 
... etc. - the rest is truncated

Reply via email to