This is an automated email from the ASF dual-hosted git repository.

pnoltes pushed a commit to branch feature/599-provide-and-use-c-service-in-rust
in repository https://gitbox.apache.org/repos/asf/celix.git

commit 2c8d89a5863bfcc77f0d49db602abc1f66037842
Author: Pepijn Noltes <[email protected]>
AuthorDate: Sat Aug 19 20:03:08 2023 +0200

    #599: Add rust (mini) example impl for context, activator and log helper.
---
 misc/experimental/rust/CMakeLists.txt              | 28 +++++--
 misc/experimental/rust/Cargo.toml                  |  1 +
 .../rust/celix_bindings/src/BundleActivator.rs     | 78 +++++++++++++++++++
 .../rust/celix_bindings/src/BundleContext.rs       | 50 +++++++++++++
 .../rust/celix_bindings/src/LogHelper.rs           | 78 +++++++++++++++++++
 .../rust/celix_bindings/src/celix_bindings.h       |  4 +
 misc/experimental/rust/celix_bindings/src/lib.rs   | 29 +++++---
 .../rust/hello_world_activator/Cargo.toml          |  2 +-
 .../rust/hello_world_activator/src/lib.rs          | 87 +++++-----------------
 9 files changed, 267 insertions(+), 90 deletions(-)

diff --git a/misc/experimental/rust/CMakeLists.txt 
b/misc/experimental/rust/CMakeLists.txt
index e2236a1a..3a710803 100644
--- a/misc/experimental/rust/CMakeLists.txt
+++ b/misc/experimental/rust/CMakeLists.txt
@@ -26,13 +26,12 @@ if (CELIX_RUST_EXPERIMENTAL)
     FetchContent_MakeAvailable(Corrosion)
 
     #Prepare a list of include paths needed to generating bindings for the 
Apache Celix C API
-    file(GENERATE
-            OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/include_paths.txt"
-            CONTENT 
"$<TARGET_PROPERTY:framework,INTERFACE_INCLUDE_DIRECTORIES>;$<TARGET_PROPERTY:utils,INTERFACE_INCLUDE_DIRECTORIES>"
-    )
+    #Note for now this includes framework, utils and shell_api maybe this 
should be separated in the future.
+    file(GENERATE OUTPUT
+        "${CMAKE_CURRENT_BINARY_DIR}/include_paths.txt" CONTENT
+        
"$<TARGET_PROPERTY:framework,INTERFACE_INCLUDE_DIRECTORIES>;$<TARGET_PROPERTY:utils,INTERFACE_INCLUDE_DIRECTORIES>;$<TARGET_PROPERTY:shell_api,INTERFACE_INCLUDE_DIRECTORIES>;$<TARGET_PROPERTY:Celix::log_service_api,INTERFACE_INCLUDE_DIRECTORIES>;$<TARGET_PROPERTY:Celix::log_helper,INTERFACE_INCLUDE_DIRECTORIES>")
 
     corrosion_import_crate(MANIFEST_PATH Cargo.toml)
-
     corrosion_add_target_local_rustflags(rust_bundle_activator 
"-Cprefer-dynamic")
     corrosion_link_libraries(rust_bundle_activator Celix::framework)
 
@@ -42,11 +41,24 @@ if (CELIX_RUST_EXPERIMENTAL)
     add_celix_bundle(rust_bundle ACTIVATOR ${ACTUAL_LIB_TARGET})
     add_dependencies(rust_bundle rust_bundle_activator)
 
