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
