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 21b00277b2fb052eac308a6c002df7512c969ab4 Author: Pepijn Noltes <pepijnnol...@gmail.com> AuthorDate: Sun Aug 20 19:33:32 2023 +0200 #599: Refactor rust celix lib and add LogHelper to rust celix lib --- misc/experimental/rust/celix/Cargo.toml | 7 +- .../rust/celix/src/bundle_activator.rs | 70 +++++++-------- misc/experimental/rust/celix/src/bundle_context.rs | 58 +++++++++--- misc/experimental/rust/celix/src/errno.rs | 11 ++- .../experimental/rust/celix/src/{mod.rs => lib.rs} | 34 ++++--- misc/experimental/rust/celix/src/log_helper.rs | 100 +++++++++++++-------- misc/experimental/rust/celix/src/log_level.rs | 64 +++++++++++++ .../rust/hello_world_activator/Cargo.toml | 2 +- .../rust/hello_world_activator/src/lib.rs | 27 +++--- 9 files changed, 252 insertions(+), 121 deletions(-) diff --git a/misc/experimental/rust/celix/Cargo.toml b/misc/experimental/rust/celix/Cargo.toml index d81416c8..4ae42766 100644 --- a/misc/experimental/rust/celix/Cargo.toml +++ b/misc/experimental/rust/celix/Cargo.toml @@ -16,14 +16,13 @@ # under the License. [package] -name = "celixs" +name = "celix" version = "0.0.1" -[build-dependencies] +[dependencies] celix_bindings = { path = "../celix_bindings" } - [lib] -name = "bindings" +name = "celix" path = "src/lib.rs" crate-type = ["rlib"] diff --git a/misc/experimental/rust/celix/src/bundle_activator.rs b/misc/experimental/rust/celix/src/bundle_activator.rs index 01dece71..11fa22a3 100644 --- a/misc/experimental/rust/celix/src/bundle_activator.rs +++ b/misc/experimental/rust/celix/src/bundle_activator.rs @@ -17,52 +17,41 @@ * under the License. */ -use ::celix::BundleContext; -use ::celix::Error; +use std::sync::Arc; + +use super::BundleContext; +use super::Error; pub trait BundleActivator { - fn new(ctx: &mut dyn BundleContext) -> Self; - fn start(&mut self, _ctx: &mut dyn BundleContext) -> Result<(), Error> { /* Default implementation */ Ok(())} - fn stop(&mut self, _ctx: &mut dyn BundleContext) -> Result<(), Error> { /* Default implementation */ Ok(())} + fn new(ctx: Arc<dyn BundleContext>) -> Self; + fn start(&mut self) -> Result<(), Error> { /* Default implementation */ Ok(())} + fn stop(&mut self) -> Result<(), Error> { /* Default implementation */ Ok(())} } #[macro_export] macro_rules! generate_bundle_activator { ($activator:ty) => { - // fn assert_implements_trait(_: &$activator) { - // fn must_implement<T: celix::BundleActivator>(_t: &T) {} - // must_implement(&*(None::<$activator>).unwrap_or_default()); - // } - - struct ActivatorWrapper { - ctx: Box<dyn $crate::celix::BundleContext>, - activator: $activator, - } - #[no_mangle] pub unsafe extern "C" fn celix_bundleActivator_create( - ctx: *mut $crate::celix_bundle_context_t, + ctx: *mut $crate::details::CBundleContext, out: *mut *mut ::std::ffi::c_void, - ) -> $crate::celix_status_t { - let mut context = $crate::celix::create_bundle_context_instance(ctx); - let activator = <$activator>::new(&mut *context); - let wrapper = ActivatorWrapper { - ctx: context, - activator - }; - *out = Box::into_raw(Box::new(wrapper)) as *mut ::std::ffi::c_void; - $crate::celix::CELIX_SUCCESS + ) -> $crate::details::CStatus { + let boxed_context = $crate::bundle_context_new(ctx); + let mut arc_context = Arc::from(boxed_context); + let activator = <$activator>::new(arc_context); + *out = Box::into_raw(Box::new(activator)) as *mut ::std::ffi::c_void; + $crate::CELIX_SUCCESS } #[no_mangle] pub unsafe extern "C" fn celix_bundleActivator_start( handle: *mut ::std::ffi::c_void, - ctx: *mut $crate::celix_bundle_context_t, - ) -> $crate::celix_status_t { - let wrapper = &mut *(handle as *mut ActivatorWrapper); - let result = wrapper.activator.start(&mut *wrapper.ctx); + ctx: *mut $crate::details::CBundleContext, + ) -> $crate::details::CStatus { + let activator = &mut *(handle as *mut $activator); + let result = activator.start(); match result { - Ok(_) => $crate::celix::CELIX_SUCCESS, + Ok(_) => $crate::CELIX_SUCCESS, Err(e) => e.into(), } } @@ -70,23 +59,24 @@ macro_rules! generate_bundle_activator { #[no_mangle] pub unsafe extern "C" fn celix_bundleActivator_stop( handle: *mut ::std::ffi::c_void, - ctx: *mut $crate::celix_bundle_context_t, - ) -> $crate::celix_status_t { - let wrapper = &mut *(handle as *mut ActivatorWrapper); - let result = wrapper.activator.stop(&mut *wrapper.ctx); + ctx: *mut $crate::details::CBundleContext, + ) -> $crate::details::CStatus { + let activator = &mut *(handle as *mut $activator); + let result = activator.stop(); match result { - Ok(_) => $crate::celix::CELIX_SUCCESS, + Ok(_) => $crate::CELIX_SUCCESS, Err(e) => e.into(), } } #[no_mangle] pub unsafe extern "C" fn celix_bundleActivator_destroy( - handle: *mut ::std::ffi::c_void - ) -> $crate::celix_status_t { - let reclaimed_wrapper = Box::from_raw(handle as *mut ActivatorWrapper); - drop(reclaimed_wrapper); - $crate::celix::CELIX_SUCCESS + handle: *mut ::std::ffi::c_void, + _ctx: *mut $crate::details::CBundleContext, + ) -> $crate::details::CStatus { + let reclaimed_activator = Box::from_raw(handle as *mut $activator); + drop(reclaimed_activator); + $crate::CELIX_SUCCESS } }; } diff --git a/misc/experimental/rust/celix/src/bundle_context.rs b/misc/experimental/rust/celix/src/bundle_context.rs index b63ae497..4bfacce2 100644 --- a/misc/experimental/rust/celix/src/bundle_context.rs +++ b/misc/experimental/rust/celix/src/bundle_context.rs @@ -17,18 +17,31 @@ * under the License. */ -use celix_bundle_context_t; -use celix_bundleContext_log; -use celix_log_level_CELIX_LOG_LEVEL_INFO; +use super::LogLevel; + +use celix_bindings::celix_bundle_context_t; +use celix_bindings::celix_bundleContext_log; +use celix_bindings::celix_log_level_e; pub trait BundleContext { fn get_c_bundle_context(&self) -> *mut celix_bundle_context_t; + fn log(&self, level: LogLevel, message: &str); + + fn log_trace(&self, message: &str); + + fn log_debug(&self, message: &str); + fn log_info(&self, message: &str); + + fn log_warning(&self, message: &str); + + fn log_error(&self, message: &str); + + fn log_fatal(&self, message: &str); } -//note BundleContextImpl is pub for usage in bundle activator macro. TODO check if this can be avoided -pub struct BundleContextImpl { +struct BundleContextImpl { c_bundle_context: *mut celix_bundle_context_t, } @@ -38,6 +51,19 @@ impl BundleContextImpl { c_bundle_context, } } + fn log_to_c(&self, level: LogLevel, message: &str) { + unsafe { + let result = std::ffi::CString::new(message); + match result { + Ok(c_str) => { + celix_bundleContext_log(self.c_bundle_context, level.into(), c_str.as_ptr() as *const i8); + } + Err(e) => { + println!("Error creating CString: {}", e); + } + } + } + } } impl BundleContext for BundleContextImpl { @@ -45,15 +71,21 @@ impl BundleContext for BundleContextImpl { self.c_bundle_context } - fn log_info(&self, message: &str) { - unsafe { - //wrap str into CString to ensure null-terminated string - let c_str = std::ffi::CString::new(message).unwrap(); - celix_bundleContext_log(self.c_bundle_context, celix_log_level_CELIX_LOG_LEVEL_INFO as u32, c_str.as_ptr() as *const i8); - } - } + fn log(&self, level: LogLevel, message: &str) { self.log_to_c(level, message); } + + fn log_trace(&self, message: &str) { self.log(LogLevel::Trace, message); } + + fn log_debug(&self, message: &str) { self.log(LogLevel::Debug, message); } + + fn log_info(&self, message: &str) { self.log(LogLevel::Info, message); } + + fn log_warning(&self, message: &str) { self.log(LogLevel::Warning, message); } + + fn log_error(&self, message: &str){ self.log(LogLevel::Error, message); } + + fn log_fatal(&self, message: &str){ self.log(LogLevel::Fatal, message); } } -pub fn create_bundle_context_instance(c_bundle_context: *mut celix_bundle_context_t) -> Box<dyn BundleContext> { +pub fn bundle_context_new(c_bundle_context: *mut celix_bundle_context_t) -> Box<dyn BundleContext> { Box::new(BundleContextImpl::new(c_bundle_context)) } diff --git a/misc/experimental/rust/celix/src/errno.rs b/misc/experimental/rust/celix/src/errno.rs index ea164b5b..a8037866 100644 --- a/misc/experimental/rust/celix/src/errno.rs +++ b/misc/experimental/rust/celix/src/errno.rs @@ -17,13 +17,18 @@ * under the License. */ -use celix_status_t; +use celix_bindings::celix_status_t; + +pub const CELIX_SUCCESS: celix_status_t = celix_bindings::CELIX_SUCCESS as celix_status_t; + +//Note compile-time defined constants are not available in rust generated bindings, so +//these are defined with literal values. +pub const BUNDLE_EXCEPTION: celix_status_t = 70001; -pub const BUNDLE_EXCEPTION: celix_status_t = 70001; //TODO move to celix_status_t_CELIX_BUNDLE_EXCEPTION pub enum Error { BundleException, - CelixStatusError(celix_status_t), // Represent unexpected C API errors + CelixStatusError(celix_status_t), // Represent not explicitly mapped celix_status_t values } impl From<celix_status_t> for Error { diff --git a/misc/experimental/rust/celix/src/mod.rs b/misc/experimental/rust/celix/src/lib.rs similarity index 50% rename from misc/experimental/rust/celix/src/mod.rs rename to misc/experimental/rust/celix/src/lib.rs index e0c30e20..791a3cda 100644 --- a/misc/experimental/rust/celix/src/mod.rs +++ b/misc/experimental/rust/celix/src/lib.rs @@ -17,25 +17,37 @@ * under the License. */ -use celix_status_t; +extern crate celix_bindings; -//Note C #defines (compile-time constants) are not all generated in the bindings file. -//So introduce them here as constants. -pub const CELIX_SUCCESS: celix_status_t = 0; +// Re-export the celix_status_t and celix_bundle_context_t C API in this crate public API so that +// it can be used in the generate_bundle_activator macro. +// Note that as result the celix rust lib is leaking the celix_status_t and celix_bundle_context_t +// C API in its public API. +#[doc(hidden)] +pub mod details { + pub use celix_bindings::celix_status_t as CStatus; + pub use celix_bindings::celix_bundle_context_t as CBundleContext; +} mod errno; -// Export errno types in the public API. +// Re-export errno types in the public API. +pub use self::errno::CELIX_SUCCESS as CELIX_SUCCESS; pub use self::errno::Error as Error; +mod log_level; +// Re-export log level types in the public API. +pub use self::log_level::LogLevel as LogLevel; + mod bundle_context; -// Export bundle context types in the public API. +// Re-export bundle context types in the public API. pub use self::bundle_context::BundleContext as BundleContext; -pub use self::bundle_context::create_bundle_context_instance as create_bundle_context_instance; +pub use self::bundle_context::bundle_context_new as bundle_context_new; mod bundle_activator; -// Export bundle activator types in the public API. +// Re-export bundle activator types in the public API. pub use self::bundle_activator::BundleActivator as BundleActivator; -// mod log_helper; -// // Export log helper types in the public API. -// pub use self::log_helper::LogHelper as LogHelper; +mod log_helper; +// Re-export log helper types in the public API. +pub use self::log_helper::LogHelper as LogHelper; +pub use self::log_helper::log_helper_new as log_helper_new; diff --git a/misc/experimental/rust/celix/src/log_helper.rs b/misc/experimental/rust/celix/src/log_helper.rs index 9f0a43b2..488c6277 100644 --- a/misc/experimental/rust/celix/src/log_helper.rs +++ b/misc/experimental/rust/celix/src/log_helper.rs @@ -17,68 +17,92 @@ * under the License. */ -use ::celix::BundleContext; -use celix_log_helper_t; -use celix_logHelper_create; -use celix_logHelper_destroy; -use celix_logHelper_log; +use super::LogLevel; +use super::BundleContext; -#[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, -} - -pub 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) }, - } - } +use celix_bindings::celix_log_helper_t; +use celix_bindings::celix_logHelper_create; +use celix_bindings::celix_logHelper_destroy; +use celix_bindings::celix_logHelper_log; - 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 trait LogHelper { + fn log(&self, level: LogLevel, message: &str); - pub fn trace(&self, message: &str) { + fn trace(&self, message: &str) { self.log(LogLevel::Trace, message); } - pub fn debug(&self, message: &str) { + fn debug(&self, message: &str) { self.log(LogLevel::Debug, message); } - pub fn info(&self, message: &str) { + fn info(&self, message: &str) { self.log(LogLevel::Info, message); } - pub fn warn(&self, message: &str) { - self.log(LogLevel::Warn, message); + fn warning(&self, message: &str) { + self.log(LogLevel::Warning, message); } - pub fn error(&self, message: &str) { + fn error(&self, message: &str) { self.log(LogLevel::Error, message); } - pub fn fatal(&self, message: &str) { + fn fatal(&self, message: &str) { self.log(LogLevel::Fatal, message); } } -impl Drop for LogHelper { +struct LogHelperImpl { + celix_log_helper: *mut celix_log_helper_t, +} + +impl LogHelperImpl { + pub fn new(ctx: &dyn BundleContext, name: &str) -> Self { + unsafe { + let result = std::ffi::CString::new(name); + match result { + Ok(c_str) => { + LogHelperImpl { + celix_log_helper: celix_logHelper_create(ctx.get_c_bundle_context(), c_str.as_ptr() as *const i8), + } + } + Err(e) => { + ctx.log_error(&format!("Error creating CString: {}. Using \"error\" as log name", e)); + let c_str = std::ffi::CString::new("error").unwrap(); + LogHelperImpl { + celix_log_helper: celix_logHelper_create(ctx.get_c_bundle_context(), c_str.as_ptr() as *const i8), + } + } + } + } + } +} + +impl Drop for LogHelperImpl { fn drop(&mut self) { unsafe { celix_logHelper_destroy(self.celix_log_helper); } } } + +impl LogHelper for LogHelperImpl { + fn log(&self, level: LogLevel, message: &str) { + unsafe { + let result = std::ffi::CString::new(message); + match result { + Ok(c_str) => { + celix_logHelper_log(self.celix_log_helper, level.into(), c_str.as_ptr() as *const i8); + } + Err(e) => { + println!("Error creating CString: {}", e); + } + } + } + } +} + +pub fn log_helper_new(ctx: &dyn BundleContext, name: &str) -> Box<dyn LogHelper> { + Box::new(LogHelperImpl::new(ctx, name)) +} diff --git a/misc/experimental/rust/celix/src/log_level.rs b/misc/experimental/rust/celix/src/log_level.rs new file mode 100644 index 00000000..d2b22470 --- /dev/null +++ b/misc/experimental/rust/celix/src/log_level.rs @@ -0,0 +1,64 @@ +/* + * 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_bindings::celix_log_level_e; +use celix_bindings::celix_log_level_CELIX_LOG_LEVEL_TRACE; +use celix_bindings::celix_log_level_CELIX_LOG_LEVEL_DEBUG; +use celix_bindings::celix_log_level_CELIX_LOG_LEVEL_INFO; +use celix_bindings::celix_log_level_CELIX_LOG_LEVEL_WARNING; +use celix_bindings::celix_log_level_CELIX_LOG_LEVEL_ERROR; +use celix_bindings::celix_log_level_CELIX_LOG_LEVEL_FATAL; +use celix_bindings::celix_log_level_CELIX_LOG_LEVEL_DISABLED; + +pub enum LogLevel { + Trace, + Debug, + Info, + Warning, + Error, + Fatal, + Disabled +} +impl From<celix_log_level_e> for LogLevel { + fn from(level: celix_log_level_e) -> Self { + match level { + celix_log_level_CELIX_LOG_LEVEL_TRACE => LogLevel::Trace, + celix_log_level_CELIX_LOG_LEVEL_DEBUG => LogLevel::Debug, + celix_log_level_CELIX_LOG_LEVEL_INFO => LogLevel::Info, + celix_log_level_CELIX_LOG_LEVEL_WARNING => LogLevel::Warning, + celix_log_level_CELIX_LOG_LEVEL_ERROR => LogLevel::Error, + celix_log_level_CELIX_LOG_LEVEL_FATAL => LogLevel::Fatal, + _ => LogLevel::Disabled, + } + } +} + +impl Into<celix_log_level_e> for LogLevel { + fn into(self) -> celix_log_level_e { + match self { + LogLevel::Trace => celix_log_level_CELIX_LOG_LEVEL_TRACE, + LogLevel::Debug => celix_log_level_CELIX_LOG_LEVEL_DEBUG, + LogLevel::Info => celix_log_level_CELIX_LOG_LEVEL_INFO, + LogLevel::Warning => celix_log_level_CELIX_LOG_LEVEL_WARNING, + LogLevel::Error => celix_log_level_CELIX_LOG_LEVEL_ERROR, + LogLevel::Fatal => celix_log_level_CELIX_LOG_LEVEL_FATAL, + _ => celix_log_level_CELIX_LOG_LEVEL_DISABLED, + } + } +} diff --git a/misc/experimental/rust/hello_world_activator/Cargo.toml b/misc/experimental/rust/hello_world_activator/Cargo.toml index 6202ece9..191c5e96 100644 --- a/misc/experimental/rust/hello_world_activator/Cargo.toml +++ b/misc/experimental/rust/hello_world_activator/Cargo.toml @@ -20,7 +20,7 @@ name = "rust_bundle" version = "0.0.1" [dependencies] -celix_bindings = { path = "../celix_bindings" } +celix = { path = "../celix" } [lib] name = "rust_bundle_activator" diff --git a/misc/experimental/rust/hello_world_activator/src/lib.rs b/misc/experimental/rust/hello_world_activator/src/lib.rs index 25390ddf..93c676ef 100644 --- a/misc/experimental/rust/hello_world_activator/src/lib.rs +++ b/misc/experimental/rust/hello_world_activator/src/lib.rs @@ -17,36 +17,41 @@ * under the License. */ -extern crate celix_bindings; +extern crate celix; + +use std::sync::Arc; -use celix_bindings::*; //Add all Apache Celix C bindings to the namespace (i.e. celix_bundleContext_log, etc.) use celix::BundleActivator; use celix::BundleContext; use celix::Error; -struct HelloWorldBundle {} +struct HelloWorldBundle { + ctx: Arc<dyn BundleContext>, +} impl BundleActivator for HelloWorldBundle { - fn new(ctx: &mut dyn celix::BundleContext) -> Self { + fn new(ctx: Arc<dyn celix::BundleContext>) -> Self { ctx.log_info("Hello World Bundle Activator created"); - HelloWorldBundle{} + HelloWorldBundle{ + ctx, + } } - fn start(&mut self, ctx: &mut dyn BundleContext) -> Result<(), Error> { - ctx.log_info("Hello World Bundle Activator started"); + fn start(&mut self) -> Result<(), Error> { + self.ctx.log_info("Hello World Bundle Activator started"); Ok(()) } - fn stop(&mut self, ctx: &mut dyn BundleContext) -> Result<(), Error> { - ctx.log_info("Hello World Bundle Activator stopped"); + fn stop(&mut self) -> Result<(), Error> { + self.ctx.log_info("Hello World Bundle Activator stopped"); Ok(()) } } impl Drop for HelloWorldBundle { fn drop(&mut self) { - //TODO self.ctx.log_info("Hello World Bundle Activator dropped"); + self.ctx.log_info("Hello World Bundle Activator destroyed"); } } -generate_bundle_activator!(HelloWorldBundle); \ No newline at end of file +celix::generate_bundle_activator!(HelloWorldBundle);