-    add_celix_container(rust_container
-        NO_COPY
+    corrosion_add_target_local_rustflags(rust_shell_tui_activator 
"-Cprefer-dynamic")
+    corrosion_link_libraries(rust_shell_tui_activator Celix::framework)
+    get_target_property(ACTUAL_LIB_TARGET rust_shell_tui_activator 
INTERFACE_LINK_LIBRARIES)
+    add_celix_bundle(rust_shell_tui ACTIVATOR ${ACTUAL_LIB_TARGET})
+    add_dependencies(rust_shell_tui rust_shell_tui_activator)
+
+    add_celix_container(rust_container NO_COPY
         BUNDLES
             Celix::shell
             Celix::shell_tui
             rust_bundle
     )
-endif ()
+
+    add_celix_container(rust_shell_tui_cnt NO_COPY
+        BUNDLES
+            Celix::shell
+            Celix::shell_tui
+            rust_shell_tui
+    )
+
+endif()
diff --git a/misc/experimental/rust/Cargo.toml 
b/misc/experimental/rust/Cargo.toml
index 8727be5d..ef69f6c6 100644
--- a/misc/experimental/rust/Cargo.toml
+++ b/misc/experimental/rust/Cargo.toml
@@ -19,4 +19,5 @@
 members = [
     "celix_bindings",
     "hello_world_activator",
+    "rust_shell_tui",
 ]
diff --git a/misc/experimental/rust/celix_bindings/src/BundleActivator.rs 
b/misc/experimental/rust/celix_bindings/src/BundleActivator.rs
new file mode 100644
index 00000000..e46ea8d3
--- /dev/null
+++ b/misc/experimental/rust/celix_bindings/src/BundleActivator.rs
@@ -0,0 +1,78 @@
+/*
+ * 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
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+pub trait BundleActivator {
+    fn new(ctx: &mut dyn BundleContext) -> Self;
+    fn start(&mut self, ctx: &mut dyn BundleContext) -> celix_status_t { /* 
Default implementation */ CELIX_SUCCESS}
+    fn stop(&mut self, ctx: &mut dyn BundleContext) -> celix_status_t { /* 
Default implementation */ CELIX_SUCCESS}
+}
+
+#[macro_export]
+macro_rules! generate_bundle_activator {
+    ($activator:ident) => {
+        use celix::BundleContextImpl;
+        use CELIX_SUCCESS;
+        use celix_bindings::celix_bundle_context_t;
+
+        struct ActivatorWrapper {
+            ctx: BundleContextImpl,
+            activator: $activator,
+        }
+
+        #[no_mangle]
+        pub unsafe extern "C" fn celix_bundleActivator_create(
+            ctx: *mut celix_bundle_context_t,
+            out: *mut *mut c_void,
+        ) -> celix_status_t {
+            let mut context = BundleContextImpl::new(ctx);
+            let activator = $activator::new(&mut context);
+            let wrapper = ActivatorWrapper {
+                ctx: context,
+                activator
+            };
+            *out = Box::into_raw(Box::new(wrapper)) as *mut c_void;
+            CELIX_SUCCESS
+        }
+
+        #[no_mangle]
+        pub unsafe extern "C" fn celix_bundleActivator_start(
+            handle: *mut c_void,
+            ctx: *mut celix_bundle_context_t,
+        ) -> celix_status_t {
+            let wrapper = &mut *(handle as *mut ActivatorWrapper);
+            wrapper.activator.start(&mut wrapper.ctx)
+        }
+
+        #[no_mangle]
+        pub unsafe extern "C" fn celix_bundleActivator_stop(
+            handle: *mut c_void,
+            ctx: *mut celix_bundle_context_t,
+        ) -> celix_status_t {
+            let wrapper = &mut *(handle as *mut ActivatorWrapper);
+            wrapper.activator.stop(&mut wrapper.ctx)
+        }
+
+        #[no_mangle]
+        pub unsafe extern "C" fn celix_bundleActivator_destroy(handle: *mut 
c_void) -> celix_status_t {
+            let wrapper = Box::from_raw(handle as *mut ActivatorWrapper);
+            drop(wrapper);
+            CELIX_SUCCESS
+        }
+    };
+}
diff --git a/misc/experimental/rust/celix_bindings/src/BundleContext.rs 
b/misc/experimental/rust/celix_bindings/src/BundleContext.rs
new file mode 100644
index 00000000..9dc340b7
--- /dev/null
+++ b/misc/experimental/rust/celix_bindings/src/BundleContext.rs
@@ -0,0 +1,50 @@
+/*
+ * 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
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+use celix_log_level_CELIX_LOG_LEVEL_INFO;
+
+pub trait BundleContext {
+    fn get_c_bundle_context(&self) -> *mut celix_bundle_context_t;
+
+    fn log_info(&self, message: &str);
+}
+
+//note BundleContextImpl is pub for usage in bundle activator macro. TODO 
check if this can be avoided
+pub struct BundleContextImpl {
+    c_bundle_context: *mut celix_bundle_context_t,
+}
+
+impl BundleContextImpl {
+    pub fn new(c_bundle_context: *mut celix_bundle_context_t) -> Self {
+        BundleContextImpl {
+            c_bundle_context,
+        }
+    }
+}
+
+impl BundleContext for BundleContextImpl {
+    fn get_c_bundle_context(&self) -> *mut celix_bundle_context_t {
+        self.c_bundle_context
+    }
+
+    fn log_info(&self, message: &str) {
+        unsafe {
+            celix_bundleContext_log(self.c_bundle_context, 
celix_log_level_CELIX_LOG_LEVEL_INFO as u32, message.as_ptr() as *const i8);
+        }
+    }
+}
diff --git a/misc/experimental/rust/celix_bindings/src/LogHelper.rs 
b/misc/experimental/rust/celix_bindings/src/LogHelper.rs
new file mode 100644
index 00000000..b168b80c
--- /dev/null
+++ b/misc/experimental/rust/celix_bindings/src/LogHelper.rs
@@ -0,0 +1,78 @@
+/*
+ * 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
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+#[warn(unused_imports)]
+pub enum LogLevel {
+    Trace = ::bindings::celix_log_level_CELIX_LOG_LEVEL_TRACE as isize,
+    Debug = ::bindings::celix_log_level_CELIX_LOG_LEVEL_DEBUG as isize,
+    Info = ::bindings::celix_log_level_CELIX_LOG_LEVEL_INFO as isize,
+    Warn = ::bindings::celix_log_level_CELIX_LOG_LEVEL_WARNING as isize,
+    Error = ::bindings::celix_log_level_CELIX_LOG_LEVEL_ERROR as isize,
+    Fatal = ::bindings::celix_log_level_CELIX_LOG_LEVEL_FATAL as isize,
+}
+
+struct LogHelper {
+    celix_log_helper: *mut celix_log_helper_t,
+}
+
+impl LogHelper {
+    pub fn new(ctx: &dyn BundleContext, name: &str) -> Self {
+        LogHelper {
+            celix_log_helper: unsafe { 
celix_logHelper_create(ctx.get_c_bundle_context(), name.as_ptr() as *const i8) 
},
+        }
+    }
+
+    pub fn log(&self, level: LogLevel, message: &str) {
+        unsafe {
+            celix_logHelper_log(self.celix_log_helper, level as u32, 
message.as_ptr() as *const i8);
+        }
+    }
+
+    pub fn trace(&self, message: &str) {
+        self.log(LogLevel::Trace, message);
+    }
+
+    pub fn debug(&self, message: &str) {
+        self.log(LogLevel::Debug, message);
+    }
+
+    pub fn info(&self, message: &str) {
+        self.log(LogLevel::Info, message);
+    }
+
+    pub fn warn(&self, message: &str) {
+        self.log(LogLevel::Warn, message);
+    }
+
+    pub fn error(&self, message: &str) {
+        self.log(LogLevel::Error, message);
+    }
+
+    pub fn fatal(&self, message: &str) {
+        self.log(LogLevel::Fatal, message);
+    }
+}
+
+impl Drop for LogHelper {
+    fn drop(&mut self) {
+        unsafe {
+            celix_logHelper_destroy(self.celix_log_helper);
+        }
+    }
+}
diff --git a/misc/experimental/rust/celix_bindings/src/celix_bindings.h 
b/misc/experimental/rust/celix_bindings/src/celix_bindings.h
index 8495c9a4..5db2ff22 100644
--- a/misc/experimental/rust/celix_bindings/src/celix_bindings.h
+++ b/misc/experimental/rust/celix_bindings/src/celix_bindings.h
@@ -30,3 +30,7 @@
 #include "celix_framework.h"
 #include "celix_framework_factory.h"
 #include "celix_framework_utils.h"
+
+#include "celix_shell_command.h"
+#include "celix_log_service.h"
+#include "celix_log_helper.h"
\ No newline at end of file
diff --git a/misc/experimental/rust/celix_bindings/src/lib.rs 
b/misc/experimental/rust/celix_bindings/src/lib.rs
index c69c7524..2e6588d3 100644
--- a/misc/experimental/rust/celix_bindings/src/lib.rs
+++ b/misc/experimental/rust/celix_bindings/src/lib.rs
@@ -18,24 +18,29 @@
  */
 
 #[allow(non_camel_case_types, non_snake_case, non_upper_case_globals, 
