From 2c8d89a5863bfcc77f0d49db602abc1f66037842 Mon Sep 17 00:00:00 2001 From: Pepijn Noltes Date: Sat, 19 Aug 2023 20:03:08 +0200 Subject: [PATCH 01/21] #599: Add rust (mini) example impl for context, activator and log helper. --- misc/experimental/rust/CMakeLists.txt | 28 ++++-- misc/experimental/rust/Cargo.toml | 1 + .../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 + .../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(-) create mode 100644 misc/experimental/rust/celix_bindings/src/BundleActivator.rs create mode 100644 misc/experimental/rust/celix_bindings/src/BundleContext.rs create mode 100644 misc/experimental/rust/celix_bindings/src/LogHelper.rs diff --git a/misc/experimental/rust/CMakeLists.txt b/misc/experimental/rust/CMakeLists.txt index e2236a1af..3a7108032 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 "$;$" - ) + #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 + "$;$;$;$;$") 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 8727be5d9..ef69f6c63 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 000000000..e46ea8d36 --- /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 000000000..9dc340b76 --- /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 000000000..b168b80cc --- /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 8495c9a43..5db2ff227 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 c69c75247..2e6588d3b 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 4844acd2c..6202ece9f 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 17d835d48..89b6d78c7 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 { - 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 From 2f37f723797bf7e10a9e96ee71bc394742d558a7 Mon Sep 17 00:00:00 2001 From: Pepijn Noltes Date: Sat, 19 Aug 2023 20:03:25 +0200 Subject: [PATCH 02/21] #599: Add initial setup for rust shell tui --- .../rust/rust_shell_tui/Cargo.toml | 28 +++ .../rust/rust_shell_tui/src/lib.rs | 161 ++++++++++++++++++ 2 files changed, 189 insertions(+) create mode 100644 misc/experimental/rust/rust_shell_tui/Cargo.toml create mode 100644 misc/experimental/rust/rust_shell_tui/src/lib.rs diff --git a/misc/experimental/rust/rust_shell_tui/Cargo.toml b/misc/experimental/rust/rust_shell_tui/Cargo.toml new file mode 100644 index 000000000..fb4dced0c --- /dev/null +++ b/misc/experimental/rust/rust_shell_tui/Cargo.toml @@ -0,0 +1,28 @@ +# 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. + +[package] +name = "rust_shell_tui" +version = "0.0.1" + +[dependencies] +celix_bindings = { path = "../celix_bindings" } + +[lib] +name = "rust_shell_tui_activator" +path = "src/lib.rs" +crate-type = ["cdylib"] diff --git a/misc/experimental/rust/rust_shell_tui/src/lib.rs b/misc/experimental/rust/rust_shell_tui/src/lib.rs new file mode 100644 index 000000000..08727add6 --- /dev/null +++ b/misc/experimental/rust/rust_shell_tui/src/lib.rs @@ -0,0 +1,161 @@ +/* + * 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. + */ + +extern crate celix_bindings; + +use std::os::raw::c_char; +use std::os::raw::c_void; +use std::ffi::CString; +use std::ffi::NulError; +use std::ptr::null_mut; +use celix_bindings::*; //Add all Apache Celix C bindings to the namespace (i.e. celix_bundleContext_log, etc.) + +// pub struct celix_shell_command { +// pub handle +// : *mut ::std ::os ::raw ::c_void, +// #[doc = +// " Calls the shell command.\n @param handle The shell command handle.\n @param commandLine The " +// "complete provided cmd line (e.g. for a 'stop' command -> 'stop 42')\n @param outStream The output " +// "stream, to use for printing normal flow info.\n @param errorStream The error stream, to use for " +// "printing error flow info.\n @return Whether a command is successfully executed."] pub +// executeCommand +// pub executeCommand : :: std :: option :: Option < unsafe extern "C" fn (handle : * mut :: std :: os :: raw :: c_void , commandLine : * const :: std :: os :: raw :: c_char , outStream : * mut FILE , errorStream : * mut FILE) -> bool > , } +// } + + +struct RustShellTui { + ctx: *mut celix_bundle_context_t, + svc_id: i64, + svc: celix_shell_command, +} + +unsafe extern "C" fn rust_shell_tui_execute_command(_handle: *mut c_void, command_line: *const c_char, out_stream: *mut FILE, error_stream: *mut FILE) -> bool { + let obj = Box::from_raw(_handle as *mut RustShellTui); + obj.execute_command(command_line, out_stream, error_stream) +} + +impl RustShellTui { + + unsafe fn new(ctx: *mut celix_bundle_context_t) -> Result { + let result = RustShellTui { + ctx, + svc_id: -1, + svc: celix_shell_command { + handle: null_mut(), + executeCommand: Some(rust_shell_tui_execute_command), + }, + }; + Ok(result) + } + + unsafe fn start(&mut self) -> Result<(), NulError> { + + // let mut input = String::new(); + // print!("-> "); + // loop { + // std::io::stdin().read_line(&mut input).unwrap(); + // println!("You typed: {}", input.trim()); + // input.clear(); + // print!("-> "); + // } + + // self.svc.executeCommand = Some(|handle: *mut c_void, commandLine: *const c_char, outStream: *mut FILE, errorStream: *mut FILE| -> bool { + // println!("RustShellTui::executeCommand called"); + // true + // }); + + //TODO let svc_name = CString::new(CELIX_SHELL_COMMAND_SERVICE_NAME as * const c_char).unwrap(); + let svc_name = CString::new("celix_shell_command").unwrap(); + + let command_name = CString::new("command.name").unwrap(); + let props = celix_properties_create(); + celix_properties_set(props, command_name.as_ptr(), CString::new("rust").unwrap().as_ptr()); + + self.svc.handle = Box::into_raw(Box::new(self.svc)) as *mut c_void; + + + self.svc_id = celix_bundleContext_registerServiceAsync( + self.ctx, + Box::into_raw(Box::new(self.svc)) as *mut c_void, + svc_name.as_ptr(), + props); + + Ok(()) + } + + unsafe fn stop(&mut self) -> Result<(), NulError> { + celix_bundleContext_unregisterService(self.ctx, self.svc_id); + self.svc_id = -1; + + // let to_drop = Box::from_raw(self.svc.handle); + // drop(to_drop); + + // TODO drop + // let to_drop = Box::from_raw(&self.svc); + // drop(to_drop); + Ok(()) + } + + fn execute_command(&self, _command_line: *const c_char, _out_stream: *mut FILE, _error_stream: *mut FILE) -> bool { + println!("RustShellTui::executeCommand called"); + true + } +} + +impl Drop for RustShellTui { + fn drop(&mut self) { () } +} + +#[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 obj = RustShellTui::new(ctx); + if obj.is_err() { + return CELIX_BUNDLE_EXCEPTION; + } + *data = Box::into_raw(Box::new(obj.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 obj = &mut *(data as *mut RustShellTui); + let result = obj.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 obj = &mut *(data as *mut RustShellTui); + let result = obj.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 obj = Box::from_raw(data as *mut RustShellTui); + drop(obj); + CELIX_SUCCESS +} + From 3b4ccb9effd87c42e3ddb973ab7075f1e4ac03fd Mon Sep 17 00:00:00 2001 From: Pepijn Noltes Date: Sun, 20 Aug 2023 16:43:31 +0200 Subject: [PATCH 03/21] #599: Refactor rust api into modules --- misc/experimental/rust/CMakeLists.txt | 22 ++--- misc/experimental/rust/Cargo.toml | 2 +- .../celix_bindings/src/BundleActivator.rs | 78 ---------------- .../src/celix/bundle_activator.rs | 92 +++++++++++++++++++ .../bundle_context.rs} | 11 ++- .../rust/celix_bindings/src/celix/errno.rs | 45 +++++++++ .../src/{LogHelper.rs => celix/log_helper.rs} | 8 +- .../rust/celix_bindings/src/celix/mod.rs | 41 +++++++++ .../rust/celix_bindings/src/lib.rs | 22 +---- .../rust/hello_world_activator/src/lib.rs | 16 ++-- 10 files changed, 214 insertions(+), 123 deletions(-) delete mode 100644 misc/experimental/rust/celix_bindings/src/BundleActivator.rs create mode 100644 misc/experimental/rust/celix_bindings/src/celix/bundle_activator.rs rename misc/experimental/rust/celix_bindings/src/{BundleContext.rs => celix/bundle_context.rs} (79%) create mode 100644 misc/experimental/rust/celix_bindings/src/celix/errno.rs rename misc/experimental/rust/celix_bindings/src/{LogHelper.rs => celix/log_helper.rs} (93%) create mode 100644 misc/experimental/rust/celix_bindings/src/celix/mod.rs diff --git a/misc/experimental/rust/CMakeLists.txt b/misc/experimental/rust/CMakeLists.txt index 3a7108032..a98150f2e 100644 --- a/misc/experimental/rust/CMakeLists.txt +++ b/misc/experimental/rust/CMakeLists.txt @@ -41,11 +41,11 @@ if (CELIX_RUST_EXPERIMENTAL) add_celix_bundle(rust_bundle ACTIVATOR ${ACTUAL_LIB_TARGET}) add_dependencies(rust_bundle rust_bundle_activator) - 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) +# 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 @@ -54,11 +54,11 @@ if (CELIX_RUST_EXPERIMENTAL) rust_bundle ) - add_celix_container(rust_shell_tui_cnt NO_COPY - BUNDLES - Celix::shell - Celix::shell_tui - rust_shell_tui - ) +# 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 ef69f6c63..891c8dd64 100644 --- a/misc/experimental/rust/Cargo.toml +++ b/misc/experimental/rust/Cargo.toml @@ -19,5 +19,5 @@ members = [ "celix_bindings", "hello_world_activator", - "rust_shell_tui", + #"rust_shell_tui", ] diff --git a/misc/experimental/rust/celix_bindings/src/BundleActivator.rs b/misc/experimental/rust/celix_bindings/src/BundleActivator.rs deleted file mode 100644 index e46ea8d36..000000000 --- a/misc/experimental/rust/celix_bindings/src/BundleActivator.rs +++ /dev/null @@ -1,78 +0,0 @@ -/* - * 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/celix/bundle_activator.rs b/misc/experimental/rust/celix_bindings/src/celix/bundle_activator.rs new file mode 100644 index 000000000..01dece714 --- /dev/null +++ b/misc/experimental/rust/celix_bindings/src/celix/bundle_activator.rs @@ -0,0 +1,92 @@ +/* + * 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::BundleContext; +use ::celix::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(())} +} + +#[macro_export] +macro_rules! generate_bundle_activator { + ($activator:ty) => { + // fn assert_implements_trait(_: &$activator) { + // fn must_implement(_t: &T) {} + // must_implement(&*(None::<$activator>).unwrap_or_default()); + // } + + struct ActivatorWrapper { + ctx: Box, + activator: $activator, + } + + #[no_mangle] + pub unsafe extern "C" fn celix_bundleActivator_create( + ctx: *mut $crate::celix_bundle_context_t, + 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 + } + + #[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); + match result { + Ok(_) => $crate::celix::CELIX_SUCCESS, + Err(e) => e.into(), + } + } + + #[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); + match result { + Ok(_) => $crate::celix::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 + } + }; +} diff --git a/misc/experimental/rust/celix_bindings/src/BundleContext.rs b/misc/experimental/rust/celix_bindings/src/celix/bundle_context.rs similarity index 79% rename from misc/experimental/rust/celix_bindings/src/BundleContext.rs rename to misc/experimental/rust/celix_bindings/src/celix/bundle_context.rs index 9dc340b76..b63ae4977 100644 --- a/misc/experimental/rust/celix_bindings/src/BundleContext.rs +++ b/misc/experimental/rust/celix_bindings/src/celix/bundle_context.rs @@ -16,6 +16,9 @@ * specific language governing permissions and limitations * under the License. */ + +use celix_bundle_context_t; +use celix_bundleContext_log; use celix_log_level_CELIX_LOG_LEVEL_INFO; pub trait BundleContext { @@ -44,7 +47,13 @@ impl BundleContext for BundleContextImpl { 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); + //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); } } } + +pub fn create_bundle_context_instance(c_bundle_context: *mut celix_bundle_context_t) -> Box { + Box::new(BundleContextImpl::new(c_bundle_context)) +} diff --git a/misc/experimental/rust/celix_bindings/src/celix/errno.rs b/misc/experimental/rust/celix_bindings/src/celix/errno.rs new file mode 100644 index 000000000..ea164b5b2 --- /dev/null +++ b/misc/experimental/rust/celix_bindings/src/celix/errno.rs @@ -0,0 +1,45 @@ +/* + * 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_status_t; + +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 +} + +impl From for Error { + fn from(status: celix_status_t) -> Self { + match status { + BUNDLE_EXCEPTION => Error::BundleException, + _ => Error::CelixStatusError(status), + } + } +} + +impl Into for Error { + fn into(self) -> celix_status_t { + match self { + Error::BundleException => BUNDLE_EXCEPTION, + Error::CelixStatusError(status) => status, + } + } +} diff --git a/misc/experimental/rust/celix_bindings/src/LogHelper.rs b/misc/experimental/rust/celix_bindings/src/celix/log_helper.rs similarity index 93% rename from misc/experimental/rust/celix_bindings/src/LogHelper.rs rename to misc/experimental/rust/celix_bindings/src/celix/log_helper.rs index b168b80cc..9f0a43b23 100644 --- a/misc/experimental/rust/celix_bindings/src/LogHelper.rs +++ b/misc/experimental/rust/celix_bindings/src/celix/log_helper.rs @@ -17,6 +17,12 @@ * under the License. */ +use ::celix::BundleContext; +use celix_log_helper_t; +use celix_logHelper_create; +use celix_logHelper_destroy; +use celix_logHelper_log; + #[warn(unused_imports)] pub enum LogLevel { Trace = ::bindings::celix_log_level_CELIX_LOG_LEVEL_TRACE as isize, @@ -27,7 +33,7 @@ pub enum LogLevel { Fatal = ::bindings::celix_log_level_CELIX_LOG_LEVEL_FATAL as isize, } -struct LogHelper { +pub struct LogHelper { celix_log_helper: *mut celix_log_helper_t, } diff --git a/misc/experimental/rust/celix_bindings/src/celix/mod.rs b/misc/experimental/rust/celix_bindings/src/celix/mod.rs new file mode 100644 index 000000000..e0c30e209 --- /dev/null +++ b/misc/experimental/rust/celix_bindings/src/celix/mod.rs @@ -0,0 +1,41 @@ +/* + * 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_status_t; + +//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; + +mod errno; +// Export errno types in the public API. +pub use self::errno::Error as Error; + +mod bundle_context; +// 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; + +mod bundle_activator; +// 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; diff --git a/misc/experimental/rust/celix_bindings/src/lib.rs b/misc/experimental/rust/celix_bindings/src/lib.rs index 2e6588d3b..a07ac3ead 100644 --- a/misc/experimental/rust/celix_bindings/src/lib.rs +++ b/misc/experimental/rust/celix_bindings/src/lib.rs @@ -23,24 +23,4 @@ mod bindings { } 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; - -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; - - include!("BundleContext.rs"); - include!("BundleActivator.rs"); - include!("LogHelper.rs"); -} +pub mod celix; diff --git a/misc/experimental/rust/hello_world_activator/src/lib.rs b/misc/experimental/rust/hello_world_activator/src/lib.rs index 89b6d78c7..25390ddf8 100644 --- a/misc/experimental/rust/hello_world_activator/src/lib.rs +++ b/misc/experimental/rust/hello_world_activator/src/lib.rs @@ -19,31 +19,27 @@ extern crate celix_bindings; -use std::os::raw::c_void; -use std::ffi::CString; -use std::ffi::NulError; - -//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; +use celix::Error; struct HelloWorldBundle {} impl BundleActivator for HelloWorldBundle { fn new(ctx: &mut dyn celix::BundleContext) -> Self { ctx.log_info("Hello World Bundle Activator created"); - HelloWorldBundle {} + HelloWorldBundle{} } - fn start(&mut self, ctx: &mut dyn BundleContext) -> celix_status_t { + fn start(&mut self, ctx: &mut dyn BundleContext) -> Result<(), Error> { ctx.log_info("Hello World Bundle Activator started"); - CELIX_SUCCESS + Ok(()) } - fn stop(&mut self, ctx: &mut dyn BundleContext) -> celix_status_t { + fn stop(&mut self, ctx: &mut dyn BundleContext) -> Result<(), Error> { ctx.log_info("Hello World Bundle Activator stopped"); - CELIX_SUCCESS + Ok(()) } } From 4c14d8cab191e9c1b7955f75a04353e6e06d2a0e Mon Sep 17 00:00:00 2001 From: Pepijn Noltes Date: Sun, 20 Aug 2023 16:48:57 +0200 Subject: [PATCH 04/21] #599: Move Celix rust api to a separate rust lib --- misc/experimental/rust/Cargo.toml | 1 + misc/experimental/rust/celix/Cargo.toml | 29 +++++++++++++++++++ .../celix => celix/src}/bundle_activator.rs | 0 .../src/celix => celix/src}/bundle_context.rs | 0 .../src/celix => celix/src}/errno.rs | 0 .../src/celix => celix/src}/log_helper.rs | 0 .../src/celix => celix/src}/mod.rs | 0 .../rust/celix_bindings/src/lib.rs | 2 -- 8 files changed, 30 insertions(+), 2 deletions(-) create mode 100644 misc/experimental/rust/celix/Cargo.toml rename misc/experimental/rust/{celix_bindings/src/celix => celix/src}/bundle_activator.rs (100%) rename misc/experimental/rust/{celix_bindings/src/celix => celix/src}/bundle_context.rs (100%) rename misc/experimental/rust/{celix_bindings/src/celix => celix/src}/errno.rs (100%) rename misc/experimental/rust/{celix_bindings/src/celix => celix/src}/log_helper.rs (100%) rename misc/experimental/rust/{celix_bindings/src/celix => celix/src}/mod.rs (100%) diff --git a/misc/experimental/rust/Cargo.toml b/misc/experimental/rust/Cargo.toml index 891c8dd64..d6679dd3f 100644 --- a/misc/experimental/rust/Cargo.toml +++ b/misc/experimental/rust/Cargo.toml @@ -18,6 +18,7 @@ [workspace] members = [ "celix_bindings", + "celix", "hello_world_activator", #"rust_shell_tui", ] diff --git a/misc/experimental/rust/celix/Cargo.toml b/misc/experimental/rust/celix/Cargo.toml new file mode 100644 index 000000000..d81416c8d --- /dev/null +++ b/misc/experimental/rust/celix/Cargo.toml @@ -0,0 +1,29 @@ +# 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. + +[package] +name = "celixs" +version = "0.0.1" + +[build-dependencies] +celix_bindings = { path = "../celix_bindings" } + + +[lib] +name = "bindings" +path = "src/lib.rs" +crate-type = ["rlib"] diff --git a/misc/experimental/rust/celix_bindings/src/celix/bundle_activator.rs b/misc/experimental/rust/celix/src/bundle_activator.rs similarity index 100% rename from misc/experimental/rust/celix_bindings/src/celix/bundle_activator.rs rename to misc/experimental/rust/celix/src/bundle_activator.rs diff --git a/misc/experimental/rust/celix_bindings/src/celix/bundle_context.rs b/misc/experimental/rust/celix/src/bundle_context.rs similarity index 100% rename from misc/experimental/rust/celix_bindings/src/celix/bundle_context.rs rename to misc/experimental/rust/celix/src/bundle_context.rs diff --git a/misc/experimental/rust/celix_bindings/src/celix/errno.rs b/misc/experimental/rust/celix/src/errno.rs similarity index 100% rename from misc/experimental/rust/celix_bindings/src/celix/errno.rs rename to misc/experimental/rust/celix/src/errno.rs diff --git a/misc/experimental/rust/celix_bindings/src/celix/log_helper.rs b/misc/experimental/rust/celix/src/log_helper.rs similarity index 100% rename from misc/experimental/rust/celix_bindings/src/celix/log_helper.rs rename to misc/experimental/rust/celix/src/log_helper.rs diff --git a/misc/experimental/rust/celix_bindings/src/celix/mod.rs b/misc/experimental/rust/celix/src/mod.rs similarity index 100% rename from misc/experimental/rust/celix_bindings/src/celix/mod.rs rename to misc/experimental/rust/celix/src/mod.rs diff --git a/misc/experimental/rust/celix_bindings/src/lib.rs b/misc/experimental/rust/celix_bindings/src/lib.rs index a07ac3ead..64fdba67b 100644 --- a/misc/experimental/rust/celix_bindings/src/lib.rs +++ b/misc/experimental/rust/celix_bindings/src/lib.rs @@ -22,5 +22,3 @@ mod bindings { include!(concat!(env!("OUT_DIR"), "/celix_bindings.rs")); } pub use bindings::*; - -pub mod celix; From 21b00277b2fb052eac308a6c002df7512c969ab4 Mon Sep 17 00:00:00 2001 From: Pepijn Noltes Date: Sun, 20 Aug 2023 19:33:32 +0200 Subject: [PATCH 05/21] #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 ++++++------ .../rust/celix/src/bundle_context.rs | 58 +++++++--- misc/experimental/rust/celix/src/errno.rs | 11 +- .../rust/celix/src/{mod.rs => lib.rs} | 34 ++++-- .../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(-) rename misc/experimental/rust/celix/src/{mod.rs => lib.rs} (50%) create mode 100644 misc/experimental/rust/celix/src/log_level.rs diff --git a/misc/experimental/rust/celix/Cargo.toml b/misc/experimental/rust/celix/Cargo.toml index d81416c8d..4ae427660 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 01dece714..11fa22a3e 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) -> 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: &T) {} - // must_implement(&*(None::<$activator>).unwrap_or_default()); - // } - - struct ActivatorWrapper { - ctx: Box, - 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 b63ae4977..4bfacce24 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 { +pub fn bundle_context_new(c_bundle_context: *mut celix_bundle_context_t) -> Box { 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 ea164b5b2..a8037866d 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 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 e0c30e209..791a3cda4 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 9f0a43b23..488c6277a 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 { + 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 000000000..d2b22470d --- /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 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 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 6202ece9f..191c5e96d 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 25390ddf8..93c676efc 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, +} impl BundleActivator for HelloWorldBundle { - fn new(ctx: &mut dyn celix::BundleContext) -> Self { + fn new(ctx: Arc) -> 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); From 1654e21e52199dc8dacddbd1ef1bfb575f496c86 Mon Sep 17 00:00:00 2001 From: Pepijn Noltes Date: Tue, 22 Aug 2023 20:24:42 +0200 Subject: [PATCH 06/21] #599: Refactor bundle context for service registration builder --- misc/experimental/rust/CMakeLists.txt | 22 +- misc/experimental/rust/Cargo.toml | 1 + .../rust/celix/src/bundle_context.rs | 227 +++++++++++++++++- misc/experimental/rust/celix/src/lib.rs | 1 + misc/experimental/rust/celix/src/log_level.rs | 40 +-- .../rust/shell_command_bundle/Cargo.toml | 29 +++ .../rust/shell_command_bundle/src/lib.rs | 107 +++++++++ 7 files changed, 390 insertions(+), 37 deletions(-) create mode 100644 misc/experimental/rust/shell_command_bundle/Cargo.toml create mode 100644 misc/experimental/rust/shell_command_bundle/src/lib.rs diff --git a/misc/experimental/rust/CMakeLists.txt b/misc/experimental/rust/CMakeLists.txt index a98150f2e..6ab2287c3 100644 --- a/misc/experimental/rust/CMakeLists.txt +++ b/misc/experimental/rust/CMakeLists.txt @@ -41,11 +41,11 @@ if (CELIX_RUST_EXPERIMENTAL) add_celix_bundle(rust_bundle ACTIVATOR ${ACTUAL_LIB_TARGET}) add_dependencies(rust_bundle rust_bundle_activator) -# 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) + corrosion_add_target_local_rustflags(rust_shell_command_activator "-Cprefer-dynamic") + corrosion_link_libraries(rust_shell_command_activator Celix::framework) + get_target_property(ACTUAL_LIB_TARGET rust_shell_command_activator INTERFACE_LINK_LIBRARIES) + add_celix_bundle(rust_shell_command ACTIVATOR ${ACTUAL_LIB_TARGET}) + add_dependencies(rust_shell_command rust_shell_command_activator) add_celix_container(rust_container NO_COPY BUNDLES @@ -54,11 +54,11 @@ if (CELIX_RUST_EXPERIMENTAL) rust_bundle ) -# add_celix_container(rust_shell_tui_cnt NO_COPY -# BUNDLES -# Celix::shell -# Celix::shell_tui -# rust_shell_tui -# ) + add_celix_container(rust_shell_cnt NO_COPY + BUNDLES + Celix::shell + Celix::shell_tui + rust_shell_command + ) endif() diff --git a/misc/experimental/rust/Cargo.toml b/misc/experimental/rust/Cargo.toml index d6679dd3f..95f253d0a 100644 --- a/misc/experimental/rust/Cargo.toml +++ b/misc/experimental/rust/Cargo.toml @@ -20,5 +20,6 @@ members = [ "celix_bindings", "celix", "hello_world_activator", + "shell_command_bundle", #"rust_shell_tui", ] diff --git a/misc/experimental/rust/celix/src/bundle_context.rs b/misc/experimental/rust/celix/src/bundle_context.rs index 4bfacce24..5ff380a43 100644 --- a/misc/experimental/rust/celix/src/bundle_context.rs +++ b/misc/experimental/rust/celix/src/bundle_context.rs @@ -17,11 +17,199 @@ * under the License. */ -use super::LogLevel; +use std::ptr::null_mut; +use std::ffi::c_void; +use std::collections::HashMap; +use std::sync::Arc; +use std::sync::Weak; +use std::any::type_name; +use std::any::Any; +use std::sync::Mutex; use celix_bindings::celix_bundle_context_t; use celix_bindings::celix_bundleContext_log; -use celix_bindings::celix_log_level_e; +use celix_bindings::celix_properties_create; +use celix_bindings::celix_properties_set; +use celix_bindings::celix_bundleContext_registerServiceWithOptions; +use celix_bindings::celix_bundleContext_unregisterService; +use celix_bindings::celix_service_registration_options_t; + +use super::Error; +use super::LogLevel; + +pub struct ServiceRegistration { + service_id: i64, + weak_ctx: Weak, + boxed_svc: Option>, + // arc_svc: Option>, +} + +impl Drop for ServiceRegistration { + fn drop(&mut self) { + let ctx = self.weak_ctx.upgrade(); + match ctx { + Some(ctx) => ctx.unregister_service(self.service_id), + None => println!("Cannot unregister ServiceRegistration: BundleContext is gone"), + } + } +} + +pub struct ServiceRegistrationBuilder<'a> { + ctx: &'a BundleContextImpl, + boxed_svc: Option>, + // _arc_svc: Option>, + unmanaged_svc: *mut c_void, + service_name: String, + service_version: String, + service_properties: HashMap, +} + +impl ServiceRegistrationBuilder<'_> { + fn new<'a>(ctx: &'a BundleContextImpl) -> ServiceRegistrationBuilder<'a> { + ServiceRegistrationBuilder { + ctx, + boxed_svc: None, + //arc_svc: None, + unmanaged_svc: null_mut(), + service_name: "".to_string(), + service_version: "".to_string(), + service_properties: HashMap::new(), + } + } + + pub fn with_service_name(&mut self, name: &str) -> &mut Self { + self.service_name = name.to_string(); + self + } + + fn with_type_name_as_service_name(&mut self) -> &mut Self { + if self.service_name.is_empty() { + self.service_name = type_name::().to_string(); + } + self + } + + pub fn with_service(&mut self, instance: I) -> &mut Self { + self.boxed_svc = Some(Box::new(instance)); + //self.arc_svc = None; + self.unmanaged_svc = null_mut(); + self.with_type_name_as_service_name::() + } + + //TODO check if dyn is needed (e.g. a trait object is needed) + pub fn with_boxed_service(&mut self, instance: Box) -> &mut Self { + self.boxed_svc = Some(instance); + //self.arc_svc = None; + self.unmanaged_svc = null_mut(); + self.with_type_name_as_service_name::() + } + + //TODO check if dyn is needed (e.g. a trait object is needed) + // pub fn with_arc_instance(&mut self, instance: Arc) -> &mut Self { + // self.boxed_svc = None; + // self.arc_svc = Some(instance); + // self.unmanaged_svc = null_mut(); + // self.with_type_name_as_service_name::() + // } + + pub fn with_unmanaged_service(&mut self, instance: *mut I) -> &mut Self { + self.boxed_svc = None; + //self.arc_svc = None; + self.unmanaged_svc = instance as *mut c_void; + self.with_type_name_as_service_name::() + } + + pub fn with_version(&mut self, version: &str) -> &mut Self { + self.service_version = version.to_string(); + self + } + + pub fn with_properties(&mut self, properties: HashMap) -> &mut Self { + self.service_properties = properties; + self + } + + pub fn with_property(&mut self, key: &str, value: &str) -> &mut Self { + self.service_properties.insert(key.to_string(), value.to_string()); + self + } + + fn validate(&self) -> Result<(), Error> { + let mut valid = true; + if self.service_name.is_empty() { + self.ctx.log_error("Cannot register service. Service name is empty"); + valid = false; + } + if self.boxed_svc.is_none() && /*self.arc_svc.is_none() &&*/ self.unmanaged_svc.is_null() { + self.ctx.log_error("Cannot register service. No instance provided"); + valid = false; + } + match valid { + true => Ok(()), + false => Err(Error::BundleException), + } + } + + fn get_c_svc(&mut self) -> *mut c_void { + if let Some(boxed_svc) = self.boxed_svc.as_mut() { + let any_svc: &mut dyn Any = boxed_svc.as_mut(); + let boxed_svc_ptr = any_svc as *mut dyn Any; //note box still owns the instance + boxed_svc_ptr as *mut c_void + // } else if let Some(arc_svc) = self.arc_svc.as_mut() { + // let any_svc: &mut dyn Any = arc_svc.as_mut(); + // let arc_svc_ptr = arc_svc as *mut dyn Any; //note arc still owns the instance + // arc_svc_ptr as *mut c_void + } else if self.unmanaged_svc.is_null() { + panic!("Cannot get c_svc. No instance provided"); + } else { + self.unmanaged_svc as *mut c_void + } + } + + unsafe fn build_unsafe(&mut self) -> Result { + let c_service_name = std::ffi::CString::new(self.service_name.as_str()).unwrap(); + let c_service_version = std::ffi::CString::new(self.service_version.as_str()).unwrap(); + let c_service_properties = celix_properties_create(); + let c_service = self.get_c_svc(); + for (key, value) in self.service_properties.iter() { + let c_key = std::ffi::CString::new(key.as_str()).unwrap(); + let c_value = std::ffi::CString::new(value.as_str()).unwrap(); + celix_properties_set(c_service_properties, c_key.as_ptr(), c_value.as_ptr()); + } + let opts = celix_service_registration_options_t { + svc: c_service, + factory: null_mut(), + serviceName: c_service_name.as_ptr() as *const i8, + properties: c_service_properties, + serviceLanguage: null_mut(), + serviceVersion: if self.service_version.is_empty() { null_mut() } else { c_service_version.as_ptr() as *const i8}, + asyncData: null_mut(), + asyncCallback: None, + }; + + let service_id: i64 = celix_bundleContext_registerServiceWithOptions( + self.ctx.get_c_bundle_context(), + &opts); + if service_id >= 0 { + Ok(ServiceRegistration { + service_id, + weak_ctx: self.ctx.get_self().clone(), + boxed_svc: self.boxed_svc.take(), //to ensure that a possible box instance is not dropped + // arc_svc: self.arc_svc.take(), //to ensure that a possible arc instance is not dropped + }) + } else { + Err(Error::BundleException) + } + } + + pub fn build(&mut self) -> Result { + self.validate()?; + unsafe { + //TODO make unsafe part smaller (if possible) + self.build_unsafe() + } + } +} pub trait BundleContext { fn get_c_bundle_context(&self) -> *mut celix_bundle_context_t; @@ -39,18 +227,41 @@ pub trait BundleContext { fn log_error(&self, message: &str); fn log_fatal(&self, message: &str); + + fn register_service(&self) -> ServiceRegistrationBuilder; } struct BundleContextImpl { c_bundle_context: *mut celix_bundle_context_t, + weak_self : Mutex>>, } impl BundleContextImpl { - pub fn new(c_bundle_context: *mut celix_bundle_context_t) -> Self { - BundleContextImpl { + fn new(c_bundle_context: *mut celix_bundle_context_t) -> Arc { + let ctx = Arc::new(BundleContextImpl { c_bundle_context, + weak_self: Mutex::new(None), + }); + let weak_ref = Arc::downgrade(&ctx); + ctx.set_self(weak_ref); + ctx + } + + fn set_self(&self, weak_self: Weak) { + let mut guard = self.weak_self.lock().unwrap(); + *guard = Some(weak_self); + } + + fn get_self(&self) -> Weak { + self.weak_self.lock().unwrap().clone().unwrap() + } + + fn unregister_service(&self, service_id: i64) { + unsafe { + celix_bundleContext_unregisterService(self.c_bundle_context, service_id); } } + fn log_to_c(&self, level: LogLevel, message: &str) { unsafe { let result = std::ffi::CString::new(message); @@ -84,8 +295,12 @@ impl BundleContext for BundleContextImpl { fn log_error(&self, message: &str){ self.log(LogLevel::Error, message); } fn log_fatal(&self, message: &str){ self.log(LogLevel::Fatal, message); } + + fn register_service(&self) -> ServiceRegistrationBuilder { + ServiceRegistrationBuilder::new(self) + } } -pub fn bundle_context_new(c_bundle_context: *mut celix_bundle_context_t) -> Box { - Box::new(BundleContextImpl::new(c_bundle_context)) +pub fn bundle_context_new(c_bundle_context: *mut celix_bundle_context_t) -> Arc { + BundleContextImpl::new(c_bundle_context) } diff --git a/misc/experimental/rust/celix/src/lib.rs b/misc/experimental/rust/celix/src/lib.rs index 791a3cda4..9befdeb8e 100644 --- a/misc/experimental/rust/celix/src/lib.rs +++ b/misc/experimental/rust/celix/src/lib.rs @@ -41,6 +41,7 @@ pub use self::log_level::LogLevel as LogLevel; mod bundle_context; // Re-export bundle context types in the public API. pub use self::bundle_context::BundleContext as BundleContext; +pub use self::bundle_context::ServiceRegistration as ServiceRegistration; pub use self::bundle_context::bundle_context_new as bundle_context_new; mod bundle_activator; diff --git a/misc/experimental/rust/celix/src/log_level.rs b/misc/experimental/rust/celix/src/log_level.rs index d2b22470d..bc9b5e489 100644 --- a/misc/experimental/rust/celix/src/log_level.rs +++ b/misc/experimental/rust/celix/src/log_level.rs @@ -18,13 +18,13 @@ */ 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; +use celix_bindings::celix_log_level_CELIX_LOG_LEVEL_TRACE as CELIX_LOG_LEVEL_TRACE; +use celix_bindings::celix_log_level_CELIX_LOG_LEVEL_DEBUG as CELIX_LOG_LEVEL_DEBUG; +use celix_bindings::celix_log_level_CELIX_LOG_LEVEL_INFO as CELIX_LOG_LEVEL_INFO; +use celix_bindings::celix_log_level_CELIX_LOG_LEVEL_WARNING as CELIX_LOG_LEVEL_WARNING; +use celix_bindings::celix_log_level_CELIX_LOG_LEVEL_ERROR as CELIX_LOG_LEVEL_ERROR; +use celix_bindings::celix_log_level_CELIX_LOG_LEVEL_FATAL as CELIX_LOG_LEVEL_FATAL; +use celix_bindings::celix_log_level_CELIX_LOG_LEVEL_DISABLED as CELIX_LOG_LEVEL_DISABLED; pub enum LogLevel { Trace, @@ -38,12 +38,12 @@ pub enum LogLevel { impl From 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, + CELIX_LOG_LEVEL_TRACE => LogLevel::Trace, + CELIX_LOG_LEVEL_DEBUG => LogLevel::Debug, + CELIX_LOG_LEVEL_INFO => LogLevel::Info, + CELIX_LOG_LEVEL_WARNING => LogLevel::Warning, + CELIX_LOG_LEVEL_ERROR => LogLevel::Error, + CELIX_LOG_LEVEL_FATAL => LogLevel::Fatal, _ => LogLevel::Disabled, } } @@ -52,13 +52,13 @@ impl From for LogLevel { impl Into 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, + LogLevel::Trace => CELIX_LOG_LEVEL_TRACE, + LogLevel::Debug => CELIX_LOG_LEVEL_DEBUG, + LogLevel::Info => CELIX_LOG_LEVEL_INFO, + LogLevel::Warning => CELIX_LOG_LEVEL_WARNING, + LogLevel::Error => CELIX_LOG_LEVEL_ERROR, + LogLevel::Fatal => CELIX_LOG_LEVEL_FATAL, + _ => CELIX_LOG_LEVEL_DISABLED, } } } diff --git a/misc/experimental/rust/shell_command_bundle/Cargo.toml b/misc/experimental/rust/shell_command_bundle/Cargo.toml new file mode 100644 index 000000000..1773c986a --- /dev/null +++ b/misc/experimental/rust/shell_command_bundle/Cargo.toml @@ -0,0 +1,29 @@ +# 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. + +[package] +name = "rust_shell_command_activator" +version = "0.0.1" + +[dependencies] +celix_bindings = { path = "../celix_bindings" } +celix = { path = "../celix" } + +[lib] +name = "rust_shell_command_activator" +path = "src/lib.rs" +crate-type = ["cdylib"] diff --git a/misc/experimental/rust/shell_command_bundle/src/lib.rs b/misc/experimental/rust/shell_command_bundle/src/lib.rs new file mode 100644 index 000000000..cc9b83f9f --- /dev/null +++ b/misc/experimental/rust/shell_command_bundle/src/lib.rs @@ -0,0 +1,107 @@ +/* + * 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. + */ + +extern crate celix_bindings; +extern crate celix; + +use std::sync::Arc; +use std::ffi::c_void; +use std::ffi::c_char; + +use celix::BundleActivator; +use celix::BundleContext; +use celix::Error; + +use celix_bindings::celix_shell_command_t; +use celix_bindings::FILE; + +//temporary, should be moved in a separate API crate +// trait RustShellCommand { +// fn execute_command(&mut self, command_line: &str, command_args: Vec<&str>) -> Result<(), Error>; +// } + +struct ShellCommandProvider { + ctx: Arc, +} +impl ShellCommandProvider { + fn new(ctx: Arc) -> Self { + ctx.log_info("Shell Command created"); + ShellCommandProvider{ + ctx, + } + } + + extern "C" fn call_execute_command(handle: *mut c_void, command_line: *const c_char, _out_stream: *mut FILE, _error_stream: *mut FILE) -> bool { + if handle.is_null() || command_line.is_null() { + return false; + } + unsafe { + println!("call_execute_command"); + let obj = &mut *(handle as *mut ShellCommandProvider); + let str_command_line = std::ffi::CStr::from_ptr(command_line).to_str().unwrap(); + obj.execute_command(str_command_line); + } + true + } + + fn execute_command(&mut self, command_line: &str) { + self.ctx.log_info(format!("Execute command: {}", command_line).as_str()); + } +} + +struct ShellCommandActivator { + ctx: Arc, + //log_helper: Box, + shell_command_provider: ShellCommandProvider, + registration: Option, +} + +impl BundleActivator for ShellCommandActivator { + fn new(ctx: Arc) -> Self { + let result = ShellCommandActivator { + ctx: ctx.clone(), + shell_command_provider: ShellCommandProvider::new(ctx.clone()), + //log_helper: log_helper_new(&*ctx, "ShellCommandBundle"), + registration: None, + }; + result + } + fn start(&mut self) -> Result<(), Error> { + let registration = self.ctx.register_service() + .with_service( celix_shell_command_t{ + handle: &mut self.shell_command_provider as *mut ShellCommandProvider as *mut c_void, + executeCommand: Some(ShellCommandProvider::call_execute_command), + }) + .with_service_name("celix_shell_command") + .with_property("command.name", "exe_in_rust") + .with_property("command.description", "Simple command written in Rust") + .build()?; + self.registration = Some(registration); + self.ctx.log_info("Rust Shell Command started"); + Ok(()) + } + + fn stop(&mut self) -> Result<(), Error> { + self.registration = None; + self.ctx.log_info("Rust Shell Command stopped"); + Ok(()) + } +} + +celix::generate_bundle_activator!(ShellCommandActivator); From dd13817198a35c91ce6f3604fa98d0c5892d5b8c Mon Sep 17 00:00:00 2001 From: Pepijn Noltes Date: Tue, 22 Aug 2023 20:53:49 +0200 Subject: [PATCH 07/21] #599: Refactor rust log helper --- .../rust/celix/src/bundle_context.rs | 4 +- misc/experimental/rust/celix/src/lib.rs | 1 - .../experimental/rust/celix/src/log_helper.rs | 84 ++++++++----------- .../rust/shell_command_bundle/src/lib.rs | 68 +++++++++++---- 4 files changed, 91 insertions(+), 66 deletions(-) diff --git a/misc/experimental/rust/celix/src/bundle_context.rs b/misc/experimental/rust/celix/src/bundle_context.rs index 5ff380a43..5d2841d83 100644 --- a/misc/experimental/rust/celix/src/bundle_context.rs +++ b/misc/experimental/rust/celix/src/bundle_context.rs @@ -40,7 +40,7 @@ use super::LogLevel; pub struct ServiceRegistration { service_id: i64, weak_ctx: Weak, - boxed_svc: Option>, + _boxed_svc: Option>, // arc_svc: Option>, } @@ -194,7 +194,7 @@ impl ServiceRegistrationBuilder<'_> { Ok(ServiceRegistration { service_id, weak_ctx: self.ctx.get_self().clone(), - boxed_svc: self.boxed_svc.take(), //to ensure that a possible box instance is not dropped + _boxed_svc: self.boxed_svc.take(), //to ensure that a possible box instance is not dropped // arc_svc: self.arc_svc.take(), //to ensure that a possible arc instance is not dropped }) } else { diff --git a/misc/experimental/rust/celix/src/lib.rs b/misc/experimental/rust/celix/src/lib.rs index 9befdeb8e..b5d5dc579 100644 --- a/misc/experimental/rust/celix/src/lib.rs +++ b/misc/experimental/rust/celix/src/lib.rs @@ -51,4 +51,3 @@ pub use self::bundle_activator::BundleActivator as BundleActivator; 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 488c6277a..2af5656c0 100644 --- a/misc/experimental/rust/celix/src/log_helper.rs +++ b/misc/experimental/rust/celix/src/log_helper.rs @@ -17,6 +17,8 @@ * under the License. */ +use std::sync::Arc; + use super::LogLevel; use super::BundleContext; @@ -24,71 +26,32 @@ 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 trait LogHelper { - fn log(&self, level: LogLevel, message: &str); - - fn trace(&self, message: &str) { - self.log(LogLevel::Trace, message); - } - - fn debug(&self, message: &str) { - self.log(LogLevel::Debug, message); - } - - fn info(&self, message: &str) { - self.log(LogLevel::Info, message); - } - - fn warning(&self, message: &str) { - self.log(LogLevel::Warning, message); - } - - fn error(&self, message: &str) { - self.log(LogLevel::Error, message); - } - - fn fatal(&self, message: &str) { - self.log(LogLevel::Fatal, message); - } -} - -struct LogHelperImpl { +pub struct LogHelper { celix_log_helper: *mut celix_log_helper_t, } -impl LogHelperImpl { - pub fn new(ctx: &dyn BundleContext, name: &str) -> Self { +impl LogHelper { + pub fn new(ctx: Arc, name: &str) -> Self { unsafe { let result = std::ffi::CString::new(name); match result { Ok(c_str) => { - LogHelperImpl { + LogHelper { 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 { + LogHelper { 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) { + pub fn log(&self, level: LogLevel, message: &str) { unsafe { let result = std::ffi::CString::new(message); match result { @@ -101,8 +64,35 @@ impl LogHelper for LogHelperImpl { } } } + 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 warning(&self, message: &str) { + self.log(LogLevel::Warning, message); + } + + pub fn error(&self, message: &str) { + self.log(LogLevel::Error, message); + } + + pub fn fatal(&self, message: &str) { + self.log(LogLevel::Fatal, message); + } } -pub fn log_helper_new(ctx: &dyn BundleContext, name: &str) -> Box { - Box::new(LogHelperImpl::new(ctx, name)) +impl Drop for LogHelper { + fn drop(&mut self) { + unsafe { + celix_logHelper_destroy(self.celix_log_helper); + } + } } diff --git a/misc/experimental/rust/shell_command_bundle/src/lib.rs b/misc/experimental/rust/shell_command_bundle/src/lib.rs index cc9b83f9f..1ed3b04d6 100644 --- a/misc/experimental/rust/shell_command_bundle/src/lib.rs +++ b/misc/experimental/rust/shell_command_bundle/src/lib.rs @@ -31,18 +31,15 @@ use celix::Error; use celix_bindings::celix_shell_command_t; use celix_bindings::FILE; -//temporary, should be moved in a separate API crate -// trait RustShellCommand { -// fn execute_command(&mut self, command_line: &str, command_args: Vec<&str>) -> Result<(), Error>; -// } -struct ShellCommandProvider { +struct CShellCommandImpl { ctx: Arc, } -impl ShellCommandProvider { + +impl CShellCommandImpl { fn new(ctx: Arc) -> Self { ctx.log_info("Shell Command created"); - ShellCommandProvider{ + CShellCommandImpl { ctx, } } @@ -53,7 +50,7 @@ impl ShellCommandProvider { } unsafe { println!("call_execute_command"); - let obj = &mut *(handle as *mut ShellCommandProvider); + let obj = &mut *(handle as *mut CShellCommandImpl); let str_command_line = std::ffi::CStr::from_ptr(command_line).to_str().unwrap(); obj.execute_command(str_command_line); } @@ -65,40 +62,79 @@ impl ShellCommandProvider { } } +//temporary, should be moved in a separate API crate +trait RustShellCommand { + fn execute_command(&mut self, command_line: &str) -> Result<(), Error>; +} + +struct RustShellCommandImpl { + ctx: Arc, +} + +impl RustShellCommandImpl { + fn new(ctx: Arc) -> Self { + ctx.log_info("Rust Shell Command created"); + RustShellCommandImpl { + ctx, + } + } +} + +impl RustShellCommand for RustShellCommandImpl { + fn execute_command(&mut self, command_line: &str) -> Result<(), Error> { + self.ctx.log_info(format!("Execute command: {}.", command_line).as_str()); + Ok(()) + } +} + struct ShellCommandActivator { ctx: Arc, //log_helper: Box, - shell_command_provider: ShellCommandProvider, - registration: Option, + shell_command_provider: CShellCommandImpl, + c_registration: Option, + rust_registration: Option, } impl BundleActivator for ShellCommandActivator { fn new(ctx: Arc) -> Self { let result = ShellCommandActivator { ctx: ctx.clone(), - shell_command_provider: ShellCommandProvider::new(ctx.clone()), + shell_command_provider: CShellCommandImpl::new(ctx.clone()), //log_helper: log_helper_new(&*ctx, "ShellCommandBundle"), - registration: None, + c_registration: None, + rust_registration: None, }; result } fn start(&mut self) -> Result<(), Error> { let registration = self.ctx.register_service() .with_service( celix_shell_command_t{ - handle: &mut self.shell_command_provider as *mut ShellCommandProvider as *mut c_void, - executeCommand: Some(ShellCommandProvider::call_execute_command), + handle: &mut self.shell_command_provider as *mut CShellCommandImpl as *mut c_void, + executeCommand: Some(CShellCommandImpl::call_execute_command), }) .with_service_name("celix_shell_command") .with_property("command.name", "exe_in_rust") .with_property("command.description", "Simple command written in Rust") .build()?; - self.registration = Some(registration); + self.c_registration = Some(registration); + self.ctx.log_info("C Shell Command registered"); + + let rust_shell_command = Box::new(RustShellCommandImpl::new(self.ctx.clone())); + let registration = self.ctx.register_service() + //maybe make svc types more explicit, e.g.with type parameters + .with_service(rust_shell_command as Box) + .with_property("command.name", "exe_in_rust") + .with_property("command.description", "Simple command written in Rust") + .build()?; + self.rust_registration = Some(registration); + self.ctx.log_info("Rust Shell Command started"); Ok(()) } fn stop(&mut self) -> Result<(), Error> { - self.registration = None; + self.rust_registration = None; + self.c_registration = None; self.ctx.log_info("Rust Shell Command stopped"); Ok(()) } From 99717a68faaea5ec853018e5992cbc1d2f9397d5 Mon Sep 17 00:00:00 2001 From: Pepijn Noltes Date: Wed, 23 Aug 2023 15:18:21 +0200 Subject: [PATCH 08/21] Add registration of rust trait --- misc/experimental/rust/Cargo.toml | 1 + .../rust/celix/src/bundle_activator.rs | 10 +- .../rust/celix/src/bundle_context.rs | 128 +++++++++--------- misc/experimental/rust/celix/src/errno.rs | 1 - misc/experimental/rust/celix/src/lib.rs | 18 +-- .../experimental/rust/celix/src/log_helper.rs | 31 +++-- misc/experimental/rust/celix/src/log_level.rs | 12 +- .../rust/celix_bindings/src/lib.rs | 9 +- .../rust/hello_world_activator/src/lib.rs | 4 +- .../rust/rust_shell_api/Cargo.toml | 28 ++++ .../rust/rust_shell_api/src/lib.rs | 29 ++++ .../rust/shell_command_bundle/Cargo.toml | 1 + .../rust/shell_command_bundle/src/lib.rs | 52 ++++--- 13 files changed, 208 insertions(+), 116 deletions(-) create mode 100644 misc/experimental/rust/rust_shell_api/Cargo.toml create mode 100644 misc/experimental/rust/rust_shell_api/src/lib.rs diff --git a/misc/experimental/rust/Cargo.toml b/misc/experimental/rust/Cargo.toml index 95f253d0a..9dc3d5140 100644 --- a/misc/experimental/rust/Cargo.toml +++ b/misc/experimental/rust/Cargo.toml @@ -20,6 +20,7 @@ members = [ "celix_bindings", "celix", "hello_world_activator", + "rust_shell_api", "shell_command_bundle", #"rust_shell_tui", ] diff --git a/misc/experimental/rust/celix/src/bundle_activator.rs b/misc/experimental/rust/celix/src/bundle_activator.rs index 11fa22a3e..a54ad5ea9 100644 --- a/misc/experimental/rust/celix/src/bundle_activator.rs +++ b/misc/experimental/rust/celix/src/bundle_activator.rs @@ -24,8 +24,14 @@ use super::Error; pub trait BundleActivator { fn new(ctx: Arc) -> Self; - fn start(&mut self) -> Result<(), Error> { /* Default implementation */ Ok(())} - fn stop(&mut self) -> Result<(), Error> { /* Default implementation */ Ok(())} + fn start(&mut self) -> Result<(), Error> { + /* Default implementation */ + Ok(()) + } + fn stop(&mut self) -> Result<(), Error> { + /* Default implementation */ + Ok(()) + } } #[macro_export] diff --git a/misc/experimental/rust/celix/src/bundle_context.rs b/misc/experimental/rust/celix/src/bundle_context.rs index 5d2841d83..88fc4ed6d 100644 --- a/misc/experimental/rust/celix/src/bundle_context.rs +++ b/misc/experimental/rust/celix/src/bundle_context.rs @@ -17,21 +17,22 @@ * under the License. */ -use std::ptr::null_mut; -use std::ffi::c_void; -use std::collections::HashMap; -use std::sync::Arc; -use std::sync::Weak; use std::any::type_name; use std::any::Any; +use std::collections::HashMap; +use std::ffi::c_void; +use std::ops::DerefMut; +use std::ptr::null_mut; +use std::sync::Arc; use std::sync::Mutex; +use std::sync::Weak; -use celix_bindings::celix_bundle_context_t; use celix_bindings::celix_bundleContext_log; -use celix_bindings::celix_properties_create; -use celix_bindings::celix_properties_set; use celix_bindings::celix_bundleContext_registerServiceWithOptions; use celix_bindings::celix_bundleContext_unregisterService; +use celix_bindings::celix_bundle_context_t; +use celix_bindings::celix_properties_create; +use celix_bindings::celix_properties_set; use celix_bindings::celix_service_registration_options_t; use super::Error; @@ -41,7 +42,6 @@ pub struct ServiceRegistration { service_id: i64, weak_ctx: Weak, _boxed_svc: Option>, - // arc_svc: Option>, } impl Drop for ServiceRegistration { @@ -57,7 +57,6 @@ impl Drop for ServiceRegistration { pub struct ServiceRegistrationBuilder<'a> { ctx: &'a BundleContextImpl, boxed_svc: Option>, - // _arc_svc: Option>, unmanaged_svc: *mut c_void, service_name: String, service_version: String, @@ -65,11 +64,10 @@ pub struct ServiceRegistrationBuilder<'a> { } impl ServiceRegistrationBuilder<'_> { - fn new<'a>(ctx: &'a BundleContextImpl) -> ServiceRegistrationBuilder<'a> { + fn new(ctx: &BundleContextImpl) -> ServiceRegistrationBuilder { ServiceRegistrationBuilder { ctx, boxed_svc: None, - //arc_svc: None, unmanaged_svc: null_mut(), service_name: "".to_string(), service_version: "".to_string(), @@ -82,41 +80,29 @@ impl ServiceRegistrationBuilder<'_> { self } - fn with_type_name_as_service_name(&mut self) -> &mut Self { + fn with_service_name_if_not_set(&mut self, name: &str) -> &mut Self { if self.service_name.is_empty() { - self.service_name = type_name::().to_string(); + self.service_name = name.to_string(); } self } - pub fn with_service(&mut self, instance: I) -> &mut Self { - self.boxed_svc = Some(Box::new(instance)); - //self.arc_svc = None; + pub fn with_service(&mut self, svc: I) -> &mut Self { + self.boxed_svc = Some(Box::new(svc)); self.unmanaged_svc = null_mut(); - self.with_type_name_as_service_name::() + self.with_service_name_if_not_set(type_name::()) } - //TODO check if dyn is needed (e.g. a trait object is needed) - pub fn with_boxed_service(&mut self, instance: Box) -> &mut Self { - self.boxed_svc = Some(instance); - //self.arc_svc = None; + pub fn with_boxed_service(&mut self, svc: Box) -> &mut Self { + self.boxed_svc = Some(Box::new(svc)); self.unmanaged_svc = null_mut(); - self.with_type_name_as_service_name::() + self.with_service_name_if_not_set(type_name::()) } - //TODO check if dyn is needed (e.g. a trait object is needed) - // pub fn with_arc_instance(&mut self, instance: Arc) -> &mut Self { - // self.boxed_svc = None; - // self.arc_svc = Some(instance); - // self.unmanaged_svc = null_mut(); - // self.with_type_name_as_service_name::() - // } - - pub fn with_unmanaged_service(&mut self, instance: *mut I) -> &mut Self { + pub fn with_unmanaged_service(&mut self, svc: *mut I) -> &mut Self { self.boxed_svc = None; - //self.arc_svc = None; - self.unmanaged_svc = instance as *mut c_void; - self.with_type_name_as_service_name::() + self.unmanaged_svc = svc as *mut c_void; + self.with_service_name_if_not_set(type_name::()) } pub fn with_version(&mut self, version: &str) -> &mut Self { @@ -130,18 +116,21 @@ impl ServiceRegistrationBuilder<'_> { } pub fn with_property(&mut self, key: &str, value: &str) -> &mut Self { - self.service_properties.insert(key.to_string(), value.to_string()); + self.service_properties + .insert(key.to_string(), value.to_string()); self } fn validate(&self) -> Result<(), Error> { let mut valid = true; if self.service_name.is_empty() { - self.ctx.log_error("Cannot register service. Service name is empty"); + self.ctx + .log_error("Cannot register service. Service name is empty"); valid = false; } if self.boxed_svc.is_none() && /*self.arc_svc.is_none() &&*/ self.unmanaged_svc.is_null() { - self.ctx.log_error("Cannot register service. No instance provided"); + self.ctx + .log_error("Cannot register service. No instance provided"); valid = false; } match valid { @@ -155,47 +144,45 @@ impl ServiceRegistrationBuilder<'_> { let any_svc: &mut dyn Any = boxed_svc.as_mut(); let boxed_svc_ptr = any_svc as *mut dyn Any; //note box still owns the instance boxed_svc_ptr as *mut c_void - // } else if let Some(arc_svc) = self.arc_svc.as_mut() { - // let any_svc: &mut dyn Any = arc_svc.as_mut(); - // let arc_svc_ptr = arc_svc as *mut dyn Any; //note arc still owns the instance - // arc_svc_ptr as *mut c_void } else if self.unmanaged_svc.is_null() { panic!("Cannot get c_svc. No instance provided"); } else { - self.unmanaged_svc as *mut c_void + self.unmanaged_svc } } - unsafe fn build_unsafe(&mut self) -> Result { + unsafe fn build_unsafe(&mut self, svc_ptr: *mut c_void) -> Result { let c_service_name = std::ffi::CString::new(self.service_name.as_str()).unwrap(); let c_service_version = std::ffi::CString::new(self.service_version.as_str()).unwrap(); let c_service_properties = celix_properties_create(); - let c_service = self.get_c_svc(); for (key, value) in self.service_properties.iter() { let c_key = std::ffi::CString::new(key.as_str()).unwrap(); let c_value = std::ffi::CString::new(value.as_str()).unwrap(); celix_properties_set(c_service_properties, c_key.as_ptr(), c_value.as_ptr()); } let opts = celix_service_registration_options_t { - svc: c_service, + svc: svc_ptr, factory: null_mut(), serviceName: c_service_name.as_ptr() as *const i8, properties: c_service_properties, serviceLanguage: null_mut(), - serviceVersion: if self.service_version.is_empty() { null_mut() } else { c_service_version.as_ptr() as *const i8}, + serviceVersion: if self.service_version.is_empty() { + null_mut() + } else { + c_service_version.as_ptr() as *const i8 + }, asyncData: null_mut(), asyncCallback: None, }; - let service_id: i64 = celix_bundleContext_registerServiceWithOptions( - self.ctx.get_c_bundle_context(), - &opts); + let service_id: i64 = + celix_bundleContext_registerServiceWithOptions(self.ctx.get_c_bundle_context(), &opts); if service_id >= 0 { Ok(ServiceRegistration { service_id, weak_ctx: self.ctx.get_self().clone(), _boxed_svc: self.boxed_svc.take(), //to ensure that a possible box instance is not dropped - // arc_svc: self.arc_svc.take(), //to ensure that a possible arc instance is not dropped + // arc_svc: self.arc_svc.take(), //to ensure that a possible arc instance is not dropped }) } else { Err(Error::BundleException) @@ -204,9 +191,10 @@ impl ServiceRegistrationBuilder<'_> { pub fn build(&mut self) -> Result { self.validate()?; + let svc_ptr = self.get_c_svc(); unsafe { //TODO make unsafe part smaller (if possible) - self.build_unsafe() + self.build_unsafe(svc_ptr) } } } @@ -233,7 +221,7 @@ pub trait BundleContext { struct BundleContextImpl { c_bundle_context: *mut celix_bundle_context_t, - weak_self : Mutex>>, + weak_self: Mutex>>, } impl BundleContextImpl { @@ -267,7 +255,11 @@ impl BundleContextImpl { 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); + celix_bundleContext_log( + self.c_bundle_context, + level.into(), + c_str.as_ptr() as *const i8, + ); } Err(e) => { println!("Error creating CString: {}", e); @@ -282,19 +274,33 @@ impl BundleContext for BundleContextImpl { self.c_bundle_context } - fn log(&self, level: LogLevel, message: &str) { self.log_to_c(level, message); } + 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_trace(&self, message: &str) { + self.log(LogLevel::Trace, message); + } - fn log_debug(&self, message: &str) { self.log(LogLevel::Debug, 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_info(&self, message: &str) { + self.log(LogLevel::Info, message); + } - fn log_warning(&self, message: &str) { self.log(LogLevel::Warning, 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_error(&self, message: &str) { + self.log(LogLevel::Error, message); + } - fn log_fatal(&self, message: &str){ self.log(LogLevel::Fatal, message); } + fn log_fatal(&self, message: &str) { + self.log(LogLevel::Fatal, message); + } fn register_service(&self) -> ServiceRegistrationBuilder { ServiceRegistrationBuilder::new(self) diff --git a/misc/experimental/rust/celix/src/errno.rs b/misc/experimental/rust/celix/src/errno.rs index a8037866d..af23d2cab 100644 --- a/misc/experimental/rust/celix/src/errno.rs +++ b/misc/experimental/rust/celix/src/errno.rs @@ -25,7 +25,6 @@ pub const CELIX_SUCCESS: celix_status_t = celix_bindings::CELIX_SUCCESS as celix //these are defined with literal values. pub const BUNDLE_EXCEPTION: celix_status_t = 70001; - pub enum Error { BundleException, CelixStatusError(celix_status_t), // Represent not explicitly mapped celix_status_t values diff --git a/misc/experimental/rust/celix/src/lib.rs b/misc/experimental/rust/celix/src/lib.rs index b5d5dc579..b30f995ef 100644 --- a/misc/experimental/rust/celix/src/lib.rs +++ b/misc/experimental/rust/celix/src/lib.rs @@ -25,29 +25,29 @@ extern crate celix_bindings; // 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; + pub use celix_bindings::celix_status_t as CStatus; } mod errno; // Re-export errno types in the public API. -pub use self::errno::CELIX_SUCCESS as CELIX_SUCCESS; -pub use self::errno::Error as Error; +pub use self::errno::Error; +pub use self::errno::CELIX_SUCCESS; mod log_level; // Re-export log level types in the public API. -pub use self::log_level::LogLevel as LogLevel; +pub use self::log_level::LogLevel; mod bundle_context; // Re-export bundle context types in the public API. -pub use self::bundle_context::BundleContext as BundleContext; -pub use self::bundle_context::ServiceRegistration as ServiceRegistration; -pub use self::bundle_context::bundle_context_new as bundle_context_new; +pub use self::bundle_context::bundle_context_new; +pub use self::bundle_context::BundleContext; +pub use self::bundle_context::ServiceRegistration; mod bundle_activator; // Re-export bundle activator types in the public API. -pub use self::bundle_activator::BundleActivator as BundleActivator; +pub use self::bundle_activator::BundleActivator; 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::LogHelper; diff --git a/misc/experimental/rust/celix/src/log_helper.rs b/misc/experimental/rust/celix/src/log_helper.rs index 2af5656c0..5c681024d 100644 --- a/misc/experimental/rust/celix/src/log_helper.rs +++ b/misc/experimental/rust/celix/src/log_helper.rs @@ -19,13 +19,13 @@ use std::sync::Arc; -use super::LogLevel; use super::BundleContext; +use super::LogLevel; -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; +use celix_bindings::celix_log_helper_t; pub struct LogHelper { celix_log_helper: *mut celix_log_helper_t, } @@ -35,16 +35,23 @@ impl LogHelper { unsafe { let result = std::ffi::CString::new(name); match result { - Ok(c_str) => { - LogHelper { - celix_log_helper: celix_logHelper_create(ctx.get_c_bundle_context(), c_str.as_ptr() as *const i8), - } - } + Ok(c_str) => LogHelper { + 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)); + ctx.log_error(&format!( + "Error creating CString: {}. Using \"error\" as log name", + e + )); let c_str = std::ffi::CString::new("error").unwrap(); LogHelper { - celix_log_helper: celix_logHelper_create(ctx.get_c_bundle_context(), c_str.as_ptr() as *const i8), + celix_log_helper: celix_logHelper_create( + ctx.get_c_bundle_context(), + c_str.as_ptr() as *const i8, + ), } } } @@ -56,7 +63,11 @@ impl LogHelper { 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); + celix_logHelper_log( + self.celix_log_helper, + level.into(), + c_str.as_ptr() as *const i8, + ); } Err(e) => { println!("Error creating CString: {}", e); diff --git a/misc/experimental/rust/celix/src/log_level.rs b/misc/experimental/rust/celix/src/log_level.rs index bc9b5e489..5beab988d 100644 --- a/misc/experimental/rust/celix/src/log_level.rs +++ b/misc/experimental/rust/celix/src/log_level.rs @@ -17,14 +17,14 @@ * under the License. */ -use celix_bindings::celix_log_level_e; -use celix_bindings::celix_log_level_CELIX_LOG_LEVEL_TRACE as CELIX_LOG_LEVEL_TRACE; use celix_bindings::celix_log_level_CELIX_LOG_LEVEL_DEBUG as CELIX_LOG_LEVEL_DEBUG; -use celix_bindings::celix_log_level_CELIX_LOG_LEVEL_INFO as CELIX_LOG_LEVEL_INFO; -use celix_bindings::celix_log_level_CELIX_LOG_LEVEL_WARNING as CELIX_LOG_LEVEL_WARNING; +use celix_bindings::celix_log_level_CELIX_LOG_LEVEL_DISABLED as CELIX_LOG_LEVEL_DISABLED; use celix_bindings::celix_log_level_CELIX_LOG_LEVEL_ERROR as CELIX_LOG_LEVEL_ERROR; use celix_bindings::celix_log_level_CELIX_LOG_LEVEL_FATAL as CELIX_LOG_LEVEL_FATAL; -use celix_bindings::celix_log_level_CELIX_LOG_LEVEL_DISABLED as CELIX_LOG_LEVEL_DISABLED; +use celix_bindings::celix_log_level_CELIX_LOG_LEVEL_INFO as CELIX_LOG_LEVEL_INFO; +use celix_bindings::celix_log_level_CELIX_LOG_LEVEL_TRACE as CELIX_LOG_LEVEL_TRACE; +use celix_bindings::celix_log_level_CELIX_LOG_LEVEL_WARNING as CELIX_LOG_LEVEL_WARNING; +use celix_bindings::celix_log_level_e; pub enum LogLevel { Trace, @@ -33,7 +33,7 @@ pub enum LogLevel { Warning, Error, Fatal, - Disabled + Disabled, } impl From for LogLevel { fn from(level: celix_log_level_e) -> Self { diff --git a/misc/experimental/rust/celix_bindings/src/lib.rs b/misc/experimental/rust/celix_bindings/src/lib.rs index 64fdba67b..0fd4dc707 100644 --- a/misc/experimental/rust/celix_bindings/src/lib.rs +++ b/misc/experimental/rust/celix_bindings/src/lib.rs @@ -17,8 +17,13 @@ * under the License. */ -#[allow(non_camel_case_types, non_snake_case, non_upper_case_globals, dead_code)] +#[allow( + non_camel_case_types, + non_snake_case, + non_upper_case_globals, + dead_code +)] mod bindings { - include!(concat!(env!("OUT_DIR"), "/celix_bindings.rs")); + include!(concat!(env!("OUT_DIR"), "/celix_bindings.rs")); } pub use bindings::*; diff --git a/misc/experimental/rust/hello_world_activator/src/lib.rs b/misc/experimental/rust/hello_world_activator/src/lib.rs index 93c676efc..c9e6e861f 100644 --- a/misc/experimental/rust/hello_world_activator/src/lib.rs +++ b/misc/experimental/rust/hello_world_activator/src/lib.rs @@ -32,9 +32,7 @@ struct HelloWorldBundle { impl BundleActivator for HelloWorldBundle { fn new(ctx: Arc) -> Self { ctx.log_info("Hello World Bundle Activator created"); - HelloWorldBundle{ - ctx, - } + HelloWorldBundle { ctx } } fn start(&mut self) -> Result<(), Error> { diff --git a/misc/experimental/rust/rust_shell_api/Cargo.toml b/misc/experimental/rust/rust_shell_api/Cargo.toml new file mode 100644 index 000000000..71c4d41b6 --- /dev/null +++ b/misc/experimental/rust/rust_shell_api/Cargo.toml @@ -0,0 +1,28 @@ +# 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. + +[package] +name = "rust_shell_api" +version = "0.0.1" + +[dependencies] +celix = { path = "../celix" } + +[lib] +name = "rust_shell_api" +path = "src/lib.rs" +crate-type = ["rlib"] diff --git a/misc/experimental/rust/rust_shell_api/src/lib.rs b/misc/experimental/rust/rust_shell_api/src/lib.rs new file mode 100644 index 000000000..79a11de2f --- /dev/null +++ b/misc/experimental/rust/rust_shell_api/src/lib.rs @@ -0,0 +1,29 @@ +/* + * 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. + */ + +extern crate celix; + +use celix::Error; +pub const COMMAND_NAME: &str = "command.name"; +pub const COMMAND_USAGE: &str = "command.usage"; +pub const COMMAND_DESCRIPTION: &str = "command.description"; + +pub trait RustShellCommand { + fn execute_command(&mut self, command_line: &str) -> Result<(), Error>; +} diff --git a/misc/experimental/rust/shell_command_bundle/Cargo.toml b/misc/experimental/rust/shell_command_bundle/Cargo.toml index 1773c986a..0c11c1805 100644 --- a/misc/experimental/rust/shell_command_bundle/Cargo.toml +++ b/misc/experimental/rust/shell_command_bundle/Cargo.toml @@ -22,6 +22,7 @@ version = "0.0.1" [dependencies] celix_bindings = { path = "../celix_bindings" } celix = { path = "../celix" } +rust_shell_api = { path = "../rust_shell_api" } [lib] name = "rust_shell_command_activator" diff --git a/misc/experimental/rust/shell_command_bundle/src/lib.rs b/misc/experimental/rust/shell_command_bundle/src/lib.rs index 1ed3b04d6..0ab73f788 100644 --- a/misc/experimental/rust/shell_command_bundle/src/lib.rs +++ b/misc/experimental/rust/shell_command_bundle/src/lib.rs @@ -17,21 +17,22 @@ * under the License. */ -extern crate celix_bindings; extern crate celix; +extern crate celix_bindings; +extern crate rust_shell_api; -use std::sync::Arc; -use std::ffi::c_void; use std::ffi::c_char; +use std::ffi::c_void; +use std::sync::{Arc, Mutex}; use celix::BundleActivator; use celix::BundleContext; use celix::Error; +use rust_shell_api::RustShellCommand; use celix_bindings::celix_shell_command_t; use celix_bindings::FILE; - struct CShellCommandImpl { ctx: Arc, } @@ -39,12 +40,15 @@ struct CShellCommandImpl { impl CShellCommandImpl { fn new(ctx: Arc) -> Self { ctx.log_info("Shell Command created"); - CShellCommandImpl { - ctx, - } + CShellCommandImpl { ctx } } - extern "C" fn call_execute_command(handle: *mut c_void, command_line: *const c_char, _out_stream: *mut FILE, _error_stream: *mut FILE) -> bool { + extern "C" fn call_execute_command( + handle: *mut c_void, + command_line: *const c_char, + _out_stream: *mut FILE, + _error_stream: *mut FILE, + ) -> bool { if handle.is_null() || command_line.is_null() { return false; } @@ -58,14 +62,12 @@ impl CShellCommandImpl { } fn execute_command(&mut self, command_line: &str) { - self.ctx.log_info(format!("Execute command: {}", command_line).as_str()); + self.ctx + .log_info(format!("Execute command: {}", command_line).as_str()); } } //temporary, should be moved in a separate API crate -trait RustShellCommand { - fn execute_command(&mut self, command_line: &str) -> Result<(), Error>; -} struct RustShellCommandImpl { ctx: Arc, @@ -74,15 +76,14 @@ struct RustShellCommandImpl { impl RustShellCommandImpl { fn new(ctx: Arc) -> Self { ctx.log_info("Rust Shell Command created"); - RustShellCommandImpl { - ctx, - } + RustShellCommandImpl { ctx } } } impl RustShellCommand for RustShellCommandImpl { fn execute_command(&mut self, command_line: &str) -> Result<(), Error> { - self.ctx.log_info(format!("Execute command: {}.", command_line).as_str()); + self.ctx + .log_info(format!("Execute command: {}.", command_line).as_str()); Ok(()) } } @@ -93,6 +94,7 @@ struct ShellCommandActivator { shell_command_provider: CShellCommandImpl, c_registration: Option, rust_registration: Option, + rust_registration2: Option, } impl BundleActivator for ShellCommandActivator { @@ -103,28 +105,33 @@ impl BundleActivator for ShellCommandActivator { //log_helper: log_helper_new(&*ctx, "ShellCommandBundle"), c_registration: None, rust_registration: None, + rust_registration2: None, }; result } fn start(&mut self) -> Result<(), Error> { + + //C service registered as direct type let registration = self.ctx.register_service() - .with_service( celix_shell_command_t{ + .with_service(celix_shell_command_t { handle: &mut self.shell_command_provider as *mut CShellCommandImpl as *mut c_void, executeCommand: Some(CShellCommandImpl::call_execute_command), - }) + }) .with_service_name("celix_shell_command") - .with_property("command.name", "exe_in_rust") + .with_property("command.name", "exe_c_command_in_rust") .with_property("command.description", "Simple command written in Rust") .build()?; self.c_registration = Some(registration); self.ctx.log_info("C Shell Command registered"); + //Rust service register using a Box with a trait let rust_shell_command = Box::new(RustShellCommandImpl::new(self.ctx.clone())); + let rust_shell_command = Box::::from(rust_shell_command); let registration = self.ctx.register_service() //maybe make svc types more explicit, e.g.with type parameters - .with_service(rust_shell_command as Box) - .with_property("command.name", "exe_in_rust") - .with_property("command.description", "Simple command written in Rust") + .with_boxed_service(rust_shell_command) + .with_property(rust_shell_api::COMMAND_NAME, "exe_rust_command") + .with_property(rust_shell_api::COMMAND_DESCRIPTION, "Simple command written in Rust") .build()?; self.rust_registration = Some(registration); @@ -133,6 +140,7 @@ impl BundleActivator for ShellCommandActivator { } fn stop(&mut self) -> Result<(), Error> { + self.rust_registration2 = None; self.rust_registration = None; self.c_registration = None; self.ctx.log_info("Rust Shell Command stopped"); From 3ef7b52989a202b5b7b2117fcfede58a57716a70 Mon Sep 17 00:00:00 2001 From: Pepijn Noltes Date: Fri, 25 Aug 2023 15:13:08 +0200 Subject: [PATCH 09/21] Add use_service poc for Rust experiment --- .../rust/celix/src/bundle_context.rs | 134 +++++++++++++++++- .../rust/rust_shell_api/src/lib.rs | 10 +- .../rust/shell_command_bundle/src/lib.rs | 133 ++++++++++++----- 3 files changed, 239 insertions(+), 38 deletions(-) diff --git a/misc/experimental/rust/celix/src/bundle_context.rs b/misc/experimental/rust/celix/src/bundle_context.rs index 88fc4ed6d..01022fa69 100644 --- a/misc/experimental/rust/celix/src/bundle_context.rs +++ b/misc/experimental/rust/celix/src/bundle_context.rs @@ -21,13 +21,16 @@ use std::any::type_name; use std::any::Any; use std::collections::HashMap; use std::ffi::c_void; -use std::ops::DerefMut; use std::ptr::null_mut; use std::sync::Arc; use std::sync::Mutex; use std::sync::Weak; use celix_bindings::celix_bundleContext_log; +use celix_bindings::celix_service_use_options_t; +use celix_bindings::celix_service_filter_options_t; +use celix_bindings::celix_bundleContext_useServicesWithOptions; +use celix_bindings::celix_bundleContext_useServiceWithOptions; use celix_bindings::celix_bundleContext_registerServiceWithOptions; use celix_bindings::celix_bundleContext_unregisterService; use celix_bindings::celix_bundle_context_t; @@ -193,12 +196,127 @@ impl ServiceRegistrationBuilder<'_> { self.validate()?; let svc_ptr = self.get_c_svc(); unsafe { - //TODO make unsafe part smaller (if possible) self.build_unsafe(svc_ptr) } } } +pub struct ServiceUseBuilder<'a> { + ctx: &'a BundleContextImpl, + many: bool, + service_name: String, + filter: String, + callback: Option>> +} + +impl ServiceUseBuilder<'_> { + fn new(ctx: &BundleContextImpl, many: bool) -> ServiceUseBuilder { + ServiceUseBuilder { + ctx, + many, + service_name: "".to_string(), + filter: "".to_string(), + callback: None, + } + } + + pub fn with_service(&mut self) -> &mut Self { + self.service_name = type_name::().to_string(); + self + } + + #[doc = " @brief Provide a callback which will be called when a service is available. T must be a Sized (non trait) type, due to the use of downcast_ref"] + pub fn with_callback(&mut self, closure: Box)-> &mut Self { + if self.service_name.is_empty() { + self.with_service::(); + } + + let any_closure = Box::new(move |any_svc: &dyn Any| { + if let Some(svc) = any_svc.downcast_ref::() { + closure(svc); + } + }); + + self.callback = Some(Box::new(any_closure)); + self + } + + #[doc = " @brief Provide a callback which will be called when a service is available, with a dyn Any argument. Note that this is useful for trait objects."] + pub fn with_any_callback(&mut self, closure: Box)-> &mut Self { + self.callback = Some(Box::new(closure)); //note double boxed + self + } + + pub fn with_service_name(&mut self, name: &str) -> &mut Self { + self.service_name = name.to_string(); + self + } + + pub fn with_filter(&mut self, filter: &str) -> &mut Self { + self.filter = filter.to_string(); + self + } + + fn validate(&self) -> Result<(), Error> { + if self.callback.is_none() || self.service_name.is_empty() { + return Err(Error::BundleException); + } + Ok(()) + } + + unsafe extern "C" fn use_service_c_callback(handle: *mut c_void, svc: *mut c_void) { + let boxed_fn = Box::from_raw(handle as *mut Box); + let any_svc_ptr = svc as *mut dyn Any; + let any_svc_ref = any_svc_ptr.as_ref().unwrap(); + boxed_fn(any_svc_ref); + } + + pub fn build(&mut self) -> Result { + self.validate()?; + + let c_service_name = std::ffi::CString::new(self.service_name.as_str()).unwrap(); + let c_filter = std::ffi::CString::new(self.filter.as_str()).unwrap(); + let c_service_name_ptr: *const i8 = c_service_name.as_ptr(); + + //Note filter is for now unused, introduce when updating to use of celix_bundleContext_useServiceWithOptions + let c_filter_ptr: *const i8 = if self.filter.is_empty() { null_mut()} else {c_filter.as_ptr() }; + + let boxed_fn = self.callback.take().unwrap(); + let fn_ptr = Box::into_raw(boxed_fn) as *mut c_void; + + + let opts = celix_service_use_options_t { + filter: celix_service_filter_options_t { + serviceName: c_service_name_ptr, + versionRange: null_mut(), + filter: c_filter_ptr, + serviceLanguage: null_mut(), + ignoreServiceLanguage: false, + }, + waitTimeoutInSeconds: 0.0, + callbackHandle: fn_ptr, + use_: Some(Self::use_service_c_callback), + useWithProperties: None, + useWithOwner: None, + flags: 0, + }; + + unsafe { + if self.many { + let count = celix_bundleContext_useServicesWithOptions(self.ctx.get_c_bundle_context(), &opts); + Ok(count as isize) + } else { + let called = celix_bundleContext_useServiceWithOptions(self.ctx.get_c_bundle_context(), &opts); + if called { + Ok(1) + } else { + Ok(0) + } + } + } + } +} + pub trait BundleContext { fn get_c_bundle_context(&self) -> *mut celix_bundle_context_t; @@ -217,6 +335,10 @@ pub trait BundleContext { fn log_fatal(&self, message: &str); fn register_service(&self) -> ServiceRegistrationBuilder; + + fn use_service(&self) -> ServiceUseBuilder; + + fn use_services(&self) -> ServiceUseBuilder; } struct BundleContextImpl { @@ -305,6 +427,14 @@ impl BundleContext for BundleContextImpl { fn register_service(&self) -> ServiceRegistrationBuilder { ServiceRegistrationBuilder::new(self) } + + fn use_service(&self) -> ServiceUseBuilder { + ServiceUseBuilder::new(self, false) + } + + fn use_services(&self) -> ServiceUseBuilder { + ServiceUseBuilder::new(self, true) + } } pub fn bundle_context_new(c_bundle_context: *mut celix_bundle_context_t) -> Arc { diff --git a/misc/experimental/rust/rust_shell_api/src/lib.rs b/misc/experimental/rust/rust_shell_api/src/lib.rs index 79a11de2f..0969f86c2 100644 --- a/misc/experimental/rust/rust_shell_api/src/lib.rs +++ b/misc/experimental/rust/rust_shell_api/src/lib.rs @@ -24,6 +24,12 @@ pub const COMMAND_NAME: &str = "command.name"; pub const COMMAND_USAGE: &str = "command.usage"; pub const COMMAND_DESCRIPTION: &str = "command.description"; -pub trait RustShellCommand { - fn execute_command(&mut self, command_line: &str) -> Result<(), Error>; +#[doc = "A trait to implement a Celix Shell Command"] +pub trait RustShellCommandTrait { + fn execute_command(&self, command_line: &str) -> Result<(), Error>; +} + +#[doc = "A struct to register a Rust Shell Command"] +pub struct RustShellCommandStruct { + pub execute_command: Box Result<(), Error>> } diff --git a/misc/experimental/rust/shell_command_bundle/src/lib.rs b/misc/experimental/rust/shell_command_bundle/src/lib.rs index 0ab73f788..50d2905f0 100644 --- a/misc/experimental/rust/shell_command_bundle/src/lib.rs +++ b/misc/experimental/rust/shell_command_bundle/src/lib.rs @@ -21,14 +21,15 @@ extern crate celix; extern crate celix_bindings; extern crate rust_shell_api; +use std::any::Any; use std::ffi::c_char; use std::ffi::c_void; -use std::sync::{Arc, Mutex}; +use std::sync::Arc; use celix::BundleActivator; use celix::BundleContext; use celix::Error; -use rust_shell_api::RustShellCommand; +use rust_shell_api::{RustShellCommandTrait, RustShellCommandStruct}; use celix_bindings::celix_shell_command_t; use celix_bindings::FILE; @@ -53,17 +54,18 @@ impl CShellCommandImpl { return false; } unsafe { - println!("call_execute_command"); let obj = &mut *(handle as *mut CShellCommandImpl); - let str_command_line = std::ffi::CStr::from_ptr(command_line).to_str().unwrap(); - obj.execute_command(str_command_line); + let str_command_line = std::ffi::CStr::from_ptr(command_line).to_str(); + if str_command_line.is_err() { + return false; + } + obj.execute_command(str_command_line.unwrap()); } true } fn execute_command(&mut self, command_line: &str) { - self.ctx - .log_info(format!("Execute command: {}", command_line).as_str()); + self.ctx.log_info(format!("Execute command: \"{}\"", command_line).as_str()); } } @@ -80,8 +82,8 @@ impl RustShellCommandImpl { } } -impl RustShellCommand for RustShellCommandImpl { - fn execute_command(&mut self, command_line: &str) -> Result<(), Error> { +impl RustShellCommandTrait for RustShellCommandImpl { + fn execute_command(&self, command_line: &str) -> Result<(), Error> { self.ctx .log_info(format!("Execute command: {}.", command_line).as_str()); Ok(()) @@ -92,26 +94,13 @@ struct ShellCommandActivator { ctx: Arc, //log_helper: Box, shell_command_provider: CShellCommandImpl, - c_registration: Option, - rust_registration: Option, - rust_registration2: Option, + registrations: Vec, } -impl BundleActivator for ShellCommandActivator { - fn new(ctx: Arc) -> Self { - let result = ShellCommandActivator { - ctx: ctx.clone(), - shell_command_provider: CShellCommandImpl::new(ctx.clone()), - //log_helper: log_helper_new(&*ctx, "ShellCommandBundle"), - c_registration: None, - rust_registration: None, - rust_registration2: None, - }; - result - } - fn start(&mut self) -> Result<(), Error> { +impl ShellCommandActivator { - //C service registered as direct type + fn register_services(&mut self) -> Result<(), Error> { + //Register C service registered as value let registration = self.ctx.register_service() .with_service(celix_shell_command_t { handle: &mut self.shell_command_provider as *mut CShellCommandImpl as *mut c_void, @@ -121,28 +110,104 @@ impl BundleActivator for ShellCommandActivator { .with_property("command.name", "exe_c_command_in_rust") .with_property("command.description", "Simple command written in Rust") .build()?; - self.c_registration = Some(registration); + self.registrations.push(registration); self.ctx.log_info("C Shell Command registered"); - //Rust service register using a Box with a trait + //Register Rust trait service register using a Box let rust_shell_command = Box::new(RustShellCommandImpl::new(self.ctx.clone())); - let rust_shell_command = Box::::from(rust_shell_command); + let rust_shell_command = Box::::from(rust_shell_command); let registration = self.ctx.register_service() //maybe make svc types more explicit, e.g.with type parameters .with_boxed_service(rust_shell_command) .with_property(rust_shell_api::COMMAND_NAME, "exe_rust_command") - .with_property(rust_shell_api::COMMAND_DESCRIPTION, "Simple command written in Rust") + .with_property(rust_shell_api::COMMAND_DESCRIPTION, "Simple command written in a Rust trait") + .build()?; + self.registrations.push(registration); + self.ctx.log_info("Rust trait Shell Command registered"); + + + //Register Rust struct service (with closures) as value + let cloned_ctx = self.ctx.clone(); + let rust_shell_command = RustShellCommandStruct { + execute_command: Box::new(move |command_line: &str| { + cloned_ctx.log_info(format!("Execute command: {}", command_line).as_str()); + Ok(()) + }), + }; + let registration = self.ctx.register_service() + .with_service(rust_shell_command) + .with_property("command.name", "exe_rust_command2") + .with_property("command.description", "Simple command written in a Rust struct using a Rust closure") .build()?; - self.rust_registration = Some(registration); + self.registrations.push(registration); + self.ctx.log_info("Rust struct Shell Command registered"); + Ok(()) + } + fn use_services(&mut self) -> Result<(), Error> { + //test using C service + + self.ctx.log_info("Use C service command service"); + let count = self.ctx.use_services() + .with_service_name("celix_shell_command") + .with_filter("(command.name=exe_c_command_in_rust)") + .with_callback(Box::new( |svc: &celix_shell_command_t| { + if let Some(exe_cmd) = svc.executeCommand { + let c_str = std::ffi::CString::new("test").unwrap(); + unsafe { + exe_cmd(svc.handle, c_str.as_ptr() as *const c_char, std::ptr::null_mut(), std::ptr::null_mut()); + } + } + })) + .build()?; + self.ctx.log_info(format!("Found {} celix_shell_command_t services", count).as_str()); + + //test using Rust trait service + self.ctx.log_info("Use Rust trait service command service"); + let count = self.ctx.use_services() + .with_service::() + .with_any_callback(Box::new( |svc: &dyn Any| { + let typed_svc = svc.downcast_ref::(); + if let Some(svc) = typed_svc { + let _ = svc.execute_command("test"); + } + })) + .build()?; + self.ctx.log_info(format!("Found {} RustShellCommandTrait services", count).as_str()); + + self.ctx.log_info("Use Rust struct service command service"); + let count = self.ctx.use_services() + .with_callback(Box::new( |svc: &RustShellCommandStruct| { + let exe_cmd = svc.execute_command.as_ref(); + let _ = exe_cmd("test"); + })) + .build()?; + self.ctx.log_info(format!("Found {} RustShellCommandStruct services", count).as_str()); + + self.ctx.log_info("Rust Shell Command started"); + Ok(()) + } +} + +impl BundleActivator for ShellCommandActivator { + fn new(ctx: Arc) -> Self { + let result = ShellCommandActivator { + ctx: ctx.clone(), + shell_command_provider: CShellCommandImpl::new(ctx.clone()), + //log_helper: log_helper_new(&*ctx, "ShellCommandBundle"), + registrations: Vec::new(), + }; + result + } + fn start(&mut self) -> Result<(), Error> { + self.register_services()?; + self.use_services()?; self.ctx.log_info("Rust Shell Command started"); Ok(()) } fn stop(&mut self) -> Result<(), Error> { - self.rust_registration2 = None; - self.rust_registration = None; - self.c_registration = None; + self.registrations.clear(); self.ctx.log_info("Rust Shell Command stopped"); Ok(()) } From b2e86574b52004a532c5d96468ac36252b36f954 Mon Sep 17 00:00:00 2001 From: Pepijn Noltes Date: Fri, 25 Aug 2023 15:33:50 +0200 Subject: [PATCH 10/21] #599: Remove BundleContext trait so that generic method are possible --- .../rust/celix/src/bundle_activator.rs | 2 +- .../rust/celix/src/bundle_context.rs | 96 ++++++------------- .../experimental/rust/celix/src/log_helper.rs | 2 +- .../rust/hello_world_activator/src/lib.rs | 4 +- .../rust/shell_command_bundle/src/lib.rs | 14 +-- 5 files changed, 42 insertions(+), 76 deletions(-) diff --git a/misc/experimental/rust/celix/src/bundle_activator.rs b/misc/experimental/rust/celix/src/bundle_activator.rs index a54ad5ea9..d3050bcea 100644 --- a/misc/experimental/rust/celix/src/bundle_activator.rs +++ b/misc/experimental/rust/celix/src/bundle_activator.rs @@ -23,7 +23,7 @@ use super::BundleContext; use super::Error; pub trait BundleActivator { - fn new(ctx: Arc) -> Self; + fn new(ctx: Arc) -> Self; fn start(&mut self) -> Result<(), Error> { /* Default implementation */ Ok(()) diff --git a/misc/experimental/rust/celix/src/bundle_context.rs b/misc/experimental/rust/celix/src/bundle_context.rs index 01022fa69..56ddc69aa 100644 --- a/misc/experimental/rust/celix/src/bundle_context.rs +++ b/misc/experimental/rust/celix/src/bundle_context.rs @@ -43,7 +43,7 @@ use super::LogLevel; pub struct ServiceRegistration { service_id: i64, - weak_ctx: Weak, + weak_ctx: Weak, _boxed_svc: Option>, } @@ -58,20 +58,18 @@ impl Drop for ServiceRegistration { } pub struct ServiceRegistrationBuilder<'a> { - ctx: &'a BundleContextImpl, + ctx: &'a BundleContext, boxed_svc: Option>, - unmanaged_svc: *mut c_void, service_name: String, service_version: String, service_properties: HashMap, } impl ServiceRegistrationBuilder<'_> { - fn new(ctx: &BundleContextImpl) -> ServiceRegistrationBuilder { + fn new(ctx: &BundleContext) -> ServiceRegistrationBuilder { ServiceRegistrationBuilder { ctx, boxed_svc: None, - unmanaged_svc: null_mut(), service_name: "".to_string(), service_version: "".to_string(), service_properties: HashMap::new(), @@ -92,22 +90,14 @@ impl ServiceRegistrationBuilder<'_> { pub fn with_service(&mut self, svc: I) -> &mut Self { self.boxed_svc = Some(Box::new(svc)); - self.unmanaged_svc = null_mut(); self.with_service_name_if_not_set(type_name::()) } pub fn with_boxed_service(&mut self, svc: Box) -> &mut Self { self.boxed_svc = Some(Box::new(svc)); - self.unmanaged_svc = null_mut(); self.with_service_name_if_not_set(type_name::()) } - pub fn with_unmanaged_service(&mut self, svc: *mut I) -> &mut Self { - self.boxed_svc = None; - self.unmanaged_svc = svc as *mut c_void; - self.with_service_name_if_not_set(type_name::()) - } - pub fn with_version(&mut self, version: &str) -> &mut Self { self.service_version = version.to_string(); self @@ -131,7 +121,7 @@ impl ServiceRegistrationBuilder<'_> { .log_error("Cannot register service. Service name is empty"); valid = false; } - if self.boxed_svc.is_none() && /*self.arc_svc.is_none() &&*/ self.unmanaged_svc.is_null() { + if self.boxed_svc.is_none() /*&& self.arc_svc.is_none() */ { self.ctx .log_error("Cannot register service. No instance provided"); valid = false; @@ -147,10 +137,8 @@ impl ServiceRegistrationBuilder<'_> { let any_svc: &mut dyn Any = boxed_svc.as_mut(); let boxed_svc_ptr = any_svc as *mut dyn Any; //note box still owns the instance boxed_svc_ptr as *mut c_void - } else if self.unmanaged_svc.is_null() { - panic!("Cannot get c_svc. No instance provided"); } else { - self.unmanaged_svc + null_mut() } } @@ -184,8 +172,7 @@ impl ServiceRegistrationBuilder<'_> { Ok(ServiceRegistration { service_id, weak_ctx: self.ctx.get_self().clone(), - _boxed_svc: self.boxed_svc.take(), //to ensure that a possible box instance is not dropped - // arc_svc: self.arc_svc.take(), //to ensure that a possible arc instance is not dropped + _boxed_svc: self.boxed_svc.take(), }) } else { Err(Error::BundleException) @@ -202,7 +189,7 @@ impl ServiceRegistrationBuilder<'_> { } pub struct ServiceUseBuilder<'a> { - ctx: &'a BundleContextImpl, + ctx: &'a BundleContext, many: bool, service_name: String, filter: String, @@ -210,7 +197,7 @@ pub struct ServiceUseBuilder<'a> { } impl ServiceUseBuilder<'_> { - fn new(ctx: &BundleContextImpl, many: bool) -> ServiceUseBuilder { + fn new(ctx: &BundleContext, many: bool) -> ServiceUseBuilder { ServiceUseBuilder { ctx, many, @@ -317,38 +304,14 @@ impl ServiceUseBuilder<'_> { } } -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); - - fn register_service(&self) -> ServiceRegistrationBuilder; - - fn use_service(&self) -> ServiceUseBuilder; - - fn use_services(&self) -> ServiceUseBuilder; -} - -struct BundleContextImpl { +pub struct BundleContext { c_bundle_context: *mut celix_bundle_context_t, - weak_self: Mutex>>, + weak_self: Mutex>>, } -impl BundleContextImpl { +impl BundleContext { fn new(c_bundle_context: *mut celix_bundle_context_t) -> Arc { - let ctx = Arc::new(BundleContextImpl { + let ctx = Arc::new(BundleContext { c_bundle_context, weak_self: Mutex::new(None), }); @@ -357,12 +320,12 @@ impl BundleContextImpl { ctx } - fn set_self(&self, weak_self: Weak) { + fn set_self(&self, weak_self: Weak) { let mut guard = self.weak_self.lock().unwrap(); *guard = Some(weak_self); } - fn get_self(&self) -> Weak { + fn get_self(&self) -> Weak { self.weak_self.lock().unwrap().clone().unwrap() } @@ -389,54 +352,55 @@ impl BundleContextImpl { } } } -} -impl BundleContext for BundleContextImpl { - fn get_c_bundle_context(&self) -> *mut celix_bundle_context_t { + pub fn get_c_bundle_context(&self) -> *mut celix_bundle_context_t { self.c_bundle_context } - fn log(&self, level: LogLevel, message: &str) { + pub fn log(&self, level: LogLevel, message: &str) { self.log_to_c(level, message); } - fn log_trace(&self, message: &str) { + pub fn log_trace(&self, message: &str) { self.log(LogLevel::Trace, message); } - fn log_debug(&self, message: &str) { + pub fn log_debug(&self, message: &str) { self.log(LogLevel::Debug, message); } - fn log_info(&self, message: &str) { + pub fn log_info(&self, message: &str) { self.log(LogLevel::Info, message); } - fn log_warning(&self, message: &str) { + pub fn log_warning(&self, message: &str) { self.log(LogLevel::Warning, message); } - fn log_error(&self, message: &str) { + pub fn log_error(&self, message: &str) { self.log(LogLevel::Error, message); } - fn log_fatal(&self, message: &str) { + pub fn log_fatal(&self, message: &str) { self.log(LogLevel::Fatal, message); } - fn register_service(&self) -> ServiceRegistrationBuilder { + //TODO make generic + pub fn register_service(&self) -> ServiceRegistrationBuilder { ServiceRegistrationBuilder::new(self) } - fn use_service(&self) -> ServiceUseBuilder { + //TODO make generic + pub fn use_service(&self) -> ServiceUseBuilder { ServiceUseBuilder::new(self, false) } - fn use_services(&self) -> ServiceUseBuilder { + //TODO make generic + pub fn use_services(&self) -> ServiceUseBuilder { ServiceUseBuilder::new(self, true) } } -pub fn bundle_context_new(c_bundle_context: *mut celix_bundle_context_t) -> Arc { - BundleContextImpl::new(c_bundle_context) +pub fn bundle_context_new(c_bundle_context: *mut celix_bundle_context_t) -> Arc { + BundleContext::new(c_bundle_context) } diff --git a/misc/experimental/rust/celix/src/log_helper.rs b/misc/experimental/rust/celix/src/log_helper.rs index 5c681024d..64099ba56 100644 --- a/misc/experimental/rust/celix/src/log_helper.rs +++ b/misc/experimental/rust/celix/src/log_helper.rs @@ -31,7 +31,7 @@ pub struct LogHelper { } impl LogHelper { - pub fn new(ctx: Arc, name: &str) -> Self { + pub fn new(ctx: Arc, name: &str) -> Self { unsafe { let result = std::ffi::CString::new(name); match result { diff --git a/misc/experimental/rust/hello_world_activator/src/lib.rs b/misc/experimental/rust/hello_world_activator/src/lib.rs index c9e6e861f..80d7b7208 100644 --- a/misc/experimental/rust/hello_world_activator/src/lib.rs +++ b/misc/experimental/rust/hello_world_activator/src/lib.rs @@ -26,11 +26,11 @@ use celix::BundleContext; use celix::Error; struct HelloWorldBundle { - ctx: Arc, + ctx: Arc, } impl BundleActivator for HelloWorldBundle { - fn new(ctx: Arc) -> Self { + fn new(ctx: Arc) -> Self { ctx.log_info("Hello World Bundle Activator created"); HelloWorldBundle { ctx } } diff --git a/misc/experimental/rust/shell_command_bundle/src/lib.rs b/misc/experimental/rust/shell_command_bundle/src/lib.rs index 50d2905f0..3856734ee 100644 --- a/misc/experimental/rust/shell_command_bundle/src/lib.rs +++ b/misc/experimental/rust/shell_command_bundle/src/lib.rs @@ -35,11 +35,11 @@ use celix_bindings::celix_shell_command_t; use celix_bindings::FILE; struct CShellCommandImpl { - ctx: Arc, + ctx: Arc, } impl CShellCommandImpl { - fn new(ctx: Arc) -> Self { + fn new(ctx: Arc) -> Self { ctx.log_info("Shell Command created"); CShellCommandImpl { ctx } } @@ -72,11 +72,11 @@ impl CShellCommandImpl { //temporary, should be moved in a separate API crate struct RustShellCommandImpl { - ctx: Arc, + ctx: Arc, } impl RustShellCommandImpl { - fn new(ctx: Arc) -> Self { + fn new(ctx: Arc) -> Self { ctx.log_info("Rust Shell Command created"); RustShellCommandImpl { ctx } } @@ -91,7 +91,7 @@ impl RustShellCommandTrait for RustShellCommandImpl { } struct ShellCommandActivator { - ctx: Arc, + ctx: Arc, //log_helper: Box, shell_command_provider: CShellCommandImpl, registrations: Vec, @@ -167,6 +167,8 @@ impl ShellCommandActivator { let count = self.ctx.use_services() .with_service::() .with_any_callback(Box::new( |svc: &dyn Any| { + //Mote below downcast, this is a hack. Cannot downcast to trait. + //Fixme trait service users should not need impl type (impl details) let typed_svc = svc.downcast_ref::(); if let Some(svc) = typed_svc { let _ = svc.execute_command("test"); @@ -190,7 +192,7 @@ impl ShellCommandActivator { } impl BundleActivator for ShellCommandActivator { - fn new(ctx: Arc) -> Self { + fn new(ctx: Arc) -> Self { let result = ShellCommandActivator { ctx: ctx.clone(), shell_command_provider: CShellCommandImpl::new(ctx.clone()), From 5329420835d1dc31f5f2b48e5d16ec1a3f7099a4 Mon Sep 17 00:00:00 2001 From: Pepijn Noltes Date: Mon, 28 Aug 2023 23:16:48 +0200 Subject: [PATCH 11/21] #599: Add poc svc tracker to rust experimental --- misc/experimental/rust/CMakeLists.txt | 15 +- .../rust/celix/src/bundle_context.rs | 463 ++++++++++++++---- misc/experimental/rust/celix/src/errno.rs | 10 + misc/experimental/rust/celix/src/lib.rs | 1 + .../experimental/rust/celix/src/log_helper.rs | 111 +++-- .../rust/celix_bindings/src/celix_bindings.h | 1 - .../rust/shell_command_bundle/src/lib.rs | 47 +- 7 files changed, 462 insertions(+), 186 deletions(-) diff --git a/misc/experimental/rust/CMakeLists.txt b/misc/experimental/rust/CMakeLists.txt index 6ab2287c3..966f83c8f 100644 --- a/misc/experimental/rust/CMakeLists.txt +++ b/misc/experimental/rust/CMakeLists.txt @@ -16,7 +16,7 @@ # under the License. option(CELIX_RUST_EXPERIMENTAL "Enable experimental rust bundle" OFF) -if (CELIX_RUST_EXPERIMENTAL) +if (CELIX_RUST_EXPERIMENTAL AND TARGET Celix::shell_tui AND TARGET Celix::shell AND TARGET Celix::log_admin) include(FetchContent) FetchContent_Declare( Corrosion @@ -29,7 +29,7 @@ if (CELIX_RUST_EXPERIMENTAL) #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 - "$;$;$;$;$") + "$;$;$;$") corrosion_import_crate(MANIFEST_PATH Cargo.toml) corrosion_add_target_local_rustflags(rust_bundle_activator "-Cprefer-dynamic") @@ -40,11 +40,17 @@ if (CELIX_RUST_EXPERIMENTAL) get_target_property(ACTUAL_LIB_TARGET rust_bundle_activator INTERFACE_LINK_LIBRARIES) add_celix_bundle(rust_bundle ACTIVATOR ${ACTUAL_LIB_TARGET}) add_dependencies(rust_bundle rust_bundle_activator) - corrosion_add_target_local_rustflags(rust_shell_command_activator "-Cprefer-dynamic") - corrosion_link_libraries(rust_shell_command_activator Celix::framework) + corrosion_link_libraries(rust_shell_command_activator + Celix::framework + ) get_target_property(ACTUAL_LIB_TARGET rust_shell_command_activator INTERFACE_LINK_LIBRARIES) add_celix_bundle(rust_shell_command ACTIVATOR ${ACTUAL_LIB_TARGET}) + target_link_libraries(${ACTUAL_LIB_TARGET} INTERFACE + -Wl,--whole-archive + Celix::log_helper + -Wl,--no-whole-archive + ) add_dependencies(rust_shell_command rust_shell_command_activator) add_celix_container(rust_container NO_COPY @@ -56,6 +62,7 @@ if (CELIX_RUST_EXPERIMENTAL) add_celix_container(rust_shell_cnt NO_COPY BUNDLES + Celix::log_admin Celix::shell Celix::shell_tui rust_shell_command diff --git a/misc/experimental/rust/celix/src/bundle_context.rs b/misc/experimental/rust/celix/src/bundle_context.rs index 56ddc69aa..e944dfa48 100644 --- a/misc/experimental/rust/celix/src/bundle_context.rs +++ b/misc/experimental/rust/celix/src/bundle_context.rs @@ -21,12 +21,17 @@ use std::any::type_name; use std::any::Any; use std::collections::HashMap; use std::ffi::c_void; +use std::ops::Deref; use std::ptr::null_mut; use std::sync::Arc; use std::sync::Mutex; use std::sync::Weak; -use celix_bindings::celix_bundleContext_log; +use celix_bindings::{celix_bundleContext_log, celix_bundleContext_stopTracker, celix_bundleContext_stopTrackerAsync, celix_bundleContext_trackServicesWithOptions, celix_bundleContext_trackServicesWithOptionsAsync, celix_properties_t}; +use celix_bindings::celix_service_filter_options; +use celix_bindings::celix_bundleContext_registerServiceWithOptionsAsync; +use celix_bindings::celix_bundleContext_unregisterServiceAsync; +use celix_bindings::celix_service_tracking_options_t; use celix_bindings::celix_service_use_options_t; use celix_bindings::celix_service_filter_options_t; use celix_bindings::celix_bundleContext_useServicesWithOptions; @@ -43,33 +48,64 @@ use super::LogLevel; pub struct ServiceRegistration { service_id: i64, + service_name: String, + unregister_async: bool, weak_ctx: Weak, - _boxed_svc: Option>, + svc: Option>, + unmanaged_svc: Option<*mut dyn Any>, +} + +impl ServiceRegistration { + pub fn get_service_id(&self) -> i64 { + self.service_id + } + + pub fn get_service_name(&self) -> &str { + self.service_name.as_str() + } + + pub fn get_service(&self) -> Option<&dyn Any> { + if let Some(boxed_svc) = self.svc.as_ref() { + Some(boxed_svc.as_ref()) + } else if let Some(unmanaged_svc) = self.unmanaged_svc { + unsafe { + Some(&*unmanaged_svc) + } + } else { + None + } + } } impl Drop for ServiceRegistration { fn drop(&mut self) { let ctx = self.weak_ctx.upgrade(); match ctx { - Some(ctx) => ctx.unregister_service(self.service_id), + Some(ctx) => ctx.unregister_service(self.service_id, self.unregister_async), None => println!("Cannot unregister ServiceRegistration: BundleContext is gone"), } } } -pub struct ServiceRegistrationBuilder<'a> { +pub struct ServiceRegistrationBuilder<'a, T: ?Sized + 'static> { ctx: &'a BundleContext, - boxed_svc: Option>, + register_async: bool, + unregister_async: bool, + svc: Option>, //note box is needed for stable pointer value + unmanaged_svc: Option<*mut dyn Any>, service_name: String, service_version: String, service_properties: HashMap, } -impl ServiceRegistrationBuilder<'_> { - fn new(ctx: &BundleContext) -> ServiceRegistrationBuilder { +impl ServiceRegistrationBuilder<'_, T> { + fn new(ctx: &BundleContext) -> ServiceRegistrationBuilder { ServiceRegistrationBuilder { ctx, - boxed_svc: None, + register_async: false, + unregister_async: false, + svc: None, + unmanaged_svc: None, service_name: "".to_string(), service_version: "".to_string(), service_properties: HashMap::new(), @@ -81,21 +117,21 @@ impl ServiceRegistrationBuilder<'_> { self } - fn with_service_name_if_not_set(&mut self, name: &str) -> &mut Self { + fn with_service_name_if_not_set(&mut self) -> &mut Self { if self.service_name.is_empty() { - self.service_name = name.to_string(); + self.service_name = type_name::().to_string(); } self } - pub fn with_service(&mut self, svc: I) -> &mut Self { - self.boxed_svc = Some(Box::new(svc)); - self.with_service_name_if_not_set(type_name::()) + pub fn with_service(&mut self, svc: T) -> &mut Self { + self.svc = Some(Box::new(svc)); + self.with_service_name_if_not_set() } - pub fn with_boxed_service(&mut self, svc: Box) -> &mut Self { - self.boxed_svc = Some(Box::new(svc)); - self.with_service_name_if_not_set(type_name::()) + pub fn with_unmanaged_service(&mut self, svc: *mut T) -> &mut Self { + self.unmanaged_svc = Some(svc); + self.with_service_name_if_not_set() } pub fn with_version(&mut self, version: &str) -> &mut Self { @@ -114,6 +150,26 @@ impl ServiceRegistrationBuilder<'_> { self } + pub fn with_register_async(&mut self) -> &mut Self { + self.register_async = true; + self + } + + pub fn with_register_sync(&mut self) -> &mut Self { + self.register_async = false; + self + } + + pub fn with_unregister_async(&mut self) -> &mut Self { + self.unregister_async = true; + self + } + + pub fn with_unregister_sync(&mut self) -> &mut Self { + self.unregister_async = false; + self + } + fn validate(&self) -> Result<(), Error> { let mut valid = true; if self.service_name.is_empty() { @@ -121,7 +177,7 @@ impl ServiceRegistrationBuilder<'_> { .log_error("Cannot register service. Service name is empty"); valid = false; } - if self.boxed_svc.is_none() /*&& self.arc_svc.is_none() */ { + if self.svc.is_none() && self.unmanaged_svc.is_none() { self.ctx .log_error("Cannot register service. No instance provided"); valid = false; @@ -132,25 +188,41 @@ impl ServiceRegistrationBuilder<'_> { } } - fn get_c_svc(&mut self) -> *mut c_void { - if let Some(boxed_svc) = self.boxed_svc.as_mut() { - let any_svc: &mut dyn Any = boxed_svc.as_mut(); - let boxed_svc_ptr = any_svc as *mut dyn Any; //note box still owns the instance - boxed_svc_ptr as *mut c_void + fn get_c_svc(svc_reg: &ServiceRegistration) -> *mut c_void { + if let Some(boxed_svc) = svc_reg.svc.as_ref() { + boxed_svc.deref() as *const dyn Any as *mut c_void + } else if let Some(unmanaged_svc) = svc_reg.unmanaged_svc { + unmanaged_svc as *mut c_void } else { null_mut() } } - - unsafe fn build_unsafe(&mut self, svc_ptr: *mut c_void) -> Result { + + pub fn build(&mut self) -> Result { + self.validate()?; + + let mut svc_reg = ServiceRegistration { + service_id: -1, + service_name: self.service_name.clone(), + unregister_async: self.unregister_async, + weak_ctx: self.ctx.get_self().clone(), + svc: if self.svc.is_none() { None } else { Some(self.svc.take().unwrap()) }, + unmanaged_svc: self.unmanaged_svc, + }; + + let svc_ptr = Self::get_c_svc(&svc_reg); let c_service_name = std::ffi::CString::new(self.service_name.as_str()).unwrap(); let c_service_version = std::ffi::CString::new(self.service_version.as_str()).unwrap(); - let c_service_properties = celix_properties_create(); - for (key, value) in self.service_properties.iter() { - let c_key = std::ffi::CString::new(key.as_str()).unwrap(); - let c_value = std::ffi::CString::new(value.as_str()).unwrap(); - celix_properties_set(c_service_properties, c_key.as_ptr(), c_value.as_ptr()); + let c_service_properties: *mut celix_properties_t; + unsafe { + c_service_properties = celix_properties_create(); + for (key, value) in self.service_properties.iter() { + let c_key = std::ffi::CString::new(key.as_str()).unwrap(); + let c_value = std::ffi::CString::new(value.as_str()).unwrap(); + celix_properties_set(c_service_properties, c_key.as_ptr(), c_value.as_ptr()); + } } + let opts = celix_service_registration_options_t { svc: svc_ptr, factory: null_mut(), @@ -166,71 +238,44 @@ impl ServiceRegistrationBuilder<'_> { asyncCallback: None, }; - let service_id: i64 = - celix_bundleContext_registerServiceWithOptions(self.ctx.get_c_bundle_context(), &opts); - if service_id >= 0 { - Ok(ServiceRegistration { - service_id, - weak_ctx: self.ctx.get_self().clone(), - _boxed_svc: self.boxed_svc.take(), - }) + if self.register_async { + unsafe { + svc_reg.service_id = celix_bundleContext_registerServiceWithOptions(self.ctx.get_c_bundle_context(), &opts); + } } else { - Err(Error::BundleException) + unsafe { + svc_reg.service_id = celix_bundleContext_registerServiceWithOptionsAsync(self.ctx.get_c_bundle_context(), &opts); + } } - } - - pub fn build(&mut self) -> Result { - self.validate()?; - let svc_ptr = self.get_c_svc(); - unsafe { - self.build_unsafe(svc_ptr) + if svc_reg.service_id >= 0 { + Ok(svc_reg) + } else { + Err(Error::BundleException) } } } -pub struct ServiceUseBuilder<'a> { +pub struct ServiceUseBuilder<'a, T> { ctx: &'a BundleContext, many: bool, service_name: String, filter: String, - callback: Option>> + callback: Option>, //note double boxed } -impl ServiceUseBuilder<'_> { - fn new(ctx: &BundleContext, many: bool) -> ServiceUseBuilder { +impl ServiceUseBuilder<'_, T> { + fn new(ctx: &BundleContext, many: bool) -> ServiceUseBuilder { ServiceUseBuilder { ctx, many, - service_name: "".to_string(), + service_name: type_name::().to_string(), filter: "".to_string(), callback: None, } } - pub fn with_service(&mut self) -> &mut Self { - self.service_name = type_name::().to_string(); - self - } - - #[doc = " @brief Provide a callback which will be called when a service is available. T must be a Sized (non trait) type, due to the use of downcast_ref"] - pub fn with_callback(&mut self, closure: Box)-> &mut Self { - if self.service_name.is_empty() { - self.with_service::(); - } - - let any_closure = Box::new(move |any_svc: &dyn Any| { - if let Some(svc) = any_svc.downcast_ref::() { - closure(svc); - } - }); - - self.callback = Some(Box::new(any_closure)); - self - } - - #[doc = " @brief Provide a callback which will be called when a service is available, with a dyn Any argument. Note that this is useful for trait objects."] - pub fn with_any_callback(&mut self, closure: Box)-> &mut Self { - self.callback = Some(Box::new(closure)); //note double boxed + pub fn with_callback(&mut self, closure: Box)-> &mut Self { + self.callback = Some(closure); self } @@ -245,17 +290,20 @@ impl ServiceUseBuilder<'_> { } fn validate(&self) -> Result<(), Error> { - if self.callback.is_none() || self.service_name.is_empty() { + if self.service_name.is_empty() { return Err(Error::BundleException); } Ok(()) } unsafe extern "C" fn use_service_c_callback(handle: *mut c_void, svc: *mut c_void) { - let boxed_fn = Box::from_raw(handle as *mut Box); - let any_svc_ptr = svc as *mut dyn Any; - let any_svc_ref = any_svc_ptr.as_ref().unwrap(); - boxed_fn(any_svc_ref); + let closure = handle as *const Box; + let closure = closure.as_ref().unwrap(); + + let typed_svc = svc as *const T; + let typed_svc = typed_svc.as_ref().unwrap(); + + closure(typed_svc); } pub fn build(&mut self) -> Result { @@ -264,13 +312,9 @@ impl ServiceUseBuilder<'_> { let c_service_name = std::ffi::CString::new(self.service_name.as_str()).unwrap(); let c_filter = std::ffi::CString::new(self.filter.as_str()).unwrap(); let c_service_name_ptr: *const i8 = c_service_name.as_ptr(); - - //Note filter is for now unused, introduce when updating to use of celix_bundleContext_useServiceWithOptions let c_filter_ptr: *const i8 = if self.filter.is_empty() { null_mut()} else {c_filter.as_ptr() }; - let boxed_fn = self.callback.take().unwrap(); - let fn_ptr = Box::into_raw(boxed_fn) as *mut c_void; - + let c_closure_ptr = self.callback.as_ref().unwrap() as *const Box as *mut c_void; let opts = celix_service_use_options_t { filter: celix_service_filter_options_t { @@ -281,18 +325,20 @@ impl ServiceUseBuilder<'_> { ignoreServiceLanguage: false, }, waitTimeoutInSeconds: 0.0, - callbackHandle: fn_ptr, + callbackHandle: c_closure_ptr, use_: Some(Self::use_service_c_callback), useWithProperties: None, useWithOwner: None, flags: 0, }; - unsafe { - if self.many { + if self.many { + unsafe { let count = celix_bundleContext_useServicesWithOptions(self.ctx.get_c_bundle_context(), &opts); Ok(count as isize) - } else { + } + } else { + unsafe { let called = celix_bundleContext_useServiceWithOptions(self.ctx.get_c_bundle_context(), &opts); if called { Ok(1) @@ -304,6 +350,210 @@ impl ServiceUseBuilder<'_> { } } +struct ServiceTrackerCallbacks { + set_callback: Option)>>, + add_callback: Option>, + remove_callback: Option>, +} + +pub struct ServiceTracker { + ctx: Arc, + tracker_id: i64, + // shared_data: Mutex>, + // data_condition: Condvar, + callbacks: Box>, //Note in a box to ensure pointer value is stable after move + stop_async: bool, +} + +impl ServiceTracker { + pub fn close(&mut self) { + self.ctx.stop_tracker(self.tracker_id, self.stop_async); + self.tracker_id = -1; + } +} + +impl Drop for ServiceTracker { + fn drop(&mut self) { + self.close(); + } +} + +pub struct ServiceTrackerBuilder<'a, T> { + ctx: &'a BundleContext, + service_name: String, + filter: String, + track_async: bool, + stop_async: bool, + set_callback: Option)>>, + add_callback: Option>, + remove_callback: Option>, +} + +impl ServiceTrackerBuilder<'_, T> { + fn new(ctx: &BundleContext) -> ServiceTrackerBuilder { + ServiceTrackerBuilder { + ctx, + service_name: type_name::().to_string(), + filter: "".to_string(), + track_async: false, + stop_async: false, + set_callback: None, + add_callback: None, + remove_callback: None, + } + } + + pub fn with_service_name(&mut self, name: &str) -> &mut Self { + self.service_name = name.to_string(); + self + } + + pub fn with_filter(&mut self, filter: &str) -> &mut Self { + self.filter = filter.to_string(); + self + } + + pub fn with_set_callback(&mut self, closure: Box)>) -> &mut Self { + self.set_callback = Some(closure); + self + } + + pub fn with_add_callback(&mut self, closure: Box) -> &mut Self { + self.add_callback = Some(closure); + self + } + + pub fn with_remove_callback(&mut self, closure: Box) -> &mut Self { + self.remove_callback = Some(closure); + self + } + + pub fn with_track_async(&mut self) -> &mut Self { + self.track_async = true; + self + } + + pub fn with_track_sync(&mut self) -> &mut Self { + self.track_async = false; + self + } + + pub fn with_stop_async(&mut self) -> &mut Self { + self.stop_async = true; + self + } + + pub fn with_stop_sync(&mut self) -> &mut Self { + self.stop_async = false; + self + } + + fn validate(&self) -> Result<(), Error> { + if self.service_name.is_empty() { + return Err(Error::BundleException); + } + Ok(()) + } + + unsafe extern "C" fn set_callback_for_c(handle: *mut ::std::os::raw::c_void, svc: *mut ::std::os::raw::c_void) { + let callbacks = handle as *const ServiceTrackerCallbacks; + let callbacks = callbacks.as_ref().unwrap(); + + if svc.is_null() { + if let Some(set_callback) = callbacks.set_callback.as_ref() { + set_callback(None); + } + } else { + let typed_svc = svc as *const T; + let typed_svc = typed_svc.as_ref().unwrap(); + if let Some(set_callback) = callbacks.set_callback.as_ref() { + set_callback(Some(typed_svc)); + } + } + } + + unsafe extern "C" fn add_callback_for_c(handle: *mut ::std::os::raw::c_void, svc: *mut ::std::os::raw::c_void) { + let callbacks = handle as *const ServiceTrackerCallbacks; + let callbacks = callbacks.as_ref().unwrap(); + + let typed_svc = svc as *const T; + let typed_svc = typed_svc.as_ref().unwrap(); + + if let Some(add_callback) = callbacks.add_callback.as_ref() { + add_callback(typed_svc); + } + } + + unsafe extern "C" fn remove_callback_for_c(handle: *mut ::std::os::raw::c_void, svc: *mut ::std::os::raw::c_void) { + let callbacks = handle as *const ServiceTrackerCallbacks; + let callbacks = callbacks.as_ref().unwrap(); + + let typed_svc = svc as *const T; + let typed_svc = typed_svc.as_ref().unwrap(); + + if let Some(remove_callback) = callbacks.remove_callback.as_ref() { + remove_callback(typed_svc); + } + } + + pub fn build(&mut self) -> Result, Error> { + self.validate()?; + + let mut svc_tracker = ServiceTracker { + ctx: self.ctx.get_self().upgrade().unwrap(), + tracker_id: -1, + callbacks: Box::new(ServiceTrackerCallbacks { + set_callback: self.set_callback.take(), + add_callback: self.add_callback.take(), + remove_callback: self.remove_callback.take(), + }), + stop_async: self.stop_async, + }; + + let c_service_name = std::ffi::CString::new(self.service_name.as_str()).unwrap(); + let c_filter = std::ffi::CString::new(self.filter.as_str()).unwrap(); + let c_callback_handle = svc_tracker.callbacks.as_ref() as *const ServiceTrackerCallbacks as *mut c_void; + + let opts = celix_service_tracking_options_t{ + filter: celix_service_filter_options { + serviceName: c_service_name.as_ptr(), + versionRange: null_mut(), + filter: if self.filter.is_empty() { null_mut() } else { c_filter.as_ptr() }, + serviceLanguage: null_mut(), + ignoreServiceLanguage: false, + }, + callbackHandle: c_callback_handle, + set: Some(Self::set_callback_for_c), + setWithProperties: None, + setWithOwner: None, + add: Some(Self::add_callback_for_c), + addWithProperties: None, + addWithOwner: None, + remove: Some(Self::remove_callback_for_c), + removeWithProperties: None, + removeWithOwner: None, + trackerCreatedCallbackData: null_mut(), + trackerCreatedCallback: None, + }; + + let svc_tracker_id: i64; + unsafe { + if self.track_async { + svc_tracker_id = celix_bundleContext_trackServicesWithOptionsAsync(self.ctx.get_c_bundle_context(), &opts); + } else { + svc_tracker_id = celix_bundleContext_trackServicesWithOptions(self.ctx.get_c_bundle_context(), &opts); + } + } + + if svc_tracker_id >= 0 { + svc_tracker.tracker_id = svc_tracker_id; + Ok(svc_tracker) + } else { + Err(Error::BundleException) + } + } +} + pub struct BundleContext { c_bundle_context: *mut celix_bundle_context_t, weak_self: Mutex>>, @@ -329,12 +579,6 @@ impl BundleContext { self.weak_self.lock().unwrap().clone().unwrap() } - fn unregister_service(&self, service_id: i64) { - unsafe { - celix_bundleContext_unregisterService(self.c_bundle_context, service_id); - } - } - fn log_to_c(&self, level: LogLevel, message: &str) { unsafe { let result = std::ffi::CString::new(message); @@ -385,20 +629,39 @@ impl BundleContext { self.log(LogLevel::Fatal, message); } - //TODO make generic - pub fn register_service(&self) -> ServiceRegistrationBuilder { + pub fn register_service(&self) -> ServiceRegistrationBuilder { ServiceRegistrationBuilder::new(self) } - //TODO make generic - pub fn use_service(&self) -> ServiceUseBuilder { + fn unregister_service(&self, service_id: i64, unregister_async: bool) { + unsafe { + if unregister_async { + celix_bundleContext_unregisterServiceAsync(self.c_bundle_context, service_id, null_mut(), None); + } else { + celix_bundleContext_unregisterService(self.c_bundle_context, service_id); + } + } + } + + pub fn use_service(&self) -> ServiceUseBuilder { ServiceUseBuilder::new(self, false) } - //TODO make generic - pub fn use_services(&self) -> ServiceUseBuilder { + pub fn use_services(&self) -> ServiceUseBuilder { ServiceUseBuilder::new(self, true) } + + pub fn track_services(&self) -> ServiceTrackerBuilder { ServiceTrackerBuilder::new(self) } + + fn stop_tracker(&self, tracker_id: i64, stop_async: bool) { + unsafe { + if stop_async { + celix_bundleContext_stopTrackerAsync(self.c_bundle_context, tracker_id, null_mut(), None); + } else { + celix_bundleContext_stopTracker(self.c_bundle_context, tracker_id); + } + } + } } pub fn bundle_context_new(c_bundle_context: *mut celix_bundle_context_t) -> Arc { diff --git a/misc/experimental/rust/celix/src/errno.rs b/misc/experimental/rust/celix/src/errno.rs index af23d2cab..4f9f85ee0 100644 --- a/misc/experimental/rust/celix/src/errno.rs +++ b/misc/experimental/rust/celix/src/errno.rs @@ -17,6 +17,7 @@ * under the License. */ +use std::fmt::{Debug, Formatter}; use celix_bindings::celix_status_t; pub const CELIX_SUCCESS: celix_status_t = celix_bindings::CELIX_SUCCESS as celix_status_t; @@ -47,3 +48,12 @@ impl Into for Error { } } } + +impl Debug for Error { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + match self { + Error::BundleException => write!(f, "BundleException"), + Error::CelixStatusError(status) => write!(f, "CelixStatusError({})", status), + } + } +} diff --git a/misc/experimental/rust/celix/src/lib.rs b/misc/experimental/rust/celix/src/lib.rs index b30f995ef..390a62805 100644 --- a/misc/experimental/rust/celix/src/lib.rs +++ b/misc/experimental/rust/celix/src/lib.rs @@ -43,6 +43,7 @@ mod bundle_context; pub use self::bundle_context::bundle_context_new; pub use self::bundle_context::BundleContext; pub use self::bundle_context::ServiceRegistration; +pub use self ::bundle_context::ServiceTracker; mod bundle_activator; // Re-export bundle activator types in the public API. diff --git a/misc/experimental/rust/celix/src/log_helper.rs b/misc/experimental/rust/celix/src/log_helper.rs index 64099ba56..72087eef1 100644 --- a/misc/experimental/rust/celix/src/log_helper.rs +++ b/misc/experimental/rust/celix/src/log_helper.rs @@ -17,93 +17,98 @@ * under the License. */ -use std::sync::Arc; +use std::ops::Deref; +use std::sync::{Arc, Mutex, RwLock}; use super::BundleContext; use super::LogLevel; -use celix_bindings::celix_logHelper_create; -use celix_bindings::celix_logHelper_destroy; -use celix_bindings::celix_logHelper_log; -use celix_bindings::celix_log_helper_t; +use celix_bindings::celix_log_service_t; +use ServiceTracker; + pub struct LogHelper { - celix_log_helper: *mut celix_log_helper_t, + name: String, + tracker: Mutex>>, + log_svc: RwLock>, } impl LogHelper { - pub fn new(ctx: Arc, name: &str) -> Self { - unsafe { - let result = std::ffi::CString::new(name); - match result { - Ok(c_str) => LogHelper { - 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(); - LogHelper { - celix_log_helper: celix_logHelper_create( - ctx.get_c_bundle_context(), - c_str.as_ptr() as *const i8, - ), - } + + pub fn new(ctx: Arc, name: &str) -> Arc { + let helper = Arc::new(LogHelper{ + name: name.to_string(), + tracker: Mutex::new(None), + log_svc: RwLock::new(None), + }); + let filter = format!("(name={})", name); + let weak_helper = Arc::downgrade(&helper); + let tracker = ctx.track_services::() + .with_service_name("celix_log_service") + .with_filter(filter.as_str()) + .with_set_callback(Box::new(move|optional_svc| { + if let Some(helper) = weak_helper.upgrade() { + helper.set_celix_log_service(optional_svc); } + })) + .build().unwrap(); + helper.tracker.lock().unwrap().replace(tracker); + helper + } + + pub fn get_name(&self) -> &str { + &self.name + } + + pub fn set_celix_log_service(&self, optional_svc: Option<&celix_log_service_t>) { + match optional_svc { + Some(svc) => { + let svc_ptr: *const celix_log_service_t = svc as *const celix_log_service_t; + self.log_svc.write().unwrap().replace(svc_ptr); + } + None => { + self.log_svc.write().unwrap().take(); } } } pub 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, - ); + let str_result = std::ffi::CString::new(message).unwrap(); + let guard = self.log_svc.read().unwrap(); + if let Some(svc) = guard.as_ref() { + unsafe { + if svc.is_null() { + return; } - Err(e) => { - println!("Error creating CString: {}", e); + let svc = &**svc; + if svc.log.is_none() { + return; } + let log_fn = svc.deref().log.as_ref().unwrap(); + log_fn(svc.handle, level.into(), str_result.as_ptr()); } } } - pub fn trace(&self, message: &str) { + pub fn log_trace(&self, message: &str) { self.log(LogLevel::Trace, message); } - pub fn debug(&self, message: &str) { + pub fn log_debug(&self, message: &str) { self.log(LogLevel::Debug, message); } - pub fn info(&self, message: &str) { + pub fn log_info(&self, message: &str) { self.log(LogLevel::Info, message); } - pub fn warning(&self, message: &str) { + pub fn log_warning(&self, message: &str) { self.log(LogLevel::Warning, message); } - pub fn error(&self, message: &str) { + pub fn log_error(&self, message: &str) { self.log(LogLevel::Error, message); } - pub fn fatal(&self, message: &str) { + pub fn log_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 5db2ff227..76c87b6a3 100644 --- a/misc/experimental/rust/celix_bindings/src/celix_bindings.h +++ b/misc/experimental/rust/celix_bindings/src/celix_bindings.h @@ -33,4 +33,3 @@ #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/shell_command_bundle/src/lib.rs b/misc/experimental/rust/shell_command_bundle/src/lib.rs index 3856734ee..bb097765f 100644 --- a/misc/experimental/rust/shell_command_bundle/src/lib.rs +++ b/misc/experimental/rust/shell_command_bundle/src/lib.rs @@ -21,12 +21,11 @@ extern crate celix; extern crate celix_bindings; extern crate rust_shell_api; -use std::any::Any; use std::ffi::c_char; use std::ffi::c_void; use std::sync::Arc; -use celix::BundleActivator; +use celix::{BundleActivator, LogHelper}; use celix::BundleContext; use celix::Error; use rust_shell_api::{RustShellCommandTrait, RustShellCommandStruct}; @@ -92,7 +91,7 @@ impl RustShellCommandTrait for RustShellCommandImpl { struct ShellCommandActivator { ctx: Arc, - //log_helper: Box, + log_helper: Arc, shell_command_provider: CShellCommandImpl, registrations: Vec, } @@ -111,19 +110,17 @@ impl ShellCommandActivator { .with_property("command.description", "Simple command written in Rust") .build()?; self.registrations.push(registration); - self.ctx.log_info("C Shell Command registered"); + self.log_helper.log_info("C Shell Command registered"); //Register Rust trait service register using a Box - let rust_shell_command = Box::new(RustShellCommandImpl::new(self.ctx.clone())); - let rust_shell_command = Box::::from(rust_shell_command); + let rust_shell_command: Arc = Arc::new(RustShellCommandImpl::new(self.ctx.clone())); let registration = self.ctx.register_service() - //maybe make svc types more explicit, e.g.with type parameters - .with_boxed_service(rust_shell_command) + .with_service(rust_shell_command) .with_property(rust_shell_api::COMMAND_NAME, "exe_rust_command") .with_property(rust_shell_api::COMMAND_DESCRIPTION, "Simple command written in a Rust trait") .build()?; self.registrations.push(registration); - self.ctx.log_info("Rust trait Shell Command registered"); + self.log_helper.log_info("Rust trait Shell Command registered"); //Register Rust struct service (with closures) as value @@ -140,53 +137,47 @@ impl ShellCommandActivator { .with_property("command.description", "Simple command written in a Rust struct using a Rust closure") .build()?; self.registrations.push(registration); - self.ctx.log_info("Rust struct Shell Command registered"); + self.log_helper.log_info("Rust struct Shell Command registered"); Ok(()) } fn use_services(&mut self) -> Result<(), Error> { //test using C service - self.ctx.log_info("Use C service command service"); + self.log_helper.log_info("Use C service command service"); let count = self.ctx.use_services() .with_service_name("celix_shell_command") .with_filter("(command.name=exe_c_command_in_rust)") .with_callback(Box::new( |svc: &celix_shell_command_t| { if let Some(exe_cmd) = svc.executeCommand { - let c_str = std::ffi::CString::new("test").unwrap(); + let c_str = std::ffi::CString::new("test c service").unwrap(); unsafe { exe_cmd(svc.handle, c_str.as_ptr() as *const c_char, std::ptr::null_mut(), std::ptr::null_mut()); } } })) .build()?; - self.ctx.log_info(format!("Found {} celix_shell_command_t services", count).as_str()); + self.log_helper.log_info(format!("Found {} celix_shell_command_t services", count).as_str()); //test using Rust trait service - self.ctx.log_info("Use Rust trait service command service"); + self.log_helper.log_info("Use Rust trait service command service"); let count = self.ctx.use_services() - .with_service::() - .with_any_callback(Box::new( |svc: &dyn Any| { - //Mote below downcast, this is a hack. Cannot downcast to trait. - //Fixme trait service users should not need impl type (impl details) - let typed_svc = svc.downcast_ref::(); - if let Some(svc) = typed_svc { - let _ = svc.execute_command("test"); - } + .with_callback(Box::new( |svc: &Arc| { + let _ = svc.execute_command("test rest trait"); })) .build()?; - self.ctx.log_info(format!("Found {} RustShellCommandTrait services", count).as_str()); + self.log_helper.log_info(format!("Found {} RustShellCommandTrait services", count).as_str()); - self.ctx.log_info("Use Rust struct service command service"); + self.log_helper.log_info("Use Rust struct service command service"); let count = self.ctx.use_services() .with_callback(Box::new( |svc: &RustShellCommandStruct| { let exe_cmd = svc.execute_command.as_ref(); - let _ = exe_cmd("test"); + let _ = exe_cmd("test rust struct"); })) .build()?; - self.ctx.log_info(format!("Found {} RustShellCommandStruct services", count).as_str()); + self.log_helper.log_info(format!("Found {} RustShellCommandStruct services", count).as_str()); - self.ctx.log_info("Rust Shell Command started"); + self.log_helper.log_info("Rust Shell Command started"); Ok(()) } } @@ -196,7 +187,7 @@ impl BundleActivator for ShellCommandActivator { let result = ShellCommandActivator { ctx: ctx.clone(), shell_command_provider: CShellCommandImpl::new(ctx.clone()), - //log_helper: log_helper_new(&*ctx, "ShellCommandBundle"), + log_helper: LogHelper::new(ctx.clone(), "ShellCommandBundle"), registrations: Vec::new(), }; result From 8b3f9436ae5cf04559bb9b166dff765c25edb7f2 Mon Sep 17 00:00:00 2001 From: Pepijn Noltes Date: Mon, 28 Aug 2023 23:51:45 +0200 Subject: [PATCH 12/21] #599: Remove unused poc rust bundle example --- misc/experimental/rust/CMakeLists.txt | 8 +- misc/experimental/rust/Cargo.toml | 1 - .../rust/rust_shell_api/src/lib.rs | 5 - .../rust/rust_shell_tui/Cargo.toml | 28 --- .../rust/rust_shell_tui/src/lib.rs | 161 ------------------ .../rust/shell_command_bundle/src/lib.rs | 27 +-- 6 files changed, 3 insertions(+), 227 deletions(-) delete mode 100644 misc/experimental/rust/rust_shell_tui/Cargo.toml delete mode 100644 misc/experimental/rust/rust_shell_tui/src/lib.rs diff --git a/misc/experimental/rust/CMakeLists.txt b/misc/experimental/rust/CMakeLists.txt index 966f83c8f..964ab62da 100644 --- a/misc/experimental/rust/CMakeLists.txt +++ b/misc/experimental/rust/CMakeLists.txt @@ -44,13 +44,9 @@ if (CELIX_RUST_EXPERIMENTAL AND TARGET Celix::shell_tui AND TARGET Celix::shell corrosion_link_libraries(rust_shell_command_activator Celix::framework ) + get_target_property(ACTUAL_LIB_TARGET rust_shell_command_activator INTERFACE_LINK_LIBRARIES) add_celix_bundle(rust_shell_command ACTIVATOR ${ACTUAL_LIB_TARGET}) - target_link_libraries(${ACTUAL_LIB_TARGET} INTERFACE - -Wl,--whole-archive - Celix::log_helper - -Wl,--no-whole-archive - ) add_dependencies(rust_shell_command rust_shell_command_activator) add_celix_container(rust_container NO_COPY @@ -62,9 +58,9 @@ if (CELIX_RUST_EXPERIMENTAL AND TARGET Celix::shell_tui AND TARGET Celix::shell add_celix_container(rust_shell_cnt NO_COPY BUNDLES - Celix::log_admin Celix::shell Celix::shell_tui + Celix::log_admin rust_shell_command ) diff --git a/misc/experimental/rust/Cargo.toml b/misc/experimental/rust/Cargo.toml index 9dc3d5140..c8942eb6b 100644 --- a/misc/experimental/rust/Cargo.toml +++ b/misc/experimental/rust/Cargo.toml @@ -22,5 +22,4 @@ members = [ "hello_world_activator", "rust_shell_api", "shell_command_bundle", - #"rust_shell_tui", ] diff --git a/misc/experimental/rust/rust_shell_api/src/lib.rs b/misc/experimental/rust/rust_shell_api/src/lib.rs index 0969f86c2..0b4396675 100644 --- a/misc/experimental/rust/rust_shell_api/src/lib.rs +++ b/misc/experimental/rust/rust_shell_api/src/lib.rs @@ -28,8 +28,3 @@ pub const COMMAND_DESCRIPTION: &str = "command.description"; pub trait RustShellCommandTrait { fn execute_command(&self, command_line: &str) -> Result<(), Error>; } - -#[doc = "A struct to register a Rust Shell Command"] -pub struct RustShellCommandStruct { - pub execute_command: Box Result<(), Error>> -} diff --git a/misc/experimental/rust/rust_shell_tui/Cargo.toml b/misc/experimental/rust/rust_shell_tui/Cargo.toml deleted file mode 100644 index fb4dced0c..000000000 --- a/misc/experimental/rust/rust_shell_tui/Cargo.toml +++ /dev/null @@ -1,28 +0,0 @@ -# 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. - -[package] -name = "rust_shell_tui" -version = "0.0.1" - -[dependencies] -celix_bindings = { path = "../celix_bindings" } - -[lib] -name = "rust_shell_tui_activator" -path = "src/lib.rs" -crate-type = ["cdylib"] diff --git a/misc/experimental/rust/rust_shell_tui/src/lib.rs b/misc/experimental/rust/rust_shell_tui/src/lib.rs deleted file mode 100644 index 08727add6..000000000 --- a/misc/experimental/rust/rust_shell_tui/src/lib.rs +++ /dev/null @@ -1,161 +0,0 @@ -/* - * 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. - */ - -extern crate celix_bindings; - -use std::os::raw::c_char; -use std::os::raw::c_void; -use std::ffi::CString; -use std::ffi::NulError; -use std::ptr::null_mut; -use celix_bindings::*; //Add all Apache Celix C bindings to the namespace (i.e. celix_bundleContext_log, etc.) - -// pub struct celix_shell_command { -// pub handle -// : *mut ::std ::os ::raw ::c_void, -// #[doc = -// " Calls the shell command.\n @param handle The shell command handle.\n @param commandLine The " -// "complete provided cmd line (e.g. for a 'stop' command -> 'stop 42')\n @param outStream The output " -// "stream, to use for printing normal flow info.\n @param errorStream The error stream, to use for " -// "printing error flow info.\n @return Whether a command is successfully executed."] pub -// executeCommand -// pub executeCommand : :: std :: option :: Option < unsafe extern "C" fn (handle : * mut :: std :: os :: raw :: c_void , commandLine : * const :: std :: os :: raw :: c_char , outStream : * mut FILE , errorStream : * mut FILE) -> bool > , } -// } - - -struct RustShellTui { - ctx: *mut celix_bundle_context_t, - svc_id: i64, - svc: celix_shell_command, -} - -unsafe extern "C" fn rust_shell_tui_execute_command(_handle: *mut c_void, command_line: *const c_char, out_stream: *mut FILE, error_stream: *mut FILE) -> bool { - let obj = Box::from_raw(_handle as *mut RustShellTui); - obj.execute_command(command_line, out_stream, error_stream) -} - -impl RustShellTui { - - unsafe fn new(ctx: *mut celix_bundle_context_t) -> Result { - let result = RustShellTui { - ctx, - svc_id: -1, - svc: celix_shell_command { - handle: null_mut(), - executeCommand: Some(rust_shell_tui_execute_command), - }, - }; - Ok(result) - } - - unsafe fn start(&mut self) -> Result<(), NulError> { - - // let mut input = String::new(); - // print!("-> "); - // loop { - // std::io::stdin().read_line(&mut input).unwrap(); - // println!("You typed: {}", input.trim()); - // input.clear(); - // print!("-> "); - // } - - // self.svc.executeCommand = Some(|handle: *mut c_void, commandLine: *const c_char, outStream: *mut FILE, errorStream: *mut FILE| -> bool { - // println!("RustShellTui::executeCommand called"); - // true - // }); - - //TODO let svc_name = CString::new(CELIX_SHELL_COMMAND_SERVICE_NAME as * const c_char).unwrap(); - let svc_name = CString::new("celix_shell_command").unwrap(); - - let command_name = CString::new("command.name").unwrap(); - let props = celix_properties_create(); - celix_properties_set(props, command_name.as_ptr(), CString::new("rust").unwrap().as_ptr()); - - self.svc.handle = Box::into_raw(Box::new(self.svc)) as *mut c_void; - - - self.svc_id = celix_bundleContext_registerServiceAsync( - self.ctx, - Box::into_raw(Box::new(self.svc)) as *mut c_void, - svc_name.as_ptr(), - props); - - Ok(()) - } - - unsafe fn stop(&mut self) -> Result<(), NulError> { - celix_bundleContext_unregisterService(self.ctx, self.svc_id); - self.svc_id = -1; - - // let to_drop = Box::from_raw(self.svc.handle); - // drop(to_drop); - - // TODO drop - // let to_drop = Box::from_raw(&self.svc); - // drop(to_drop); - Ok(()) - } - - fn execute_command(&self, _command_line: *const c_char, _out_stream: *mut FILE, _error_stream: *mut FILE) -> bool { - println!("RustShellTui::executeCommand called"); - true - } -} - -impl Drop for RustShellTui { - fn drop(&mut self) { () } -} - -#[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 obj = RustShellTui::new(ctx); - if obj.is_err() { - return CELIX_BUNDLE_EXCEPTION; - } - *data = Box::into_raw(Box::new(obj.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 obj = &mut *(data as *mut RustShellTui); - let result = obj.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 obj = &mut *(data as *mut RustShellTui); - let result = obj.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 obj = Box::from_raw(data as *mut RustShellTui); - drop(obj); - CELIX_SUCCESS -} - diff --git a/misc/experimental/rust/shell_command_bundle/src/lib.rs b/misc/experimental/rust/shell_command_bundle/src/lib.rs index bb097765f..98d5501db 100644 --- a/misc/experimental/rust/shell_command_bundle/src/lib.rs +++ b/misc/experimental/rust/shell_command_bundle/src/lib.rs @@ -28,7 +28,7 @@ use std::sync::Arc; use celix::{BundleActivator, LogHelper}; use celix::BundleContext; use celix::Error; -use rust_shell_api::{RustShellCommandTrait, RustShellCommandStruct}; +use rust_shell_api::RustShellCommandTrait; use celix_bindings::celix_shell_command_t; use celix_bindings::FILE; @@ -123,21 +123,6 @@ impl ShellCommandActivator { self.log_helper.log_info("Rust trait Shell Command registered"); - //Register Rust struct service (with closures) as value - let cloned_ctx = self.ctx.clone(); - let rust_shell_command = RustShellCommandStruct { - execute_command: Box::new(move |command_line: &str| { - cloned_ctx.log_info(format!("Execute command: {}", command_line).as_str()); - Ok(()) - }), - }; - let registration = self.ctx.register_service() - .with_service(rust_shell_command) - .with_property("command.name", "exe_rust_command2") - .with_property("command.description", "Simple command written in a Rust struct using a Rust closure") - .build()?; - self.registrations.push(registration); - self.log_helper.log_info("Rust struct Shell Command registered"); Ok(()) } @@ -168,16 +153,6 @@ impl ShellCommandActivator { .build()?; self.log_helper.log_info(format!("Found {} RustShellCommandTrait services", count).as_str()); - self.log_helper.log_info("Use Rust struct service command service"); - let count = self.ctx.use_services() - .with_callback(Box::new( |svc: &RustShellCommandStruct| { - let exe_cmd = svc.execute_command.as_ref(); - let _ = exe_cmd("test rust struct"); - })) - .build()?; - self.log_helper.log_info(format!("Found {} RustShellCommandStruct services", count).as_str()); - - self.log_helper.log_info("Rust Shell Command started"); Ok(()) } } From 53654a3c758f9a463768b1139e4abc54fccbd796 Mon Sep 17 00:00:00 2001 From: Pepijn Noltes Date: Tue, 29 Aug 2023 19:24:36 +0200 Subject: [PATCH 13/21] #599: Add support for CELIX_RUST_INCLUDE_PATHS_FILE env in rust poc --- .../experimental/rust/celix_bindings/build.rs | 40 ++++++++++++------- 1 file changed, 26 insertions(+), 14 deletions(-) diff --git a/misc/experimental/rust/celix_bindings/build.rs b/misc/experimental/rust/celix_bindings/build.rs index 8bae728bd..6f3b1d0a6 100644 --- a/misc/experimental/rust/celix_bindings/build.rs +++ b/misc/experimental/rust/celix_bindings/build.rs @@ -19,21 +19,37 @@ extern crate bindgen; +use std::env; use std::error::Error; -use std::path::PathBuf; use std::fs::File; use std::io::{self, BufRead}; -use std::env; +use std::path::PathBuf; -fn print_include_paths() -> Result, Box> { - let build_dir = PathBuf::from(env::var("CORROSION_BUILD_DIR").unwrap()); - let include_path_file = build_dir.join("include_paths.txt"); +fn open_include_paths_file() -> Result> { + let file: File; - //let include_path_file = Path::new("include_paths.txt"); - let file = File::open(&include_path_file)?; + let corrosion_build_dir = env::var("CORROSION_BUILD_DIR"); + if corrosion_build_dir.is_ok() { + let build_dir = PathBuf::from(corrosion_build_dir.unwrap()); + let include_path_file = build_dir.join("include_paths.txt"); + file = File::open(&include_path_file)?; + } else { + println!("include_paths.txt not found in CORROSION_BUILD_DIR. Failing back to CELIX_RUST_INCLUDE_PATHS_FILE env value"); + let include_path_file = env::var("CELIX_RUST_INCLUDE_PATHS_FILE")?; + file = File::open(&include_path_file)?; + } + + Ok(file) +} + +fn print_include_paths() -> Result, Box> { + let file = open_include_paths_file()?; let reader = io::BufReader::new(file); let mut include_paths = Vec::new(); - let line = reader.lines().next().ok_or("Expected at least one line")??; + let line = reader + .lines() + .next() + .ok_or("Expected at least one line")??; for path in line.split(';') { include_paths.push(path.to_string()); } @@ -44,8 +60,7 @@ fn main() { println!("cargo:info=Start build.rs for celix_bindings"); let include_paths = print_include_paths().unwrap(); - let mut builder = bindgen::Builder::default() - .header("src/celix_bindings.h"); + let mut builder = bindgen::Builder::default().header("src/celix_bindings.h"); // Add framework and utils include paths for path in &include_paths { @@ -53,10 +68,7 @@ fn main() { } // Gen bindings - let bindings = builder - .generate() - .expect("Unable to generate bindings"); - + let bindings = builder.generate().expect("Unable to generate bindings"); let out_path = PathBuf::from(env::var("OUT_DIR").unwrap()); bindings From 88deb837510d7b4878a6c9eb5eb73f586ca83b98 Mon Sep 17 00:00:00 2001 From: Pepijn Noltes Date: Tue, 29 Aug 2023 20:03:19 +0200 Subject: [PATCH 14/21] #599: Rename RustShellCommandTrait in rust poc --- misc/experimental/rust/rust_shell_api/src/lib.rs | 2 +- misc/experimental/rust/shell_command_bundle/src/lib.rs | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/misc/experimental/rust/rust_shell_api/src/lib.rs b/misc/experimental/rust/rust_shell_api/src/lib.rs index 0b4396675..c75a7c092 100644 --- a/misc/experimental/rust/rust_shell_api/src/lib.rs +++ b/misc/experimental/rust/rust_shell_api/src/lib.rs @@ -25,6 +25,6 @@ pub const COMMAND_USAGE: &str = "command.usage"; pub const COMMAND_DESCRIPTION: &str = "command.description"; #[doc = "A trait to implement a Celix Shell Command"] -pub trait RustShellCommandTrait { +pub trait RustShellCommand { fn execute_command(&self, command_line: &str) -> Result<(), Error>; } diff --git a/misc/experimental/rust/shell_command_bundle/src/lib.rs b/misc/experimental/rust/shell_command_bundle/src/lib.rs index 98d5501db..0889e386f 100644 --- a/misc/experimental/rust/shell_command_bundle/src/lib.rs +++ b/misc/experimental/rust/shell_command_bundle/src/lib.rs @@ -28,7 +28,7 @@ use std::sync::Arc; use celix::{BundleActivator, LogHelper}; use celix::BundleContext; use celix::Error; -use rust_shell_api::RustShellCommandTrait; +use rust_shell_api::RustShellCommand; use celix_bindings::celix_shell_command_t; use celix_bindings::FILE; @@ -81,7 +81,7 @@ impl RustShellCommandImpl { } } -impl RustShellCommandTrait for RustShellCommandImpl { +impl RustShellCommand for RustShellCommandImpl { fn execute_command(&self, command_line: &str) -> Result<(), Error> { self.ctx .log_info(format!("Execute command: {}.", command_line).as_str()); @@ -112,8 +112,8 @@ impl ShellCommandActivator { self.registrations.push(registration); self.log_helper.log_info("C Shell Command registered"); - //Register Rust trait service register using a Box - let rust_shell_command: Arc = Arc::new(RustShellCommandImpl::new(self.ctx.clone())); + //Register Rust trait service register using a Arc + let rust_shell_command: Arc = Arc::new(RustShellCommandImpl::new(self.ctx.clone())); let registration = self.ctx.register_service() .with_service(rust_shell_command) .with_property(rust_shell_api::COMMAND_NAME, "exe_rust_command") @@ -147,7 +147,7 @@ impl ShellCommandActivator { //test using Rust trait service self.log_helper.log_info("Use Rust trait service command service"); let count = self.ctx.use_services() - .with_callback(Box::new( |svc: &Arc| { + .with_callback(Box::new( |svc: &Arc| { let _ = svc.execute_command("test rest trait"); })) .build()?; From bf01a26804eb244babe170076f59227b4a803e17 Mon Sep 17 00:00:00 2001 From: Pepijn Noltes Date: Mon, 4 Sep 2023 19:34:59 +0200 Subject: [PATCH 15/21] #632: Update changes.md for coming Apache Celix 2.4.0 --- CHANGES.md | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/CHANGES.md b/CHANGES.md index 5cb408344..0d03bf528 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -19,6 +19,39 @@ See the License for the specific language governing permissions and limitations under the License. --> +# Noteworthy Changes for 2.4.0 (TBD) + +## New Features + +- V2 Shared memory for remote service admin. +- Zeroconf discovery of remote services. +- Symbol visibility support: Bundle symbols are now hidden by default, except for the bundle activator. +- Error injection library (for testing). +- Coding convention documentation. +- Celix error library for printing errors when no framework is available. +- Scope-based Resource Management (RAII-light for C). +- Rust Proof of Concept (PoC) for Apache Celix. + +## Improvements + +- Support for Conan 2. +- Support for uclibc (not tested in CI yet). +- Support for C++14 in addition to C++17. +- Deprecated `snprintf` usage; transitioned to `snprintf` or `aprintf`. +- Refactored the bundle cache to support retention of unchanged bundles on disk. +- Automatic scan for project build options using CMake. +- Use of upstream `civetweb` dependency instead of embedded sources. +- Applied attribute format for printf-like functions. +- Removed the busy loop mechanism from the pubsub admin websocket. +- Improved cleanup procedures during bundle uninstallation to conform to the OSGi specification. +- Improved `INSTALL_RPATH` to use `$ORIGIN` during installation. +- Corrected bundle update behavior when updating bundles from different sources. +- Enhanced `libcurl` initialization procedures and made `libcurl` optional. + +## Fixes + +- Numerous minor fixes, especially concerning multi-threading issues and error handling. + # Noteworthy changes for 2.3.0 (2022-07-10) ## New Features From f22719116e45fef6dfd9945d1b4b80ed0338bcd6 Mon Sep 17 00:00:00 2001 From: PengZheng Date: Wed, 6 Sep 2023 21:32:53 +0800 Subject: [PATCH 16/21] Update CMake to 3.19 to meet Corrosion's need. --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index f659fb16f..38f1daec3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -15,7 +15,7 @@ # specific language governing permissions and limitations # under the License. -cmake_minimum_required (VERSION 3.18) +cmake_minimum_required (VERSION 3.19) cmake_policy(SET CMP0012 NEW) cmake_policy(SET CMP0042 NEW) cmake_policy(SET CMP0068 NEW) From e3aa83a651a7c5c8b4edfcea08cf93ed17b74c39 Mon Sep 17 00:00:00 2001 From: Pepijn Noltes Date: Wed, 6 Sep 2023 19:23:28 +0200 Subject: [PATCH 17/21] #599: Add CMake 3.19 requirement for Rust PoC --- misc/experimental/rust/CMakeLists.txt | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/misc/experimental/rust/CMakeLists.txt b/misc/experimental/rust/CMakeLists.txt index 964ab62da..b407937e0 100644 --- a/misc/experimental/rust/CMakeLists.txt +++ b/misc/experimental/rust/CMakeLists.txt @@ -17,6 +17,10 @@ option(CELIX_RUST_EXPERIMENTAL "Enable experimental rust bundle" OFF) if (CELIX_RUST_EXPERIMENTAL AND TARGET Celix::shell_tui AND TARGET Celix::shell AND TARGET Celix::log_admin) + #Note because of FetchContent_Declare needs CMake 3.19 or higher, + #so the Apache Celix Rust PoC needs CMake 3.19 or higher + cmake_minimum_required(VERSION 3.19) + include(FetchContent) FetchContent_Declare( Corrosion From e0f3c4c0a707c2c0e8e737d4629f0ff0efb87908 Mon Sep 17 00:00:00 2001 From: Pepijn Noltes Date: Wed, 6 Sep 2023 19:26:08 +0200 Subject: [PATCH 18/21] Revert " #599: Add CMake 3.19 requirement for Rust PoC" This reverts commit e3aa83a651a7c5c8b4edfcea08cf93ed17b74c39. --- misc/experimental/rust/CMakeLists.txt | 4 ---- 1 file changed, 4 deletions(-) diff --git a/misc/experimental/rust/CMakeLists.txt b/misc/experimental/rust/CMakeLists.txt index b407937e0..964ab62da 100644 --- a/misc/experimental/rust/CMakeLists.txt +++ b/misc/experimental/rust/CMakeLists.txt @@ -17,10 +17,6 @@ option(CELIX_RUST_EXPERIMENTAL "Enable experimental rust bundle" OFF) if (CELIX_RUST_EXPERIMENTAL AND TARGET Celix::shell_tui AND TARGET Celix::shell AND TARGET Celix::log_admin) - #Note because of FetchContent_Declare needs CMake 3.19 or higher, - #so the Apache Celix Rust PoC needs CMake 3.19 or higher - cmake_minimum_required(VERSION 3.19) - include(FetchContent) FetchContent_Declare( Corrosion From 9fd6da59b681fd415d8e3ff02aa5d0538d30b7f0 Mon Sep 17 00:00:00 2001 From: PengZheng Date: Sat, 16 Sep 2023 17:24:43 +0800 Subject: [PATCH 19/21] Fix rustc warning. --- misc/experimental/rust/celix/src/log_helper.rs | 3 +-- misc/experimental/rust/celix_bindings/build.rs | 2 -- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/misc/experimental/rust/celix/src/log_helper.rs b/misc/experimental/rust/celix/src/log_helper.rs index 72087eef1..16271c7b5 100644 --- a/misc/experimental/rust/celix/src/log_helper.rs +++ b/misc/experimental/rust/celix/src/log_helper.rs @@ -17,7 +17,6 @@ * under the License. */ -use std::ops::Deref; use std::sync::{Arc, Mutex, RwLock}; use super::BundleContext; @@ -83,7 +82,7 @@ impl LogHelper { if svc.log.is_none() { return; } - let log_fn = svc.deref().log.as_ref().unwrap(); + let log_fn = svc.log.as_ref().unwrap(); log_fn(svc.handle, level.into(), str_result.as_ptr()); } } diff --git a/misc/experimental/rust/celix_bindings/build.rs b/misc/experimental/rust/celix_bindings/build.rs index 6f3b1d0a6..374f4d454 100644 --- a/misc/experimental/rust/celix_bindings/build.rs +++ b/misc/experimental/rust/celix_bindings/build.rs @@ -17,8 +17,6 @@ * under the License. */ -extern crate bindgen; - use std::env; use std::error::Error; use std::fs::File; From dc81c7a6157c807745d1442305e4066dfcdee3c3 Mon Sep 17 00:00:00 2001 From: PengZheng Date: Sun, 17 Sep 2023 11:28:37 +0800 Subject: [PATCH 20/21] Update Rust edition, remove extern crates --- misc/experimental/rust/celix/Cargo.toml | 1 + misc/experimental/rust/celix/src/lib.rs | 2 -- misc/experimental/rust/celix/src/log_helper.rs | 2 +- misc/experimental/rust/celix_bindings/Cargo.toml | 1 + misc/experimental/rust/hello_world_activator/Cargo.toml | 1 + misc/experimental/rust/hello_world_activator/src/lib.rs | 2 -- misc/experimental/rust/rust_shell_api/Cargo.toml | 1 + misc/experimental/rust/rust_shell_api/src/lib.rs | 2 -- misc/experimental/rust/shell_command_bundle/Cargo.toml | 1 + misc/experimental/rust/shell_command_bundle/src/lib.rs | 4 ---- 10 files changed, 6 insertions(+), 11 deletions(-) diff --git a/misc/experimental/rust/celix/Cargo.toml b/misc/experimental/rust/celix/Cargo.toml index 4ae427660..fc3559706 100644 --- a/misc/experimental/rust/celix/Cargo.toml +++ b/misc/experimental/rust/celix/Cargo.toml @@ -18,6 +18,7 @@ [package] name = "celix" version = "0.0.1" +edition = '2021' [dependencies] celix_bindings = { path = "../celix_bindings" } diff --git a/misc/experimental/rust/celix/src/lib.rs b/misc/experimental/rust/celix/src/lib.rs index 390a62805..5ad567172 100644 --- a/misc/experimental/rust/celix/src/lib.rs +++ b/misc/experimental/rust/celix/src/lib.rs @@ -17,8 +17,6 @@ * under the License. */ -extern crate celix_bindings; - // 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 diff --git a/misc/experimental/rust/celix/src/log_helper.rs b/misc/experimental/rust/celix/src/log_helper.rs index 16271c7b5..e62238c3c 100644 --- a/misc/experimental/rust/celix/src/log_helper.rs +++ b/misc/experimental/rust/celix/src/log_helper.rs @@ -23,7 +23,7 @@ use super::BundleContext; use super::LogLevel; use celix_bindings::celix_log_service_t; -use ServiceTracker; +use crate::ServiceTracker; pub struct LogHelper { name: String, diff --git a/misc/experimental/rust/celix_bindings/Cargo.toml b/misc/experimental/rust/celix_bindings/Cargo.toml index b46868b9a..221002531 100644 --- a/misc/experimental/rust/celix_bindings/Cargo.toml +++ b/misc/experimental/rust/celix_bindings/Cargo.toml @@ -18,6 +18,7 @@ [package] name = "celix_bindings" version = "0.0.1" +edition = '2021' [build-dependencies] bindgen = "0.66.1" diff --git a/misc/experimental/rust/hello_world_activator/Cargo.toml b/misc/experimental/rust/hello_world_activator/Cargo.toml index 191c5e96d..378d5fb59 100644 --- a/misc/experimental/rust/hello_world_activator/Cargo.toml +++ b/misc/experimental/rust/hello_world_activator/Cargo.toml @@ -18,6 +18,7 @@ [package] name = "rust_bundle" version = "0.0.1" +edition = '2021' [dependencies] celix = { path = "../celix" } diff --git a/misc/experimental/rust/hello_world_activator/src/lib.rs b/misc/experimental/rust/hello_world_activator/src/lib.rs index 80d7b7208..d59212c28 100644 --- a/misc/experimental/rust/hello_world_activator/src/lib.rs +++ b/misc/experimental/rust/hello_world_activator/src/lib.rs @@ -17,8 +17,6 @@ * under the License. */ -extern crate celix; - use std::sync::Arc; use celix::BundleActivator; diff --git a/misc/experimental/rust/rust_shell_api/Cargo.toml b/misc/experimental/rust/rust_shell_api/Cargo.toml index 71c4d41b6..ed9c1c646 100644 --- a/misc/experimental/rust/rust_shell_api/Cargo.toml +++ b/misc/experimental/rust/rust_shell_api/Cargo.toml @@ -18,6 +18,7 @@ [package] name = "rust_shell_api" version = "0.0.1" +edition = '2021' [dependencies] celix = { path = "../celix" } diff --git a/misc/experimental/rust/rust_shell_api/src/lib.rs b/misc/experimental/rust/rust_shell_api/src/lib.rs index c75a7c092..18a6a4060 100644 --- a/misc/experimental/rust/rust_shell_api/src/lib.rs +++ b/misc/experimental/rust/rust_shell_api/src/lib.rs @@ -17,8 +17,6 @@ * under the License. */ -extern crate celix; - use celix::Error; pub const COMMAND_NAME: &str = "command.name"; pub const COMMAND_USAGE: &str = "command.usage"; diff --git a/misc/experimental/rust/shell_command_bundle/Cargo.toml b/misc/experimental/rust/shell_command_bundle/Cargo.toml index 0c11c1805..aba9f73b1 100644 --- a/misc/experimental/rust/shell_command_bundle/Cargo.toml +++ b/misc/experimental/rust/shell_command_bundle/Cargo.toml @@ -18,6 +18,7 @@ [package] name = "rust_shell_command_activator" version = "0.0.1" +edition = '2021' [dependencies] celix_bindings = { path = "../celix_bindings" } diff --git a/misc/experimental/rust/shell_command_bundle/src/lib.rs b/misc/experimental/rust/shell_command_bundle/src/lib.rs index 0889e386f..9bd7f174a 100644 --- a/misc/experimental/rust/shell_command_bundle/src/lib.rs +++ b/misc/experimental/rust/shell_command_bundle/src/lib.rs @@ -17,10 +17,6 @@ * under the License. */ -extern crate celix; -extern crate celix_bindings; -extern crate rust_shell_api; - use std::ffi::c_char; use std::ffi::c_void; use std::sync::Arc; From 4e91216c2dff5b9397134ca2a583cf4419870105 Mon Sep 17 00:00:00 2001 From: PengZheng Date: Sun, 17 Sep 2023 11:57:37 +0800 Subject: [PATCH 21/21] Added resolver in workspace to version 2 --- misc/experimental/rust/Cargo.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/misc/experimental/rust/Cargo.toml b/misc/experimental/rust/Cargo.toml index c8942eb6b..bd144ccfb 100644 --- a/misc/experimental/rust/Cargo.toml +++ b/misc/experimental/rust/Cargo.toml @@ -23,3 +23,4 @@ members = [ "rust_shell_api", "shell_command_bundle", ] +resolver = "2" \ No newline at end of file