dead_code)]
- mod bindings {
-      include!(concat!(env!("OUT_DIR"), "/celix_bindings.rs"));
- }
+mod bindings {
+     include!(concat!(env!("OUT_DIR"), "/celix_bindings.rs"));
+}
 pub use bindings::*;
 
 //Note C #defines (compile-time constants) are not all generated in the 
bindings.
 pub const CELIX_SUCCESS: celix_status_t = 0;
 pub const CELIX_BUNDLE_EXCEPTION: celix_status_t = 70001;
 
-// Move to celix_api lib
 pub mod celix {
+    use celix_status_t;
+    use CELIX_SUCCESS;
+    use CELIX_BUNDLE_EXCEPTION;
+
+    use celix_bundle_context_t;
+    use celix_bundleContext_log;
+
+    use celix_log_helper_t;
+    use celix_logHelper_create;
+    use celix_logHelper_log;
+    use celix_logHelper_destroy;
 
-    #[warn(unused_imports)]
-    pub enum LogLevel {
-        Trace = ::bindings::celix_log_level_CELIX_LOG_LEVEL_TRACE as isize,
-        Debug = ::bindings::celix_log_level_CELIX_LOG_LEVEL_DEBUG as isize,
-        Info = ::bindings::celix_log_level_CELIX_LOG_LEVEL_INFO as isize,
-        Warn = ::bindings::celix_log_level_CELIX_LOG_LEVEL_WARNING as isize,
-        Error = ::bindings::celix_log_level_CELIX_LOG_LEVEL_ERROR as isize,
-    }
+    include!("BundleContext.rs");
+    include!("BundleActivator.rs");
+    include!("LogHelper.rs");
 }
diff --git a/misc/experimental/rust/hello_world_activator/Cargo.toml 
b/misc/experimental/rust/hello_world_activator/Cargo.toml
index 4844acd2..6202ece9 100644
--- a/misc/experimental/rust/hello_world_activator/Cargo.toml
+++ b/misc/experimental/rust/hello_world_activator/Cargo.toml
@@ -16,7 +16,7 @@
 # under the License.
 
 [package]
-name = "rust_bundle_activator"
+name = "rust_bundle"
 version = "0.0.1"
 
 [dependencies]
diff --git a/misc/experimental/rust/hello_world_activator/src/lib.rs 
b/misc/experimental/rust/hello_world_activator/src/lib.rs
index 17d835d4..89b6d78c 100644
--- a/misc/experimental/rust/hello_world_activator/src/lib.rs
+++ b/misc/experimental/rust/hello_world_activator/src/lib.rs
@@ -19,89 +19,38 @@
 
 extern crate celix_bindings;
 
-use std::error::Error;
 use std::os::raw::c_void;
 use std::ffi::CString;
 use std::ffi::NulError;
-use celix_bindings::*; //Add all Apache Celix C bindings to the namespace 
(i.e. celix_bundleContext_log, etc.)
-
-struct RustBundle {
-    name: String,
-    ctx: *mut celix_bundle_context_t,
-}
 
-impl RustBundle {
+//TODO try to remove celix_bindings use statement
+use celix_bindings::*; //Add all Apache Celix C bindings to the namespace 
(i.e. celix_bundleContext_log, etc.)
+use celix::BundleActivator;
+use celix::BundleContext;
 
-    unsafe fn new(name: String, ctx: *mut celix_bundle_context_t) -> 
Result<RustBundle, NulError> {
-        let result = RustBundle {
-            name,
-            ctx,
-        };
-        result.log_lifecycle("created")?;
-        Ok(result)
-    }
+struct HelloWorldBundle {}
 
-    unsafe fn log_lifecycle(&self, event: &str) -> Result<(), NulError> {
-        let id = celix_bundleContext_getBundleId(self.ctx);
-        let c_string = CString::new(format!("Rust Bundle '{}' with id {} {}!", 
self.name, id, event))?;
-        celix_bundleContext_log(self.ctx, 
celix_log_level_CELIX_LOG_LEVEL_INFO, c_string.as_ptr());
-        Ok(())
+impl BundleActivator for HelloWorldBundle {
+    fn new(ctx: &mut dyn celix::BundleContext) -> Self {
+        ctx.log_info("Hello World Bundle Activator created");
+        HelloWorldBundle {}
     }
 
-    unsafe fn start(&self) -> Result<(), NulError> {
-        self.log_lifecycle("started")
+    fn start(&mut self, ctx: &mut dyn BundleContext) -> celix_status_t {
+        ctx.log_info("Hello World Bundle Activator started");
+        CELIX_SUCCESS
     }
 
-    unsafe fn stop(&self) -> Result<(), NulError> {
-        self.log_lifecycle("stopped")
+    fn stop(&mut self, ctx: &mut dyn BundleContext) -> celix_status_t {
+        ctx.log_info("Hello World Bundle Activator stopped");
+        CELIX_SUCCESS
     }
 }
 
-impl Drop for RustBundle {
+impl Drop for HelloWorldBundle {
     fn drop(&mut self) {
-        unsafe {
-            let result = self.log_lifecycle("destroyed");
-            match result {
-                Ok(()) => (),
-                Err(e) => println!("Error while logging: {}", e),
-            }
-        }
-    }
-}
-
-#[no_mangle]
-pub unsafe extern "C" fn celix_bundleActivator_create(ctx: *mut 
celix_bundle_context_t, data: *mut *mut c_void) -> celix_status_t {
-    let rust_bundle = RustBundle::new("Hello World".to_string(), ctx);
-    if rust_bundle.is_err() {
-        return CELIX_BUNDLE_EXCEPTION;
+        //TODO self.ctx.log_info("Hello World Bundle Activator dropped");
     }
-    *data = Box::into_raw(Box::new(rust_bundle.unwrap())) as *mut c_void;
-    CELIX_SUCCESS
 }
 
-#[no_mangle]
-pub unsafe extern "C" fn celix_bundleActivator_start(data: *mut c_void, _ctx: 
*mut celix_bundle_context_t) -> celix_status_t {
-    let rust_bundle = &*(data as *mut RustBundle);
-    let result = rust_bundle.start();
-    match result {
-        Ok(()) => CELIX_SUCCESS,
-        Err(_) => CELIX_BUNDLE_EXCEPTION,
-    }
-}
-
-#[no_mangle]
-pub unsafe extern "C" fn celix_bundleActivator_stop(data: *mut c_void, _ctx: 
*mut celix_bundle_context_t) -> celix_status_t {
-    let rust_bundle = &*(data as *mut RustBundle);
-    let result = rust_bundle.stop();
-    match result {
-        Ok(()) => CELIX_SUCCESS,
-        Err(_) => CELIX_BUNDLE_EXCEPTION,
-    }
-}
-
-#[no_mangle]
-pub unsafe extern "C" fn celix_bundleActivator_destroy(data: *mut c_void, 
_ctx: *mut celix_bundle_context_t) -> celix_status_t {
-    let rust_bundle = Box::from_raw(data as *mut RustBundle);
-    drop(rust_bundle);
-    CELIX_SUCCESS
-}
+generate_bundle_activator!(HelloWorldBundle);
\ No newline at end of file

Reply via email to