From 5c3833b531c11505e96fa930fc82ce6945907165 Mon Sep 17 00:00:00 2001 From: Sebastian Goll Date: Fri, 1 Aug 2025 16:22:02 +0200 Subject: [PATCH 01/20] Switch to `master` branch of open62541 --- Cargo.lock | 33 +++++- Cargo.toml | 4 +- .../create_monitored_items.rs | 3 +- .../delete_monitored_items.rs | 3 +- src/async_subscription.rs | 6 +- src/client.rs | 5 +- src/server.rs | 109 ++++++++++++------ src/ua/certificate_verification.rs | 54 +++++---- src/ua/client.rs | 9 +- 9 files changed, 148 insertions(+), 78 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index e038fc49..276970f9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -270,6 +270,27 @@ dependencies = [ "serde", ] +[[package]] +name = "derive_more" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "093242cf7570c207c83073cf82f79706fe7b8317e98620a47d5be7c3d8497678" +dependencies = [ + "derive_more-impl", +] + +[[package]] +name = "derive_more-impl" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bda628edc44c4bb645fbe0f758797143e4e07926f7ebf4e9bdfbd3d2ce621df3" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "unicode-xid", +] + [[package]] name = "either" version = "1.9.0" @@ -606,6 +627,7 @@ name = "open62541" version = "0.9.3" dependencies = [ "anyhow", + "derive_more", "env_logger", "futures", "futures-channel", @@ -628,9 +650,8 @@ dependencies = [ [[package]] name = "open62541-sys" -version = "0.4.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c098dee418e964c2515e3c0ba97052503a8a81ac1adb8ea3b259d09238ffc853" +version = "0.4.18" +source = "git+https://github.com/sgoll/open62541-sys.git?branch=open62541-1.5#5e1d073ad4ffc7e9964157e4715f89f5c3717f3f" dependencies = [ "bindgen", "cc", @@ -1031,6 +1052,12 @@ version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" +[[package]] +name = "unicode-xid" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" + [[package]] name = "untrusted" version = "0.9.0" diff --git a/Cargo.toml b/Cargo.toml index e71d4283..240f8ad4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -17,10 +17,12 @@ categories = ["network-programming", "embedded", "api-bindings"] include = ["src/", "README.md", "CHANGELOG.md"] [dependencies] +derive_more = { version = "2.0.1", features = ["debug"] } futures-channel = "0.3.30" futures-core = { version = "0.3.30", default-features = false } log = "0.4.20" -open62541-sys = "0.4.17" +# FIXME: Revert before merge. +open62541-sys = { git = "https://github.com/sgoll/open62541-sys.git", branch = "open62541-1.5" } parking_lot = "0.12.4" paste = "1.0.14" serde = { version = "1.0.194", optional = true } diff --git a/src/async_monitored_item/create_monitored_items.rs b/src/async_monitored_item/create_monitored_items.rs index 152fd5b7..fde88610 100644 --- a/src/async_monitored_item/create_monitored_items.rs +++ b/src/async_monitored_item/create_monitored_items.rs @@ -225,11 +225,10 @@ unsafe extern "C" fn callback_c( _client: *mut UA_Client, userdata: *mut c_void, _request_id: UA_UInt32, - response: *mut c_void, + response: *mut UA_CreateMonitoredItemsResponse, ) { log::debug!("MonitoredItems_createDataChanges() completed"); - let response = response.cast::(); // SAFETY: Incoming pointer is valid for access. // PANIC: We expect pointer to be valid when good. let response = unsafe { response.as_ref() }.expect("response should be set"); diff --git a/src/async_monitored_item/delete_monitored_items.rs b/src/async_monitored_item/delete_monitored_items.rs index c2984661..eea26b0b 100644 --- a/src/async_monitored_item/delete_monitored_items.rs +++ b/src/async_monitored_item/delete_monitored_items.rs @@ -34,11 +34,10 @@ unsafe extern "C" fn callback_c( _client: *mut UA_Client, _userdata: *mut c_void, _request_id: UA_UInt32, - response: *mut c_void, + response: *mut UA_DeleteMonitoredItemsResponse, ) { log::debug!("MonitoredItems_delete() completed"); - let response = response.cast::(); // SAFETY: Incoming pointer is valid for access. // PANIC: We expect pointer to be valid when good. let response = unsafe { response.as_ref() }.expect("response should be set"); diff --git a/src/async_subscription.rs b/src/async_subscription.rs index 2a18d71d..3ab3ef2c 100644 --- a/src/async_subscription.rs +++ b/src/async_subscription.rs @@ -230,11 +230,10 @@ async fn create_subscription( _client: *mut UA_Client, userdata: *mut c_void, _request_id: UA_UInt32, - response: *mut c_void, + response: *mut UA_CreateSubscriptionResponse, ) { log::debug!("Subscriptions_create() completed"); - let response = response.cast::(); // SAFETY: Incoming pointer is valid for access. // PANIC: We expect pointer to be valid when good. let response = unsafe { response.as_ref() }.expect("response should be set"); @@ -296,11 +295,10 @@ fn delete_subscriptions(client: &ua::Client, request: &ua::DeleteSubscriptionsRe _client: *mut UA_Client, _userdata: *mut c_void, _request_id: UA_UInt32, - response: *mut c_void, + response: *mut UA_DeleteSubscriptionsResponse, ) { log::debug!("Subscriptions_delete() completed"); - let response = response.cast::(); // SAFETY: Incoming pointer is valid for access. // PANIC: We expect pointer to be valid when good. let response = unsafe { response.as_ref() }.expect("response should be set"); diff --git a/src/client.rs b/src/client.rs index f88d4e8f..c2cc9106 100644 --- a/src/client.rs +++ b/src/client.rs @@ -1,8 +1,7 @@ use std::{ffi::CString, ptr, time::Duration}; use open62541_sys::{ - UA_CertificateVerification_AcceptAll, UA_ClientConfig, UA_Client_connect, - UA_Client_getEndpoints, + UA_CertificateGroup_AcceptAll, UA_ClientConfig, UA_Client_connect, UA_Client_getEndpoints, }; use crate::{ua, DataType as _, Error, Result}; @@ -195,7 +194,7 @@ impl ClientBuilder { pub fn accept_all(mut self) -> Self { let config = self.config_mut(); unsafe { - UA_CertificateVerification_AcceptAll(&raw mut config.certificateVerification); + UA_CertificateGroup_AcceptAll(&raw mut config.certificateVerification); } self } diff --git a/src/server.rs b/src/server.rs index 9b677377..c0d11123 100644 --- a/src/server.rs +++ b/src/server.rs @@ -12,9 +12,11 @@ use std::{ time::Instant, }; +use derive_more::Debug; use open62541_sys::{ - UA_CertificateVerification_AcceptAll, UA_NodeId, UA_Server, UA_ServerConfig, - UA_Server_addDataSourceVariableNode, UA_Server_addMethodNodeEx, UA_Server_addNamespace, + UA_CertificateGroup_AcceptAll, UA_NodeId, UA_Server, UA_ServerConfig, + UA_Server_addCallbackValueSourceVariableNode, UA_Server_addMethodNodeEx, + UA_Server_addNamespace, UA_Server_addNode_begin, UA_Server_addNode_finish, UA_Server_addReference, UA_Server_browse, UA_Server_browseNext, UA_Server_browseRecursive, UA_Server_browseSimplifiedBrowsePath, UA_Server_createEvent, UA_Server_deleteNode, UA_Server_deleteReference, UA_Server_getConfig, UA_Server_getNamespaceByIndex, @@ -22,7 +24,7 @@ use open62541_sys::{ UA_Server_readObjectProperty, UA_Server_runUntilInterrupt, UA_Server_run_iterate, UA_Server_run_shutdown, UA_Server_run_startup, UA_Server_translateBrowsePathToNodeIds, UA_Server_triggerEvent, UA_Server_writeDataValue, UA_Server_writeObjectProperty, - UA_Server_writeValue, __UA_Server_addNode, UA_STATUSCODE_BADNOTFOUND, + UA_Server_writeValue, UA_STATUSCODE_BADNOTFOUND, }; use parking_lot::{Condvar, Mutex, MutexGuard}; @@ -194,8 +196,8 @@ impl ServerBuilder { pub fn accept_all(mut self) -> Self { let config = self.config_mut(); unsafe { - UA_CertificateVerification_AcceptAll(&raw mut config.secureChannelPKI); - UA_CertificateVerification_AcceptAll(&raw mut config.sessionPKI); + UA_CertificateGroup_AcceptAll(&raw mut config.secureChannelPKI); + UA_CertificateGroup_AcceptAll(&raw mut config.sessionPKI); } self } @@ -263,8 +265,8 @@ impl ServerBuilder { let config = self.config_mut(); // PANIC: We never set lifecycle hooks elsewhere in config. - debug_assert!(config.nodeLifecycle.destructor.is_none()); - config.nodeLifecycle.destructor = Some(destructor_c); + debug_assert!(unsafe { &*config.nodeLifecycle }.destructor.is_none()); + unsafe { &mut *config.nodeLifecycle }.destructor = Some(destructor_c); let Self { config, @@ -365,6 +367,7 @@ enum RunnerStateInner { #[derive(Debug)] struct ServerConfigGuard<'a> { + #[debug(skip)] config: &'a UA_ServerConfig, guard: RunnerStateGuard<'a>, } @@ -609,18 +612,20 @@ impl Server { let mut out_new_node_id = ua::NodeId::null(); let status_code = ua::StatusCode::new(unsafe { - __UA_Server_addNode( + UA_Server_addNode_begin( // SAFETY: Cast to `mut` pointer, function is marked `UA_THREADSAFE`. self.server.as_ptr().cast_mut(), // Passing ownership is trivial with primitive value (`u32`). attributes.node_class().clone().into_raw(), - requested_new_node_id.as_ptr(), - parent_node_id.as_ptr(), - reference_type_id.as_ptr(), - // TODO: Verify that `__UA_Server_addNode()` takes ownership. + // TODO: Verify that `UA_Server_addNode_begin()` does not take ownership. + DataType::to_raw_copy(&requested_new_node_id), + DataType::to_raw_copy(&parent_node_id), + DataType::to_raw_copy(&reference_type_id), + // TODO: Verify that `UA_Server_addNode_begin()` takes ownership. browse_name.clone().into_raw(), - type_definition.as_ptr(), - attributes.as_node_attributes().as_ptr(), + // TODO: Verify that `UA_Server_addNode_begin()` does not take ownership. + DataType::to_raw_copy(&type_definition), + attributes.as_node_attributes().as_ptr().cast(), attributes.attribute_type(), context.map_or(ptr::null_mut(), NodeContext::leak), out_new_node_id.as_mut_ptr(), @@ -628,6 +633,16 @@ impl Server { }); Error::verify_good(&status_code)?; + let status_code = ua::StatusCode::new(unsafe { + UA_Server_addNode_finish( + // SAFETY: Cast to `mut` pointer, function is marked `UA_THREADSAFE`. + self.server.as_ptr().cast_mut(), + // TODO: Verify that `UA_Server_addNode_finish()` does not take ownership. + DataType::to_raw_copy(&out_new_node_id), + ) + }); + Error::verify_good(&status_code)?; + Ok(out_new_node_id) } @@ -656,18 +671,20 @@ impl Server { let mut out_new_node_id = ua::NodeId::null(); let status_code = ua::StatusCode::new(unsafe { - __UA_Server_addNode( + UA_Server_addNode_begin( // SAFETY: Cast to `mut` pointer, function is marked `UA_THREADSAFE`. self.server.as_ptr().cast_mut(), // Passing ownership is trivial with primitive value (`u32`). ua::NodeClass::OBJECT.into_raw(), - requested_new_node_id.as_ptr(), - parent_node_id.as_ptr(), - reference_type_id.as_ptr(), - // TODO: Verify that `__UA_Server_addNode()` takes ownership. + // TODO: Verify that `UA_Server_addNode_begin()` does not take ownership. + DataType::to_raw_copy(&requested_new_node_id), + DataType::to_raw_copy(&parent_node_id), + DataType::to_raw_copy(&reference_type_id), + // TODO: Verify that `UA_Server_addNode_begin()` takes ownership. browse_name.into_raw(), - type_definition.as_ptr(), - attributes.as_node_attributes().as_ptr(), + // TODO: Verify that `UA_Server_addNode_begin()` does not take ownership. + DataType::to_raw_copy(&type_definition), + attributes.as_node_attributes().as_ptr().cast(), ua::ObjectAttributes::data_type(), ptr::null_mut(), out_new_node_id.as_mut_ptr(), @@ -675,6 +692,16 @@ impl Server { }); Error::verify_good(&status_code)?; + let status_code = ua::StatusCode::new(unsafe { + UA_Server_addNode_finish( + // SAFETY: Cast to `mut` pointer, function is marked `UA_THREADSAFE`. + self.server.as_ptr().cast_mut(), + // TODO: Verify that `UA_Server_addNode_finish()` does not take ownership. + DataType::to_raw_copy(&out_new_node_id), + ) + }); + Error::verify_good(&status_code)?; + Ok(out_new_node_id) } @@ -703,18 +730,20 @@ impl Server { let mut out_new_node_id = ua::NodeId::null(); let status_code = ua::StatusCode::new(unsafe { - __UA_Server_addNode( + UA_Server_addNode_begin( // SAFETY: Cast to `mut` pointer, function is marked `UA_THREADSAFE`. self.server.as_ptr().cast_mut(), // Passing ownership is trivial with primitive value (`u32`). ua::NodeClass::VARIABLE.into_raw(), - requested_new_node_id.as_ptr(), - parent_node_id.as_ptr(), - reference_type_id.as_ptr(), - // TODO: Verify that `__UA_Server_addNode()` takes ownership. + // TODO: Verify that `UA_Server_addNode_begin()` does not take ownership. + DataType::to_raw_copy(&requested_new_node_id), + DataType::to_raw_copy(&parent_node_id), + DataType::to_raw_copy(&reference_type_id), + // TODO: Verify that `UA_Server_addNode_begin()` takes ownership. browse_name.into_raw(), - type_definition.as_ptr(), - attributes.as_node_attributes().as_ptr(), + // TODO: Verify that `UA_Server_addNode_begin()` does not take ownership. + DataType::to_raw_copy(&type_definition), + attributes.as_node_attributes().as_ptr().cast(), ua::VariableAttributes::data_type(), ptr::null_mut(), out_new_node_id.as_mut_ptr(), @@ -722,6 +751,16 @@ impl Server { }); Error::verify_good(&status_code)?; + let status_code = ua::StatusCode::new(unsafe { + UA_Server_addNode_finish( + // SAFETY: Cast to `mut` pointer, function is marked `UA_THREADSAFE`. + self.server.as_ptr().cast_mut(), + // TODO: Verify that `UA_Server_addNode_finish()` does not take ownership. + DataType::to_raw_copy(&out_new_node_id), + ) + }); + Error::verify_good(&status_code)?; + Ok(out_new_node_id) } @@ -756,20 +795,20 @@ impl Server { // SAFETY: We store `node_context` inside the node to keep `data_source` alive. let (data_source, node_context) = unsafe { data_source::wrap_data_source(data_source) }; let status_code = ua::StatusCode::new(unsafe { - UA_Server_addDataSourceVariableNode( + UA_Server_addCallbackValueSourceVariableNode( // SAFETY: Cast to `mut` pointer, function is marked `UA_THREADSAFE`. self.server.as_ptr().cast_mut(), - // TODO: Verify that `UA_Server_addDataSourceVariableNode()` takes ownership. + // TODO: Verify that `UA_Server_addCallbackValueSourceVariableNode()` takes ownership. requested_new_node_id.into_raw(), - // TODO: Verify that `UA_Server_addDataSourceVariableNode()` takes ownership. + // TODO: Verify that `UA_Server_addCallbackValueSourceVariableNode()` takes ownership. parent_node_id.into_raw(), - // TODO: Verify that `UA_Server_addDataSourceVariableNode()` takes ownership. + // TODO: Verify that `UA_Server_addCallbackValueSourceVariableNode()` takes ownership. reference_type_id.into_raw(), - // TODO: Verify that `UA_Server_addDataSourceVariableNode()` takes ownership. + // TODO: Verify that `UA_Server_addCallbackValueSourceVariableNode()` takes ownership. browse_name.into_raw(), - // TODO: Verify that `UA_Server_addDataSourceVariableNode()` takes ownership. + // TODO: Verify that `UA_Server_addCallbackValueSourceVariableNode()` takes ownership. type_definition.into_raw(), - // TODO: Verify that `UA_Server_addDataSourceVariableNode()` takes ownership. + // TODO: Verify that `UA_Server_addCallbackValueSourceVariableNode()` takes ownership. attributes.into_raw(), data_source, node_context.leak(), diff --git a/src/ua/certificate_verification.rs b/src/ua/certificate_verification.rs index dd6e6687..76a64d13 100644 --- a/src/ua/certificate_verification.rs +++ b/src/ua/certificate_verification.rs @@ -3,16 +3,16 @@ use std::{ ptr, }; +use derive_more::Debug; use open62541_sys::{ - UA_ByteString, UA_CertificateVerification, UA_CertificateVerification_AcceptAll, UA_StatusCode, - UA_String, + UA_ByteString, UA_CertificateGroup, UA_CertificateGroup_AcceptAll, UA_StatusCode, UA_String, }; use crate::{ua, CustomCertificateVerification, DataType, Userdata}; -/// Wrapper for [`UA_CertificateVerification`] from [`open62541_sys`]. +/// Wrapper for [`UA_CertificateGroup`] from [`open62541_sys`]. #[derive(Debug)] -pub struct CertificateVerification(UA_CertificateVerification); +pub struct CertificateVerification(#[debug(skip)] UA_CertificateGroup); impl CertificateVerification { /// Creates certificate verification with all checks disabled. @@ -24,17 +24,18 @@ impl CertificateVerification { let mut certificate_verification = Self::init(); // SAFETY: Certificate verification is null, but that is valid. unsafe { - UA_CertificateVerification_AcceptAll(certificate_verification.as_mut_ptr()); + UA_CertificateGroup_AcceptAll(certificate_verification.as_mut_ptr()); } certificate_verification } /// Creates certificate verification with custom callbacks. - pub fn custom(certificate_verification: impl CustomCertificateVerification + 'static) -> Self { + #[expect(dead_code, reason = "work in progress")] + pub fn custom(_certificate_verification: impl CustomCertificateVerification + 'static) -> Self { type Ud = Userdata>; unsafe extern "C" fn verify_certificate_c( - cv: *const UA_CertificateVerification, + cv: *const UA_CertificateGroup, certificate: *const UA_ByteString, ) -> UA_StatusCode { // SAFETY: Reference is used only for the remainder of this function. @@ -49,7 +50,7 @@ impl CertificateVerification { } unsafe extern "C" fn verify_application_uri_c( - cv: *const UA_CertificateVerification, + cv: *const UA_CertificateGroup, certificate: *const UA_ByteString, application_uri: *const UA_String, ) -> UA_StatusCode { @@ -70,23 +71,26 @@ impl CertificateVerification { status_code.into_raw() } - unsafe extern "C" fn clear_c(cv: *mut UA_CertificateVerification) { + unsafe extern "C" fn clear_c(cv: *mut UA_CertificateGroup) { // Reclaim ownership of certificate verification and drop it. // SAFETY: We use the user data only when it is still alive. let _unused = unsafe { Ud::consume((*cv).context) }; } - let inner = UA_CertificateVerification { - context: Ud::prepare(Box::new(certificate_verification)), - verifyCertificate: Some(verify_certificate_c), - verifyApplicationURI: Some(verify_application_uri_c), - getExpirationDate: None, - getSubjectName: None, - clear: Some(clear_c), - logging: ptr::null_mut(), - }; + // FIXME: Implement `UA_CertificateGroup`. + unimplemented!() - unsafe { Self::from_raw(inner) } + // let inner = UA_CertificateGroup { + // context: Ud::prepare(Box::new(certificate_verification)), + // verifyCertificate: Some(verify_certificate_c), + // verifyApplicationURI: Some(verify_application_uri_c), + // getExpirationDate: None, + // getSubjectName: None, + // clear: Some(clear_c), + // logging: ptr::null_mut(), + // }; + + // unsafe { Self::from_raw(inner) } } /// Creates wrapper by taking ownership of value. @@ -98,7 +102,7 @@ impl CertificateVerification { /// Ownership of the value passes to `Self`. This must only be used for values that are not /// contained within other values that may be dropped. #[must_use] - pub(crate) const unsafe fn from_raw(src: UA_CertificateVerification) -> Self { + pub(crate) const unsafe fn from_raw(src: UA_CertificateGroup) -> Self { Self(src) } @@ -112,7 +116,7 @@ impl CertificateVerification { #[expect(clippy::allow_attributes, reason = "non-static condition")] #[allow(clippy::missing_const_for_fn, reason = "unsupported before Rust 1.87")] #[must_use] - pub(crate) fn into_raw(self) -> UA_CertificateVerification { + pub(crate) fn into_raw(self) -> UA_CertificateGroup { // Use `ManuallyDrop` to avoid double-free even when added code might cause panic. See // documentation of `mem::forget()` for details. let this = ManuallyDrop::new(self); @@ -125,7 +129,7 @@ impl CertificateVerification { /// This initializes the value and makes all attributes well-defined. Additional attributes may /// need to be initialized for the value to be actually useful afterwards. pub(crate) const fn init() -> Self { - let inner = MaybeUninit::::zeroed(); + let inner = MaybeUninit::::zeroed(); // SAFETY: Zero-initialized memory is a valid certificate verification. let inner = unsafe { inner.assume_init() }; // SAFETY: We pass a value without pointers to it into `Self`. @@ -140,7 +144,7 @@ impl CertificateVerification { /// The logging reference will be transferred from the old to the new certificate verification. /// /// After this, it is the responsibility of `dst` to eventually clean up the data. - pub(crate) fn move_into_raw(self, dst: &mut UA_CertificateVerification) { + pub(crate) fn move_into_raw(self, dst: &mut UA_CertificateGroup) { // Move certificate verification into target, transferring ownership. let orig = mem::replace(dst, self.into_raw()); // Take ownership of previously set certificate verification in order to drop it. @@ -161,7 +165,7 @@ impl CertificateVerification { #[must_use] #[expect(clippy::allow_attributes, reason = "non-static condition")] #[allow(clippy::missing_const_for_fn, reason = "unsupported before Rust 1.87")] - pub(crate) unsafe fn as_mut(&mut self) -> &mut UA_CertificateVerification { + pub(crate) unsafe fn as_mut(&mut self) -> &mut UA_CertificateGroup { &mut self.0 } @@ -174,7 +178,7 @@ impl CertificateVerification { #[must_use] #[expect(clippy::allow_attributes, reason = "non-static condition")] #[allow(clippy::missing_const_for_fn, reason = "unsupported before Rust 1.87")] - pub(crate) unsafe fn as_mut_ptr(&mut self) -> *mut UA_CertificateVerification { + pub(crate) unsafe fn as_mut_ptr(&mut self) -> *mut UA_CertificateGroup { &raw mut self.0 } } diff --git a/src/ua/client.rs b/src/ua/client.rs index eb1cc30c..382bd1d9 100644 --- a/src/ua/client.rs +++ b/src/ua/client.rs @@ -1,8 +1,8 @@ use std::ptr::NonNull; use open62541_sys::{ - UA_Client, UA_Client_delete, UA_Client_disconnect, UA_Client_getConfig, UA_Client_getContext, - UA_Client_getState, UA_Client_new, UA_Client_newWithConfig, + UA_Client, UA_Client_delete, UA_Client_disconnect, UA_Client_getConfig, UA_Client_getState, + UA_Client_new, UA_Client_newWithConfig, }; use crate::{ua, ClientContext, DataType as _, Error}; @@ -118,7 +118,10 @@ impl Drop for Client { // Fetch context pointer before deleting client below, but free associated memory only after // client has completely shut down. - let context = unsafe { UA_Client_getContext(self.as_mut_ptr()) }.cast::(); + let context = unsafe { UA_Client_getConfig(self.as_mut_ptr()).as_ref() } + .expect("require client config") + .clientContext + .cast::(); // `UA_Client_delete()` matches `UA_Client_new()`. This may block (!) whenever the client is // still connected, for as long as it takes to take down the connection. This can be avoided From 248664fe4b68c20fd7d31366202085bca1aab23a Mon Sep 17 00:00:00 2001 From: Sebastian Goll Date: Thu, 28 Aug 2025 18:12:28 +0200 Subject: [PATCH 02/20] Fix change in handling of variadic log messages --- src/ua/data_types/byte_string.rs | 11 ++++ src/ua/data_types/string.rs | 50 +++++++++++++++- src/ua/logger/rust_log.rs | 100 ++++++++++--------------------- 3 files changed, 93 insertions(+), 68 deletions(-) diff --git a/src/ua/data_types/byte_string.rs b/src/ua/data_types/byte_string.rs index 815bd240..189b321f 100644 --- a/src/ua/data_types/byte_string.rs +++ b/src/ua/data_types/byte_string.rs @@ -105,6 +105,17 @@ impl ByteString { unsafe { self.as_bytes().unwrap_unchecked() } } + /// Converts byte string into string. + /// + /// This is lossless because the underlying types of OPC UA strings and byte strings are exactly + /// the same, only with different semantics. + #[must_use] + pub(crate) fn into_string(self) -> ua::String { + let string = self.into_raw(); + // SAFETY: We still own this string. + unsafe { ua::String::from_raw(string) } + } + #[must_use] fn array_value(&self) -> ArrayValue { // Internally, `open62541` represents strings as `Byte` array and has the same special cases diff --git a/src/ua/data_types/string.rs b/src/ua/data_types/string.rs index 00cc8cc3..10c187c1 100644 --- a/src/ua/data_types/string.rs +++ b/src/ua/data_types/string.rs @@ -1,6 +1,6 @@ use std::{ffi::CString, fmt, ptr, slice, str}; -use open62541_sys::UA_String_fromChars; +use open62541_sys::{UA_ByteString_allocBuffer, UA_String_fromChars}; use crate::{ua, ArrayValue, DataType as _, Error}; @@ -24,6 +24,24 @@ impl String { Ok(Self(str)) } + /// Creates uninitialized string of specific length. + /// + /// This should be used with caution: the uninitialized contents may contain leaked data and may + /// not be valid UTF-8. + #[must_use] + pub(crate) fn uninit(len: usize) -> Self { + let mut str = ua::ByteString::init(); + // We let `UA_ByteString_allocBuffer()` do the string allocation. + let status_code = + ua::StatusCode::new(unsafe { UA_ByteString_allocBuffer(str.as_mut_ptr(), len) }); + // PANIC: The only possible errors here are out-of-memory. + assert!( + status_code.is_good(), + "byte string should have been created" + ); + str.into_string() + } + /// Creates invalid string (as defined by OPC UA). // TODO: The OPC UA specification calls invalid strings "null". Consider changing this to match. pub(crate) fn invalid() -> Self { @@ -37,6 +55,22 @@ impl String { Self::new("").unwrap() } + /// Gets string length. + /// + /// This may return [`None`] when the string itself is invalid (as defined by OPC UA). + #[expect(dead_code, reason = "unused for now")] + #[must_use] + pub(crate) fn len(&self) -> Option { + match self.array_value() { + ArrayValue::Invalid => None, + ArrayValue::Empty => Some(0), + ArrayValue::Valid(_) => { + // `self.0.data` is valid, so we may use `self.0.length` now. + Some(self.0.length) + } + } + } + /// Checks if string is invalid. /// /// The invalid state is defined by OPC UA. It is a third state which is distinct from empty and @@ -69,6 +103,20 @@ impl String { } } + #[must_use] + pub(crate) fn as_mut_bytes(&mut self) -> Option<&mut [u8]> { + // Internally, `open62541` represents strings as `Byte` array and has the same special cases + // as regular arrays, i.e. empty and invalid states. + match self.array_value() { + ArrayValue::Invalid => None, + ArrayValue::Empty => Some(&mut []), + ArrayValue::Valid(data) => { + // `self.0.data` is valid, so we may use `self.0.length` now. + Some(unsafe { slice::from_raw_parts_mut(data.as_ptr(), self.0.length) }) + } + } + } + /// Returns string contents as string slice. /// /// This may return [`None`] when the string itself is invalid (as defined by OPC UA) or when it diff --git a/src/ua/logger/rust_log.rs b/src/ua/logger/rust_log.rs index b2e83dfd..8ee2e515 100644 --- a/src/ua/logger/rust_log.rs +++ b/src/ua/logger/rust_log.rs @@ -1,11 +1,11 @@ use std::{ - ffi::{c_char, c_void, CStr}, + ffi::{c_char, c_void}, ptr, }; -use open62541_sys::{vsnprintf_va_copy, vsnprintf_va_end, UA_LogCategory, UA_LogLevel, UA_Logger}; +use open62541_sys::{UA_LogCategory, UA_LogLevel, UA_Logger, UA_String_vformat}; -use crate::ua; +use crate::{ua, DataType as _, Error, Result}; const LOG_TARGET: &str = "open62541_sys"; @@ -21,14 +21,15 @@ pub(crate) fn logger() -> ua::Logger { msg: *const c_char, args: open62541_sys::va_list_, ) { - let Some(msg) = format_message(msg, args) else { - log::error!(target: LOG_TARGET, "Unknown log message"); - return; + let msg = match format_message(msg, args) { + Ok(msg) => msg, + Err(error) => { + log::error!(target: LOG_TARGET, "Unknown log message: {error}"); + return; + } }; - let msg = CStr::from_bytes_with_nul(&msg) - .unwrap_or(c"Invalid log message") - .to_string_lossy(); + let msg = msg.as_str().unwrap_or("Invalid log message"); if level == UA_LogLevel::UA_LOGLEVEL_FATAL { // Without fatal level in `log`, fall back to error. @@ -89,70 +90,35 @@ pub(crate) fn logger() -> ua::Logger { unsafe { ua::Logger::from_raw(logger) } } -/// Initial buffer size when formatting messages. -const FORMAT_MESSAGE_DEFAULT_BUFFER_LEN: usize = 128; - -/// Maximum buffer size when formatting messages. -const FORMAT_MESSAGE_MAXIMUM_BUFFER_LEN: usize = 65536; +/// Buffer size when formatting messages. +// This matches the limit used by default implementations `ua_log_stdout.h` and `ua_log_syslog.h`. +const FORMAT_MESSAGE_BUFFER_LEN: usize = 512; /// Formats message with `vprintf` library calls. /// -/// This returns the formatted message with a trailing NUL byte, or `None` when formatting fails. A -/// long message may be truncated (see [`FORMAT_MESSAGE_MAXIMUM_BUFFER_LEN`] for details); its last -/// characters will be replaced with `...` to indicate this. -fn format_message(msg: *const c_char, args: open62541_sys::va_list_) -> Option> { - // Delegate string formatting to `vsnprintf()`, the length-checked string buffer variant of the - // variadic `vprintf` family. - // - // We use the custom `vsnprintf_va_copy()` provided by `open62541_sys`. This copies the va args - // and requires an explicit call to `vsnprintf_va_end()` afterwards. - - // Allocate default buffer first. Only when the message doesn't fit, we need to allocate larger - // buffer below. - let mut msg_buffer: Vec = vec![0; FORMAT_MESSAGE_DEFAULT_BUFFER_LEN]; - loop { - let result = unsafe { - vsnprintf_va_copy( - msg_buffer.as_mut_ptr().cast::(), - msg_buffer.len(), - msg, - args, - ) - }; - let Ok(msg_len) = usize::try_from(result) else { - // Negative result is an error in the format string. Nothing we can do. - debug_assert!(result < 0); - // Free the `va_list` argument that is no consumed by `vsnprintf()`! - unsafe { vsnprintf_va_end(args) } - return None; - }; - let buffer_len = msg_len + 1; - if buffer_len > msg_buffer.len() { - // Last byte must always be the NUL terminator, even if the message - // doesn't fit into the buffer. - debug_assert_eq!(msg_buffer.last(), Some(&0)); - if msg_buffer.len() < FORMAT_MESSAGE_MAXIMUM_BUFFER_LEN { - // Allocate larger buffer and try again. - msg_buffer.resize(FORMAT_MESSAGE_MAXIMUM_BUFFER_LEN, 0); - continue; - } - // Message is too large to format. Truncate the message by ending it with `...`. - for char in msg_buffer.iter_mut().rev().skip(1).take(3) { +/// This returns the formatted message as string, or `Err` when formatting fails. A long message is +/// truncated (see [`FORMAT_MESSAGE_BUFFER_LEN`]); its last characters will be replaced with `...`. +fn format_message(msg: *const c_char, args: open62541_sys::va_list_) -> Result { + // With non-zero length, `UA_String_vformat()` fills the given string directly. For zero length + // strings, the result would be dynamically allocated, but this risks handling incredibly large + // amounts of memory in the log handler which we want to avoid here. + let mut msg_buffer = ua::String::uninit(FORMAT_MESSAGE_BUFFER_LEN); + + let status_code = + ua::StatusCode::new(unsafe { UA_String_vformat(msg_buffer.as_mut_ptr(), msg, args) }); + if status_code == ua::StatusCode::BADENCODINGLIMITSEXCEEDED { + // Message is too large to format. We could try again with a larger buffer, but since we do + // not know the required length (`UA_String_vformat()` doesn't return it), we would have to + // guess (e.g., doubling the length until the message fits). Simply truncate the message by + // ending it with `...` instead to ensure constant-time operation. + if let Some(msg_buffer) = msg_buffer.as_mut_bytes() { + for char in msg_buffer.iter_mut().rev().take(3) { *char = b'.'; } - } else { - // Message fits into the buffer. Make sure that `from_bytes_with_nul()` - // sees the expected single NUL terminator in the final position. - msg_buffer.truncate(buffer_len); } - break; + } else { + Error::verify_good(&status_code)?; } - // Free the `va_list` argument that is not consumed by `vsnprintf()`! - unsafe { vsnprintf_va_end(args) } - - // Last byte must always be the NUL terminator. - debug_assert_eq!(msg_buffer.last(), Some(&0)); - - Some(msg_buffer) + Ok(msg_buffer) } From 9a794c5bf1a8d02510eb6f1ce52969744c6e07d2 Mon Sep 17 00:00:00 2001 From: Sebastian Goll Date: Fri, 29 Aug 2025 12:57:59 +0200 Subject: [PATCH 03/20] Add workaround for unset node lifecycle config --- src/server.rs | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/server.rs b/src/server.rs index c0d11123..4f7ae83b 100644 --- a/src/server.rs +++ b/src/server.rs @@ -264,9 +264,12 @@ impl ServerBuilder { let config = self.config_mut(); - // PANIC: We never set lifecycle hooks elsewhere in config. - debug_assert!(unsafe { &*config.nodeLifecycle }.destructor.is_none()); - unsafe { &mut *config.nodeLifecycle }.destructor = Some(destructor_c); + // FIXME: Initialize lifecycle hooks object. + if !config.nodeLifecycle.is_null() { + // PANIC: We never set lifecycle hooks elsewhere in config. + debug_assert!(unsafe { &*config.nodeLifecycle }.destructor.is_none()); + unsafe { &mut *config.nodeLifecycle }.destructor = Some(destructor_c); + } let Self { config, From f270f6db6ff3bd9e58c31e9b9ac918a54bfbc23d Mon Sep 17 00:00:00 2001 From: Sebastian Goll Date: Fri, 29 Aug 2025 15:52:44 +0200 Subject: [PATCH 04/20] Skip unnecessary log formatting, include log category --- src/ua/logger/rust_log.rs | 78 ++++++++++++++++++++++++++------------- 1 file changed, 52 insertions(+), 26 deletions(-) diff --git a/src/ua/logger/rust_log.rs b/src/ua/logger/rust_log.rs index 8ee2e515..5f095023 100644 --- a/src/ua/logger/rust_log.rs +++ b/src/ua/logger/rust_log.rs @@ -3,51 +3,77 @@ use std::{ ptr, }; +use log::Level; use open62541_sys::{UA_LogCategory, UA_LogLevel, UA_Logger, UA_String_vformat}; use crate::{ua, DataType as _, Error, Result}; +// This matches the crate name. const LOG_TARGET: &str = "open62541_sys"; +// These match the category names from `ua_log_stdout.c` and `ua_log_syslog.c`. +const LOG_CATEGORY_NETWORK: &str = "network"; +const LOG_CATEGORY_SECURECHANNEL: &str = "channel"; +const LOG_CATEGORY_SESSION: &str = "session"; +const LOG_CATEGORY_SERVER: &str = "server"; +const LOG_CATEGORY_CLIENT: &str = "client"; +const LOG_CATEGORY_USERLAND: &str = "userland"; +const LOG_CATEGORY_SECURITYPOLICY: &str = "security"; +const LOG_CATEGORY_EVENTLOOP: &str = "eventloop"; +const LOG_CATEGORY_PUBSUB: &str = "pubsub"; +const LOG_CATEGORY_DISCOVERY: &str = "discovery"; +const LOG_CATEGORY_UNKNOWN: &str = "unknown"; + /// Creates logger that forwards to the `log` crate. /// -/// We can use this to prevent `open62541` from installing its own default logger (which outputs any +/// We can use this to prevent `open62541` from installing its own default logger (which outputs all /// logs to stdout/stderr directly). pub(crate) fn logger() -> ua::Logger { unsafe extern "C" fn log_c( _log_context: *mut c_void, level: UA_LogLevel, - _category: UA_LogCategory, + category: UA_LogCategory, msg: *const c_char, args: open62541_sys::va_list_, ) { - let msg = match format_message(msg, args) { - Ok(msg) => msg, - Err(error) => { - log::error!(target: LOG_TARGET, "Unknown log message: {error}"); - return; - } - }; - - let msg = msg.as_str().unwrap_or("Invalid log message"); - - if level == UA_LogLevel::UA_LOGLEVEL_FATAL { + let level = match level { // Without fatal level in `log`, fall back to error. - log::error!(target: LOG_TARGET, "{msg}"); - } else if level == UA_LogLevel::UA_LOGLEVEL_ERROR { - log::error!(target: LOG_TARGET, "{msg}"); - } else if level == UA_LogLevel::UA_LOGLEVEL_WARNING { - log::warn!(target: LOG_TARGET, "{msg}"); - } else if level == UA_LogLevel::UA_LOGLEVEL_INFO { - log::info!(target: LOG_TARGET, "{msg}"); - } else if level == UA_LogLevel::UA_LOGLEVEL_DEBUG { - log::debug!(target: LOG_TARGET, "{msg}"); - } else if level == UA_LogLevel::UA_LOGLEVEL_TRACE { - log::trace!(target: LOG_TARGET, "{msg}"); - } else { + UA_LogLevel::UA_LOGLEVEL_FATAL | UA_LogLevel::UA_LOGLEVEL_ERROR => Level::Error, + UA_LogLevel::UA_LOGLEVEL_WARNING => Level::Warn, + UA_LogLevel::UA_LOGLEVEL_INFO => Level::Info, + UA_LogLevel::UA_LOGLEVEL_DEBUG => Level::Debug, + UA_LogLevel::UA_LOGLEVEL_TRACE => Level::Trace, // Handle unexpected level by escalating to error. - log::error!(target: LOG_TARGET, "{msg}"); + #[expect(clippy::match_same_arms, reason = "distinction of cases")] + _ => Level::Error, + }; + + if !log::log_enabled!(target: LOG_TARGET, level) { + // Bail out early to skip formatting message. + return; } + + let msg = format_message(msg, args); + let msg = match msg { + Ok(ref msg) => msg.as_str().unwrap_or("Invalid log message"), + Err(_) => "Unknown log message", + }; + + let category = match category { + UA_LogCategory::UA_LOGCATEGORY_NETWORK => LOG_CATEGORY_NETWORK, + UA_LogCategory::UA_LOGCATEGORY_SECURECHANNEL => LOG_CATEGORY_SECURECHANNEL, + UA_LogCategory::UA_LOGCATEGORY_SESSION => LOG_CATEGORY_SESSION, + UA_LogCategory::UA_LOGCATEGORY_SERVER => LOG_CATEGORY_SERVER, + UA_LogCategory::UA_LOGCATEGORY_CLIENT => LOG_CATEGORY_CLIENT, + UA_LogCategory::UA_LOGCATEGORY_USERLAND => LOG_CATEGORY_USERLAND, + UA_LogCategory::UA_LOGCATEGORY_SECURITYPOLICY => LOG_CATEGORY_SECURITYPOLICY, + UA_LogCategory::UA_LOGCATEGORY_EVENTLOOP => LOG_CATEGORY_EVENTLOOP, + UA_LogCategory::UA_LOGCATEGORY_PUBSUB => LOG_CATEGORY_PUBSUB, + UA_LogCategory::UA_LOGCATEGORY_DISCOVERY => LOG_CATEGORY_DISCOVERY, + _ => LOG_CATEGORY_UNKNOWN, + }; + + log::log!(target: LOG_TARGET, level, "({category}) {msg}"); } unsafe extern "C" fn clear_c(logger: *mut UA_Logger) { From 358835ff02c840c8f202b4dbb94a1b384b11a947 Mon Sep 17 00:00:00 2001 From: Sebastian Goll Date: Mon, 1 Sep 2025 13:02:30 +0200 Subject: [PATCH 05/20] Fix handling of `config.nodeLifecycle` --- src/server.rs | 87 +++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 74 insertions(+), 13 deletions(-) diff --git a/src/server.rs b/src/server.rs index 4f7ae83b..7b350a26 100644 --- a/src/server.rs +++ b/src/server.rs @@ -7,14 +7,14 @@ mod node_types; use std::{ any::Any, ffi::{c_void, CString}, - ptr, + mem, ptr, sync::Arc, time::Instant, }; use derive_more::Debug; use open62541_sys::{ - UA_CertificateGroup_AcceptAll, UA_NodeId, UA_Server, UA_ServerConfig, + UA_CertificateGroup_AcceptAll, UA_GlobalNodeLifecycle, UA_NodeId, UA_Server, UA_ServerConfig, UA_Server_addCallbackValueSourceVariableNode, UA_Server_addMethodNodeEx, UA_Server_addNamespace, UA_Server_addNode_begin, UA_Server_addNode_finish, UA_Server_addReference, UA_Server_browse, UA_Server_browseNext, UA_Server_browseRecursive, @@ -69,6 +69,9 @@ pub use self::{ pub struct ServerBuilder { config: ua::ServerConfig, + /// Heap-allocated set of callbacks in `config.nodeLifecycle`. + global_node_lifecycle: Box, + /// [`AccessControl`] instances may hold additional data that must be kept alive until server is /// shut down. The sentinel value cleans this up when it is dropped. access_control_sentinel: Option>, @@ -78,6 +81,7 @@ impl ServerBuilder { fn new(config: ua::ServerConfig) -> Self { Self { config, + global_node_lifecycle: Box::default(), access_control_sentinel: None, } } @@ -227,7 +231,7 @@ impl ServerBuilder { /// Builds OPC UA server. #[must_use] - pub fn build(mut self) -> (Server, ServerRunner) { + pub fn build(self) -> (Server, ServerRunner) { unsafe extern "C" fn destructor_c( _server: *mut UA_Server, _session_id: *const UA_NodeId, @@ -262,25 +266,25 @@ impl ServerBuilder { } } - let config = self.config_mut(); - - // FIXME: Initialize lifecycle hooks object. - if !config.nodeLifecycle.is_null() { - // PANIC: We never set lifecycle hooks elsewhere in config. - debug_assert!(unsafe { &*config.nodeLifecycle }.destructor.is_none()); - unsafe { &mut *config.nodeLifecycle }.destructor = Some(destructor_c); - } - let Self { - config, + mut config, + mut global_node_lifecycle, access_control_sentinel, } = self; + // PANIC: We never set lifecycle hooks elsewhere in config. + debug_assert!(global_node_lifecycle.destructor.is_none()); + global_node_lifecycle.destructor = Some(destructor_c); + + // SAFETY: We keep `global_node_lifecycle` alive until `clear_global_node_lifecycle()`. + unsafe { set_global_node_lifecycle(&mut config, &mut global_node_lifecycle) }; + let server = Arc::new(ua::Server::new_with_config(config)); let state = Arc::new(RunnerState::new()); let runner = ServerRunner::new( Arc::clone(&server), + global_node_lifecycle, access_control_sentinel, Arc::clone(&state), ); @@ -1695,6 +1699,9 @@ impl Server { pub struct ServerRunner { server: Arc, + /// Heap-allocated set of callbacks in `config.nodeLifecycle`. + global_node_lifecycle: Box, + /// [`AccessControl`] instances may hold additional data that must be kept alive until server is /// shut down. The sentinel value cleans this up when it is dropped. access_control_sentinel: Option>, @@ -1706,11 +1713,13 @@ impl ServerRunner { #[must_use] fn new( server: Arc, + global_node_lifecycle: Box, access_control_sentinel: Option>, state: Arc, ) -> Self { Self { server, + global_node_lifecycle, access_control_sentinel, state, } @@ -1737,9 +1746,11 @@ impl ServerRunner { pub fn run_until_interrupt(mut self) -> Result<()> { let Self { server, + global_node_lifecycle, access_control_sentinel, state, } = &mut self; + let global_node_lifecycle = mem::take(global_node_lifecycle); let access_control_sentinel = access_control_sentinel.take(); let mut state_guard = state.lock(); @@ -1767,6 +1778,8 @@ impl ServerRunner { } } + unsafe { clear_global_node_lifecycle(server, global_node_lifecycle) }; + // Compile-time assertion to make sure that the sentinel value was still around for the call // above (including any branches that exit early with `?` or `return`): only when the server // has finished shutting down, we are allowed to drop sentinel values. @@ -1786,9 +1799,11 @@ impl ServerRunner { pub fn run_until_cancelled(mut self, mut is_cancelled: impl FnMut() -> bool) -> Result<()> { let Self { server, + global_node_lifecycle, access_control_sentinel, state, } = &mut self; + let global_node_lifecycle = mem::take(global_node_lifecycle); let access_control_sentinel = access_control_sentinel.take(); let mut state_guard = state.lock(); @@ -1863,6 +1878,8 @@ impl ServerRunner { } } + unsafe { clear_global_node_lifecycle(server, global_node_lifecycle) }; + // Compile-time assertion to make sure that the sentinel value was still around for the call // above (including any branches that exit early with `?` or `return`): only when the server // has finished shutting down, we are allowed to drop sentinel values. @@ -1895,3 +1912,47 @@ fn to_browse_result(result: &ua::BrowseResult) -> BrowseResult { Ok((references.into_vec(), result.continuation_point())) } + +/// Sets `config.nodeLifecycle` to the given value. +/// +/// # Safety +/// +/// This must be called before the server accesses `config.nodeLifecycle`. +/// +/// The boxed value `global_node_lifecycle` must be kept alive until `clear_global_node_lifecycle()` +/// has been called. +unsafe fn set_global_node_lifecycle( + config: &mut ua::ServerConfig, + global_node_lifecycle: &mut Box, +) { + let config = unsafe { config.as_mut() }; + + // PANIC: Nobody else has initialized the node lifecycle callbacks before. + debug_assert!(config.nodeLifecycle.is_null()); + + // This stores the pointer to the `Box`-allocated `global_node_lifecycle` in the config; it must + // be kept alive elsewhere (e.g., in `ServerRunner`) until the server no longer accesses it. + config.nodeLifecycle = &raw mut *global_node_lifecycle.as_mut(); +} + +/// Clears `config.nodeLifecycle`. +/// +/// # Safety +/// +/// This must be called after the server has finished accessing `config.nodeLifecycle`. +unsafe fn clear_global_node_lifecycle( + server: &ua::Server, + mut global_node_lifecycle: Box, +) { + // SAFETY: The server has finished execution and we can mutate the configuration. + let config = unsafe { &mut *UA_Server_getConfig(server.as_ptr().cast_mut()) }; + + debug_assert_eq!( + config.nodeLifecycle, + &raw mut *global_node_lifecycle.as_mut() + ); + + // Remove pointer to prevent server from making any more calls. `global_node_lifecycle` goes out + // of scope at the end of this function and gets freed. + config.nodeLifecycle = ptr::null_mut(); +} From 6bced2ea8fe4e6f4ae6eb0a09f8cbe4f5bb93748 Mon Sep 17 00:00:00 2001 From: Sebastian Goll Date: Mon, 1 Sep 2025 14:51:22 +0200 Subject: [PATCH 06/20] Skip broken builds on Ubuntu 22.04 with GNU libc --- .github/workflows/latest-dependencies.yaml | 12 ++++++++++-- .github/workflows/test.yaml | 12 ++++++++++-- 2 files changed, 20 insertions(+), 4 deletions(-) diff --git a/.github/workflows/latest-dependencies.yaml b/.github/workflows/latest-dependencies.yaml index 5c1ed049..71bdf0a5 100644 --- a/.github/workflows/latest-dependencies.yaml +++ b/.github/workflows/latest-dependencies.yaml @@ -99,14 +99,18 @@ jobs: cargo update --verbose - name: Build with feature combinations + # Disable build for GNU targets on Ubuntu 22.04 (unsupported `atomic_uintptr_t`). + # TODO: Try to re-enable this step regardless of the build target in the future. + if: ${{ matrix.runner_os != 'ubuntu-22.04' || endsWith(matrix.target, '-musl') }} run: >- cargo hack --each-feature build --locked - name: Run tests (bins/lib/tests/examples) with feature combinations + # Disable build for GNU targets on Ubuntu 22.04 (unsupported `atomic_uintptr_t`). # Disable tests for musl libc target(s) due to build failure for unknown reasons. # TODO: Try to re-enable this step regardless of the build target in the future. - if: ${{ !endsWith(matrix.target, '-musl') }} + if: ${{ matrix.runner_os != 'ubuntu-22.04' && !endsWith(matrix.target, '-musl') }} run: >- cargo hack --each-feature test --locked @@ -119,15 +123,19 @@ jobs: # certain features only for some doctests, so we run them without # `cargo-hack`. - name: Run doctests with all features enabled + # Disable build for GNU targets on Ubuntu 22.04 (unsupported `atomic_uintptr_t`). # Disable tests for musl libc target(s) due to build failure for unknown reasons. # TODO: Try to re-enable this step regardless of the build target in the future. - if: ${{ !endsWith(matrix.target, '-musl') }} + if: ${{ matrix.runner_os != 'ubuntu-22.04' && !endsWith(matrix.target, '-musl') }} run: >- cargo test --locked --all-features --doc - name: Build package with all features enabled + # Disable build for GNU targets on Ubuntu 22.04 (unsupported `atomic_uintptr_t`). + # TODO: Try to re-enable this step regardless of the build target in the future. + if: ${{ matrix.runner_os != 'ubuntu-22.04' || endsWith(matrix.target, '-musl') }} # We allow dirty state here because it is only expected after update. run: >- cargo package diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml index 78f63c8b..47bebe2f 100644 --- a/.github/workflows/test.yaml +++ b/.github/workflows/test.yaml @@ -113,14 +113,18 @@ jobs: shared-key: ${{ github.workflow }}-${{ github.job }}-${{ matrix.target }}-${{ matrix.runner_os }} - name: Build with feature combinations + # Disable build for GNU targets on Ubuntu 22.04 (unsupported `atomic_uintptr_t`). + # TODO: Try to re-enable this step regardless of the build target in the future. + if: ${{ matrix.runner_os != 'ubuntu-22.04' || endsWith(matrix.target, '-musl') }} run: >- cargo hack --each-feature build --locked - name: Run tests (bins/lib/tests/examples) with feature combinations + # Disable build for GNU targets on Ubuntu 22.04 (unsupported `atomic_uintptr_t`). # Disable tests for musl libc target(s) due to build failure for unknown reasons. # TODO: Try to re-enable this step regardless of the build target in the future. - if: ${{ !endsWith(matrix.target, '-musl') }} + if: ${{ matrix.runner_os != 'ubuntu-22.04' && !endsWith(matrix.target, '-musl') }} run: >- cargo hack --each-feature test --locked @@ -133,15 +137,19 @@ jobs: # certain features only for some doctests, so we run them without # `cargo-hack`. - name: Run doctests with all features enabled + # Disable build for GNU targets on Ubuntu 22.04 (unsupported `atomic_uintptr_t`). # Disable tests for musl libc target(s) due to build failure for unknown reasons. # TODO: Try to re-enable this step regardless of the build target in the future. - if: ${{ !endsWith(matrix.target, '-musl') }} + if: ${{ matrix.runner_os != 'ubuntu-22.04' && !endsWith(matrix.target, '-musl') }} run: >- cargo test --locked --all-features --doc - name: Build package with all features enabled + # Disable build for GNU targets on Ubuntu 22.04 (unsupported `atomic_uintptr_t`). + # TODO: Try to re-enable this step regardless of the build target in the future. + if: ${{ matrix.runner_os != 'ubuntu-22.04' || endsWith(matrix.target, '-musl') }} run: >- cargo package --locked --all-features From 044b2026c3bf867fd26cc7ab0ce9903b914dab0a Mon Sep 17 00:00:00 2001 From: Sebastian Goll Date: Mon, 1 Sep 2025 14:58:15 +0200 Subject: [PATCH 07/20] Remove unsupported custom certificate verification for now --- src/lib.rs | 5 +-- src/traits.rs | 13 ------ src/ua/certificate_verification.rs | 70 +----------------------------- 3 files changed, 2 insertions(+), 86 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index d3a6c2a3..774a7ecc 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -254,10 +254,7 @@ pub use self::{ MethodNode, Node, ObjectNode, Server, ServerBuilder, ServerRunner, VariableNode, }, service::{ServiceRequest, ServiceResponse}, - traits::{ - Attribute, Attributes, CustomCertificateVerification, DataTypeExt, FilterOperand, - MonitoringFilter, - }, + traits::{Attribute, Attributes, DataTypeExt, FilterOperand, MonitoringFilter}, userdata::{Userdata, UserdataSentinel}, value::{ScalarValue, ValueType, VariantValue}, }; diff --git a/src/traits.rs b/src/traits.rs index 41f889ca..ddc3fcc6 100644 --- a/src/traits.rs +++ b/src/traits.rs @@ -77,19 +77,6 @@ pub trait Attributes: DataType { fn as_node_attributes(&self) -> &ua::NodeAttributes; } -/// Custom certificate verification. -/// -/// This is used to implement custom callbacks in [`ua::CertificateVerification::custom()`]. -pub trait CustomCertificateVerification { - fn verify_certificate(&self, certificate: &ua::ByteString) -> ua::StatusCode; - - fn verify_application_uri( - &self, - certificate: &ua::ByteString, - application_uri: &ua::String, - ) -> ua::StatusCode; -} - /// Private-key password callback. /// /// This is used to fetch the password for a given client private key when establishing a connection diff --git a/src/ua/certificate_verification.rs b/src/ua/certificate_verification.rs index 76a64d13..65a2f4df 100644 --- a/src/ua/certificate_verification.rs +++ b/src/ua/certificate_verification.rs @@ -4,11 +4,7 @@ use std::{ }; use derive_more::Debug; -use open62541_sys::{ - UA_ByteString, UA_CertificateGroup, UA_CertificateGroup_AcceptAll, UA_StatusCode, UA_String, -}; - -use crate::{ua, CustomCertificateVerification, DataType, Userdata}; +use open62541_sys::{UA_CertificateGroup, UA_CertificateGroup_AcceptAll}; /// Wrapper for [`UA_CertificateGroup`] from [`open62541_sys`]. #[derive(Debug)] @@ -29,70 +25,6 @@ impl CertificateVerification { certificate_verification } - /// Creates certificate verification with custom callbacks. - #[expect(dead_code, reason = "work in progress")] - pub fn custom(_certificate_verification: impl CustomCertificateVerification + 'static) -> Self { - type Ud = Userdata>; - - unsafe extern "C" fn verify_certificate_c( - cv: *const UA_CertificateGroup, - certificate: *const UA_ByteString, - ) -> UA_StatusCode { - // SAFETY: Reference is used only for the remainder of this function. - let certificate = ua::ByteString::raw_ref(unsafe { - certificate.as_ref().expect("certificate should be set") - }); - - // SAFETY: We use the user data only when it is still alive. - let certificate_verification = unsafe { Ud::peek_at((*cv).context) }; - let status_code = certificate_verification.verify_certificate(certificate); - status_code.into_raw() - } - - unsafe extern "C" fn verify_application_uri_c( - cv: *const UA_CertificateGroup, - certificate: *const UA_ByteString, - application_uri: *const UA_String, - ) -> UA_StatusCode { - // SAFETY: References are used only for the remainder of this function. - let certificate = ua::ByteString::raw_ref(unsafe { - certificate.as_ref().expect("certificate should be set") - }); - let application_uri = ua::String::raw_ref(unsafe { - application_uri - .as_ref() - .expect("application URI should be set") - }); - - // SAFETY: We use the user data only when it is still alive. - let certificate_verification = unsafe { Ud::peek_at((*cv).context) }; - let status_code = - certificate_verification.verify_application_uri(certificate, application_uri); - status_code.into_raw() - } - - unsafe extern "C" fn clear_c(cv: *mut UA_CertificateGroup) { - // Reclaim ownership of certificate verification and drop it. - // SAFETY: We use the user data only when it is still alive. - let _unused = unsafe { Ud::consume((*cv).context) }; - } - - // FIXME: Implement `UA_CertificateGroup`. - unimplemented!() - - // let inner = UA_CertificateGroup { - // context: Ud::prepare(Box::new(certificate_verification)), - // verifyCertificate: Some(verify_certificate_c), - // verifyApplicationURI: Some(verify_application_uri_c), - // getExpirationDate: None, - // getSubjectName: None, - // clear: Some(clear_c), - // logging: ptr::null_mut(), - // }; - - // unsafe { Self::from_raw(inner) } - } - /// Creates wrapper by taking ownership of value. /// /// When `Self` is dropped, allocations held by the inner type are cleaned up. From 1b00e19ff61d6619ac416980239a5ab496bbf45f Mon Sep 17 00:00:00 2001 From: Sebastian Goll Date: Mon, 1 Sep 2025 14:58:26 +0200 Subject: [PATCH 08/20] Add changelog messages --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 35db552a..04cca40b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,10 @@ adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). ### Changed +- Breaking: Upgrade to open62541 version + [1.5.0](https://github.com/open62541/open62541/releases/tag/v1.5.0). +- Breaking: Remove method `ua::CertificateVerification::custom()` and trait + `CustomCertificateVerification`. - Include category ("network", "channel", ..., "discovery") in log messages. - Skip overhead of formatting log message when corresponding log level has been disabled. From 9add1df7f514d45dcf363afb9924e5654baadf66 Mon Sep 17 00:00:00 2001 From: Sebastian Goll Date: Mon, 1 Sep 2025 15:46:10 +0200 Subject: [PATCH 09/20] Add `ua::CertificateVerification::memory_store()` stub --- CHANGELOG.md | 4 +++ src/ua/certificate_verification.rs | 32 ++++++++++++++++- src/ua/data_types.rs | 2 ++ src/ua/data_types/trust_list_data_type.rs | 44 +++++++++++++++++++++++ 4 files changed, 81 insertions(+), 1 deletion(-) create mode 100644 src/ua/data_types/trust_list_data_type.rs diff --git a/CHANGELOG.md b/CHANGELOG.md index 04cca40b..5eb4a579 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,10 @@ adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). ## [Unreleased] +### Added + +- Add method `ua::CertificateVerification::memory_store()` and `ua::TrustListDataType`. + ### Changed - Breaking: Upgrade to open62541 version diff --git a/src/ua/certificate_verification.rs b/src/ua/certificate_verification.rs index 65a2f4df..244af89e 100644 --- a/src/ua/certificate_verification.rs +++ b/src/ua/certificate_verification.rs @@ -4,8 +4,13 @@ use std::{ }; use derive_more::Debug; +#[cfg(feature = "mbedtls")] +use open62541_sys::UA_CertificateGroup_Memorystore; use open62541_sys::{UA_CertificateGroup, UA_CertificateGroup_AcceptAll}; +#[cfg(feature = "mbedtls")] +use crate::{ua, DataType as _}; + /// Wrapper for [`UA_CertificateGroup`] from [`open62541_sys`]. #[derive(Debug)] pub struct CertificateVerification(#[debug(skip)] UA_CertificateGroup); @@ -18,13 +23,38 @@ impl CertificateVerification { #[must_use] pub fn accept_all() -> Self { let mut certificate_verification = Self::init(); - // SAFETY: Certificate verification is null, but that is valid. + // SAFETY: Certificate verification is uninitialized, but that is expected. unsafe { UA_CertificateGroup_AcceptAll(certificate_verification.as_mut_ptr()); } certificate_verification } + #[cfg(feature = "mbedtls")] + #[must_use] + pub fn memory_store( + certificate_group_id: &ua::NodeId, + trust_list: Option<&ua::TrustListDataType>, + ) -> Self { + let mut certificate_verification = Self::init(); + // SAFETY: Certificate verification is uninitialized, but that is expected. + unsafe { + UA_CertificateGroup_Memorystore( + certificate_verification.as_mut_ptr(), + // SAFETY: Argument is only read, not modified or returned. + certificate_group_id.as_ptr().cast_mut(), + trust_list.map_or(ptr::null(), |trust_list| trust_list.as_ptr()), + // FIXME: Initialize logger. + ptr::null(), + // TODO: Allow parameters. Valid parameters are: + // - "max-trust-listsize" + // - "max-rejected-listsize" + ptr::null(), + ); + } + certificate_verification + } + /// Creates wrapper by taking ownership of value. /// /// When `Self` is dropped, allocations held by the inner type are cleaned up. diff --git a/src/ua/data_types.rs b/src/ua/data_types.rs index b00d9f4e..55d16284 100644 --- a/src/ua/data_types.rs +++ b/src/ua/data_types.rs @@ -76,6 +76,7 @@ mod status_code; mod string; mod structure_definition; mod timestamps_to_return; +mod trust_list_data_type; mod user_name_identity_token; mod variant; mod write_request; @@ -164,6 +165,7 @@ pub use self::{ string::String, structure_definition::StructureDefinition, timestamps_to_return::TimestampsToReturn, + trust_list_data_type::TrustListDataType, user_name_identity_token::UserNameIdentityToken, variant::Variant, write_request::WriteRequest, diff --git a/src/ua/data_types/trust_list_data_type.rs b/src/ua/data_types/trust_list_data_type.rs new file mode 100644 index 00000000..f9412aa8 --- /dev/null +++ b/src/ua/data_types/trust_list_data_type.rs @@ -0,0 +1,44 @@ +use crate::ua; + +crate::data_type!(TrustListDataType); + +impl TrustListDataType { + #[must_use] + pub fn with_trusted_certificates(mut self, trusted_certificates: &[ua::String]) -> Self { + let array = ua::Array::from_slice(trusted_certificates); + array.move_into_raw( + &mut self.0.trustedCertificatesSize, + &mut self.0.trustedCertificates, + ); + // FIXME: How to set masks? + // self.0.specifiedLists |= UA_TRUSTLISTMASKS_TRUSTEDCERTIFICATES; + self + } + + #[must_use] + pub fn with_trusted_crls(mut self, trusted_crls: &[ua::String]) -> Self { + let array = ua::Array::from_slice(trusted_crls); + array.move_into_raw(&mut self.0.trustedCrlsSize, &mut self.0.trustedCrls); + // FIXME: How to set masks? + self + } + + #[must_use] + pub fn with_issuer_certificates(mut self, issuer_certificates: &[ua::String]) -> Self { + let array = ua::Array::from_slice(issuer_certificates); + array.move_into_raw( + &mut self.0.issuerCertificatesSize, + &mut self.0.issuerCertificates, + ); + // FIXME: How to set masks? + self + } + + #[must_use] + pub fn with_issuer_crls(mut self, issuer_crls: &[ua::String]) -> Self { + let array = ua::Array::from_slice(issuer_crls); + array.move_into_raw(&mut self.0.issuerCrlsSize, &mut self.0.issuerCrls); + // FIXME: How to set masks? + self + } +} From 531393826fd9cc45e376f80bfe8a185f5670a562 Mon Sep 17 00:00:00 2001 From: Sebastian Goll Date: Mon, 1 Sep 2025 15:58:05 +0200 Subject: [PATCH 10/20] Set trust list masks --- src/ua.rs | 2 + src/ua/data_types/trust_list_data_type.rs | 25 +++++++-- src/ua/trust_list_masks.rs | 67 +++++++++++++++++++++++ 3 files changed, 89 insertions(+), 5 deletions(-) create mode 100644 src/ua/trust_list_masks.rs diff --git a/src/ua.rs b/src/ua.rs index c5d61fc8..5f5003c5 100644 --- a/src/ua.rs +++ b/src/ua.rs @@ -31,6 +31,7 @@ mod session_state; mod session_statistics; mod specified_attributes; mod subscription_id; +mod trust_list_masks; mod unit_id; mod user_identity_token; @@ -64,6 +65,7 @@ pub use self::{ session_statistics::SessionStatistics, specified_attributes::SpecifiedAttributes, subscription_id::SubscriptionId, + trust_list_masks::TrustListMasks, unit_id::UnitId, user_identity_token::UserIdentityToken, }; diff --git a/src/ua/data_types/trust_list_data_type.rs b/src/ua/data_types/trust_list_data_type.rs index f9412aa8..823c8c81 100644 --- a/src/ua/data_types/trust_list_data_type.rs +++ b/src/ua/data_types/trust_list_data_type.rs @@ -6,39 +6,54 @@ impl TrustListDataType { #[must_use] pub fn with_trusted_certificates(mut self, trusted_certificates: &[ua::String]) -> Self { let array = ua::Array::from_slice(trusted_certificates); + if array.is_empty() { + self.0.specifiedLists &= !ua::TrustListMasks::TRUSTEDCERTIFICATES.as_u32(); + } else { + self.0.specifiedLists |= ua::TrustListMasks::TRUSTEDCERTIFICATES.as_u32(); + } array.move_into_raw( &mut self.0.trustedCertificatesSize, &mut self.0.trustedCertificates, ); - // FIXME: How to set masks? - // self.0.specifiedLists |= UA_TRUSTLISTMASKS_TRUSTEDCERTIFICATES; self } #[must_use] pub fn with_trusted_crls(mut self, trusted_crls: &[ua::String]) -> Self { let array = ua::Array::from_slice(trusted_crls); + if array.is_empty() { + self.0.specifiedLists &= !ua::TrustListMasks::TRUSTEDCRLS.as_u32(); + } else { + self.0.specifiedLists |= ua::TrustListMasks::TRUSTEDCRLS.as_u32(); + } array.move_into_raw(&mut self.0.trustedCrlsSize, &mut self.0.trustedCrls); - // FIXME: How to set masks? self } #[must_use] pub fn with_issuer_certificates(mut self, issuer_certificates: &[ua::String]) -> Self { let array = ua::Array::from_slice(issuer_certificates); + if array.is_empty() { + self.0.specifiedLists &= !ua::TrustListMasks::ISSUERCERTIFICATES.as_u32(); + } else { + self.0.specifiedLists |= ua::TrustListMasks::ISSUERCERTIFICATES.as_u32(); + } array.move_into_raw( &mut self.0.issuerCertificatesSize, &mut self.0.issuerCertificates, ); - // FIXME: How to set masks? self } #[must_use] pub fn with_issuer_crls(mut self, issuer_crls: &[ua::String]) -> Self { let array = ua::Array::from_slice(issuer_crls); + if array.is_empty() { + self.0.specifiedLists &= !ua::TrustListMasks::ISSUERCRLS.as_u32(); + } else { + self.0.specifiedLists |= ua::TrustListMasks::ISSUERCRLS.as_u32(); + } array.move_into_raw(&mut self.0.issuerCrlsSize, &mut self.0.issuerCrls); - // FIXME: How to set masks? self } } diff --git a/src/ua/trust_list_masks.rs b/src/ua/trust_list_masks.rs new file mode 100644 index 00000000..adf4e65d --- /dev/null +++ b/src/ua/trust_list_masks.rs @@ -0,0 +1,67 @@ +#[expect(unreachable_pub, reason = "hidden inner enum")] +// We do not expose the inner enum. We want to use a proper `u32` for bit operations on the mask and +// we want to be clear about what is an initial (const, enum-like) value and what is a derived mask; +// specifically, the bitmask type is _not_ an enum even though declared so in `open62541-sys`. +mod inner { + crate::data_type!(TrustListMasks); + + crate::enum_variants!( + TrustListMasks, + UA_TrustListMasks, + [ + NONE, + TRUSTEDCERTIFICATES, + TRUSTEDCRLS, + ISSUERCERTIFICATES, + ISSUERCRLS, + ALL, + ], + ); +} + +/// Wrapper for trust list masks from [`open62541_sys`]. +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +pub struct TrustListMasks(u32); + +crate::bitmask_ops!(TrustListMasks); + +impl TrustListMasks { + pub const NONE: Self = Self(inner::TrustListMasks::NONE_U32); + pub const TRUSTEDCERTIFICATES: Self = Self(inner::TrustListMasks::TRUSTEDCERTIFICATES_U32); + pub const TRUSTEDCRLS: Self = Self(inner::TrustListMasks::TRUSTEDCRLS_U32); + pub const ISSUERCERTIFICATES: Self = Self(inner::TrustListMasks::ISSUERCERTIFICATES_U32); + pub const ISSUERCRLS: Self = Self(inner::TrustListMasks::ISSUERCRLS_U32); + pub const ALL: Self = Self(inner::TrustListMasks::ALL_U32); + + pub(crate) const fn from_u32(mask: u32) -> Self { + Self(mask) + } + + pub(crate) const fn as_u32(&self) -> u32 { + self.0 + } +} + +#[cfg(test)] +mod tests { + use crate::ua; + + #[test] + fn combine_masks() { + // We support mask combinators in `const` expressions. + const LHS: ua::TrustListMasks = ua::TrustListMasks::TRUSTEDCERTIFICATES + .or(&ua::TrustListMasks::TRUSTEDCRLS) + .or(&ua::TrustListMasks::ISSUERCERTIFICATES) + .or(&ua::TrustListMasks::ISSUERCRLS); + const RHS: ua::TrustListMasks = ua::TrustListMasks::ALL; + assert_eq!(LHS, RHS); + + // We support mask combinators with `|` shorthand notation. + let lhs = ua::TrustListMasks::TRUSTEDCERTIFICATES + | ua::TrustListMasks::TRUSTEDCRLS + | ua::TrustListMasks::ISSUERCERTIFICATES + | ua::TrustListMasks::ISSUERCRLS; + let rhs = ua::TrustListMasks::ALL; + assert_eq!(lhs, rhs); + } +} From 25aaba7eb1d0282d2e2bcaa594826357a68ba86a Mon Sep 17 00:00:00 2001 From: Sebastian Goll Date: Mon, 22 Dec 2025 15:59:46 +0100 Subject: [PATCH 11/20] Fix inconsistencies after merge --- CHANGELOG.md | 1 - src/monitored_item/delete_monitored_items.rs | 2 -- 2 files changed, 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 069f5b05..669113b8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -48,7 +48,6 @@ adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). - Deprecate `MonitoredItemBuilder`. Use `MonitoredItemCreateRequestBuilder` and `AsyncMonitoredItem::create()` instead. - Breaking: Bump Minimum Supported Rust Version (MSRV) to 1.85 (Edition 2024). ->>>>>>> origin/main ## [0.9.4] - 2025-09-01 diff --git a/src/monitored_item/delete_monitored_items.rs b/src/monitored_item/delete_monitored_items.rs index cd988168..6b75285e 100644 --- a/src/monitored_item/delete_monitored_items.rs +++ b/src/monitored_item/delete_monitored_items.rs @@ -60,7 +60,6 @@ unsafe extern "C" fn callback_execute_response_c( ) { log::debug!("MonitoredItems_delete_async() completed"); - let response = response.cast::(); // SAFETY: Incoming pointer is valid for access. // PANIC: We expect pointer to be valid when good. let response = unsafe { response.as_ref() }.expect("response should be set"); @@ -118,7 +117,6 @@ unsafe extern "C" fn callback_log_response_c( ) { log::debug!("MonitoredItems_delete_async() completed"); - let response = response.cast::(); // SAFETY: Incoming pointer is valid for access. // PANIC: We expect pointer to be valid when good. let response = unsafe { response.as_ref() }.expect("response should be set"); From 1a7b1349be152f1beff1c86b91f837083c5aa763 Mon Sep 17 00:00:00 2001 From: Sebastian Goll Date: Wed, 7 Jan 2026 14:39:06 +0100 Subject: [PATCH 12/20] Switch to tag `v1.5.0-rc2` of open62541 --- Cargo.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.lock b/Cargo.lock index 845faf6a..0dcd05bf 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -658,7 +658,7 @@ dependencies = [ [[package]] name = "open62541-sys" version = "0.5.1" -source = "git+https://github.com/HMIProject/open62541-sys.git?branch=open62541-1.5#e72e9d34a1831b90c6f3d30962058956507b83b9" +source = "git+https://github.com/HMIProject/open62541-sys.git?branch=open62541-1.5#9cc00579215d4656a91b5b862b0e08db9051a327" dependencies = [ "bindgen", "cc", From cfe08f20a64573778a7a4d7112cdb408f6902e4a Mon Sep 17 00:00:00 2001 From: Uwe Klotz Date: Sun, 15 Mar 2026 23:28:42 +0100 Subject: [PATCH 13/20] Update to open62541 v1.5.3 (#317) --- .pre-commit-config.yaml | 6 +- Cargo.lock | 783 +++++++++++++++---------------- src/ua/data_types/status_code.rs | 2 +- 3 files changed, 394 insertions(+), 397 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 2149052e..1a7e1f85 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -24,15 +24,15 @@ repos: - id: mixed-line-ending - id: trailing-whitespace - repo: https://github.com/DavidAnson/markdownlint-cli2 - rev: v0.18.1 + rev: v0.21.0 hooks: - id: markdownlint-cli2 - repo: https://github.com/codespell-project/codespell - rev: v2.4.1 + rev: v2.4.2 hooks: - id: codespell - repo: https://github.com/sirosen/check-jsonschema - rev: 0.34.0 + rev: 0.37.0 hooks: - id: check-github-actions - id: check-github-workflows diff --git a/Cargo.lock b/Cargo.lock index 0dcd05bf..6de05295 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,36 +2,15 @@ # It is not intended for manual editing. version = 4 -[[package]] -name = "addr2line" -version = "0.21.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a30b2e23b9e17a9f90641c7ab1549cd9b44f296d3ccbf309d2863cfe398a0cb" -dependencies = [ - "gimli", -] - -[[package]] -name = "adler" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" - [[package]] name = "aho-corasick" -version = "1.1.2" +version = "1.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2969dcb958b36655471fc61f7e416fa76033bdd4bfed0678d8fee1e2d07a1f0" +checksum = "ddd31a130427c27518df266943a5308ed92d4b226cc639f5a8f1002816174301" dependencies = [ "memchr", ] -[[package]] -name = "android-tzdata" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0" - [[package]] name = "android_system_properties" version = "0.1.5" @@ -43,78 +22,65 @@ dependencies = [ [[package]] name = "anstream" -version = "0.6.11" +version = "0.6.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e2e1ebcb11de5c03c67de28a7df593d32191b44939c482e97702baaaa6ab6a5" +checksum = "43d5b281e737544384e969a5ccad3f1cdd24b48086a0fc1b2a5262a26b8f4f4a" dependencies = [ "anstyle", "anstyle-parse", "anstyle-query", "anstyle-wincon", "colorchoice", + "is_terminal_polyfill", "utf8parse", ] [[package]] name = "anstyle" -version = "1.0.6" +version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8901269c6307e8d93993578286ac0edf7f195079ffff5ebdeea6a59ffb7e36bc" +checksum = "940b3a0ca603d1eade50a4846a2afffd5ef57a9feac2c0e2ec2e14f9ead76000" [[package]] name = "anstyle-parse" -version = "0.2.3" +version = "0.2.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c75ac65da39e5fe5ab759307499ddad880d724eed2f6ce5b5e8a26f4f387928c" +checksum = "4e7644824f0aa2c7b9384579234ef10eb7efb6a0deb83f9630a49594dd9c15c2" dependencies = [ "utf8parse", ] [[package]] name = "anstyle-query" -version = "1.0.2" +version = "1.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e28923312444cdd728e4738b3f9c9cac739500909bb3d3c94b43551b16517648" +checksum = "40c48f72fd53cd289104fc64099abca73db4166ad86ea0b4341abe65af83dadc" dependencies = [ - "windows-sys 0.52.0", + "windows-sys 0.61.2", ] [[package]] name = "anstyle-wincon" -version = "3.0.2" +version = "3.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1cd54b81ec8d6180e24654d0b371ad22fc3dd083b6ff8ba325b72e00c87660a7" +checksum = "291e6a250ff86cd4a820112fb8898808a366d8f9f58ce16d1f538353ad55747d" dependencies = [ "anstyle", - "windows-sys 0.52.0", + "once_cell_polyfill", + "windows-sys 0.61.2", ] [[package]] name = "anyhow" -version = "1.0.79" +version = "1.0.102" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "080e9890a082662b09c1ad45f567faeeb47f22b5fb23895fbe1e651e718e25ca" +checksum = "7f202df86484c868dbad7eaa557ef785d5c66295e41b460ef922eca0723b842c" [[package]] name = "autocfg" -version = "1.1.0" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" - -[[package]] -name = "backtrace" -version = "0.3.69" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2089b7e3f35b9dd2d0ed921ead4f6d318c27680d4a5bd167b3ee120edb105837" -dependencies = [ - "addr2line", - "cc", - "cfg-if", - "libc", - "miniz_oxide", - "object", - "rustc-demangle", -] +checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" [[package]] name = "base64" @@ -124,15 +90,15 @@ checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" [[package]] name = "base64ct" -version = "1.6.0" +version = "1.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b" +checksum = "2af50177e190e07a26ab74f8b1efbfe2ef87da2116221318cb1c2e82baf7de06" [[package]] name = "bcder" -version = "0.7.4" +version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c627747a6774aab38beb35990d88309481378558875a41da1a4b2e373c906ef0" +checksum = "1f7c42c9913f68cf9390a225e81ad56a5c515347287eb98baa710090ca1de86d" dependencies = [ "bytes", "smallvec", @@ -160,27 +126,27 @@ dependencies = [ [[package]] name = "bitflags" -version = "2.4.2" +version = "2.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed570934406eb16438a4e976b1b4500774099c13b8cb96eec99f620f05090ddf" +checksum = "843867be96c8daad0d758b57df9392b6d8d271134fce549de6ce169ff98a92af" [[package]] name = "bumpalo" -version = "3.16.0" +version = "3.20.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" +checksum = "5d20789868f4b01b2f2caec9f5c4e0213b41e3e5702a50157d699ae31ced2fcb" [[package]] name = "bytes" -version = "1.9.0" +version = "1.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "325918d6fe32f23b19878fe4b34794ae41fc19ddbe53b10571a4874d44ffd39b" +checksum = "1e748733b7cbc798e1434b6ac524f0c1ff2ab456fe201501e6497c8417a4fc33" [[package]] name = "cc" -version = "1.2.41" +version = "1.2.57" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac9fe6cdbb24b6ade63616c0a0688e45bb56732262c158df3c0c4bea4ca47cb7" +checksum = "7a0dd1ca384932ff3641c8718a02769f1698e7563dc6974ffd03346116310423" dependencies = [ "find-msvc-tools", "shlex", @@ -197,27 +163,26 @@ dependencies = [ [[package]] name = "cfg-if" -version = "1.0.0" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" [[package]] name = "chrono" -version = "0.4.38" +version = "0.4.44" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a21f936df1771bf62b77f047b726c4625ff2e8aa607c01ec06e5a05bd8463401" +checksum = "c673075a2e0e5f4a1dde27ce9dee1ea4558c7ffe648f576438a20ca1d2acc4b0" dependencies = [ - "android-tzdata", "iana-time-zone", "num-traits", - "windows-targets 0.52.0", + "windows-link", ] [[package]] name = "clang-sys" -version = "1.7.0" +version = "1.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67523a3b4be3ce1989d607a828d036249522dd9c1c8de7f4dd2dae43a37369d1" +checksum = "0b023947811758c97c59bf9d1c188fd619ad4718dcaa767947df1cadb14f39f4" dependencies = [ "glob", "libc", @@ -226,18 +191,18 @@ dependencies = [ [[package]] name = "cmake" -version = "0.1.54" +version = "0.1.57" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7caa3f9de89ddbe2c607f4101924c5abec803763ae9534e4f4d7d8f84aa81f0" +checksum = "75443c44cd6b379beb8c5b45d85d0773baf31cce901fe7bb252f4eff3008ef7d" dependencies = [ "cc", ] [[package]] name = "colorchoice" -version = "1.0.0" +version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7" +checksum = "1d07550c9036bf2ae0c684c4297d503f838287c83c53686d05370d0e139ae570" [[package]] name = "const-oid" @@ -253,9 +218,9 @@ checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" [[package]] name = "der" -version = "0.7.9" +version = "0.7.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f55bf8e7b65898637379c1b74eb1551107c8294ed26d855ceb9fd1a09cfc9bc0" +checksum = "e7c1832837b905bbfb5101e07cc24c8deddf52f93225eee6ead5f4d63d53ddcb" dependencies = [ "const-oid", "zeroize", @@ -263,46 +228,47 @@ dependencies = [ [[package]] name = "deranged" -version = "0.3.11" +version = "0.5.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b42b6fa04a440b495c8b04d0e71b707c585f83cb9cb28cf8cd0d976c315e31b4" +checksum = "7cd812cc2bc1d69d4764bd80df88b4317eaef9e773c75226407d9bc0876b211c" dependencies = [ "powerfmt", - "serde", + "serde_core", ] [[package]] name = "derive_more" -version = "2.0.1" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "093242cf7570c207c83073cf82f79706fe7b8317e98620a47d5be7c3d8497678" +checksum = "d751e9e49156b02b44f9c1815bcb94b984cdcc4396ecc32521c739452808b134" dependencies = [ "derive_more-impl", ] [[package]] name = "derive_more-impl" -version = "2.0.1" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bda628edc44c4bb645fbe0f758797143e4e07926f7ebf4e9bdfbd3d2ce621df3" +checksum = "799a97264921d8623a957f6c3b9011f3b5492f557bbb7a5a19b7fa6d06ba8dcb" dependencies = [ "proc-macro2", "quote", + "rustc_version", "syn", "unicode-xid", ] [[package]] name = "either" -version = "1.9.0" +version = "1.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a26ae43d7bcc3b814de94796a5e736d4029efb0ee900c12e2d54c993ad1a1e07" +checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" [[package]] name = "env_filter" -version = "0.1.0" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a009aa4810eb158359dda09d0c87378e4bbb89b5a801f016885a4707ba24f7ea" +checksum = "7a1c3cc8e57274ec99de65301228b537f1e4eedc1b8e0f9411c6caac8ae7308f" dependencies = [ "log", "regex", @@ -310,28 +276,28 @@ dependencies = [ [[package]] name = "env_logger" -version = "0.11.1" +version = "0.11.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05e7cf40684ae96ade6232ed84582f40ce0a66efcd43a5117aef610534f8e0b8" +checksum = "b2daee4ea451f429a58296525ddf28b45a3b64f1acf6587e2067437bb11e218d" dependencies = [ "anstream", "anstyle", "env_filter", - "humantime", + "jiff", "log", ] [[package]] name = "find-msvc-tools" -version = "0.1.4" +version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "52051878f80a721bb68ebfbc930e07b65ba72f2da88968ea5c06fd6ca3d3a127" +checksum = "5baebc0774151f905a1a2cc41989300b1e6fbb29aff0ceffa1064fdd3088d582" [[package]] name = "futures" -version = "0.3.31" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "65bc07b1a8bc7c85c5f2e110c476c7389b4554ba72af57d8445ea63a576b0876" +checksum = "8b147ee9d1f6d097cef9ce628cd2ee62288d963e16fb287bd9286455b241382d" dependencies = [ "futures-channel", "futures-core", @@ -344,9 +310,9 @@ dependencies = [ [[package]] name = "futures-channel" -version = "0.3.31" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2dff15bf788c671c1934e366d07e30c1814a8ef514e1af724a602e8a2fbe1b10" +checksum = "07bbe89c50d7a535e539b8c17bc0b49bdb77747034daa8087407d655f3f7cc1d" dependencies = [ "futures-core", "futures-sink", @@ -354,15 +320,15 @@ dependencies = [ [[package]] name = "futures-core" -version = "0.3.31" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e" +checksum = "7e3450815272ef58cec6d564423f6e755e25379b217b0bc688e295ba24df6b1d" [[package]] name = "futures-executor" -version = "0.3.31" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e28d1d997f585e54aebc3f97d39e72338912123a67330d723fdbb564d646c9f" +checksum = "baf29c38818342a3b26b5b923639e7b1f4a61fc5e76102d4b1981c6dc7a7579d" dependencies = [ "futures-core", "futures-task", @@ -371,15 +337,15 @@ dependencies = [ [[package]] name = "futures-io" -version = "0.3.31" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6" +checksum = "cecba35d7ad927e23624b22ad55235f2239cfa44fd10428eecbeba6d6a717718" [[package]] name = "futures-macro" -version = "0.3.31" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" +checksum = "e835b70203e41293343137df5c0664546da5745f82ec9b84d40be8336958447b" dependencies = [ "proc-macro2", "quote", @@ -388,21 +354,21 @@ dependencies = [ [[package]] name = "futures-sink" -version = "0.3.31" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e575fab7d1e0dcb8d0c7bcf9a63ee213816ab51902e6d244a95819acacf1d4f7" +checksum = "c39754e157331b013978ec91992bde1ac089843443c49cbc7f46150b0fad0893" [[package]] name = "futures-task" -version = "0.3.31" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988" +checksum = "037711b3d59c33004d3856fbdc83b99d4ff37a24768fa1be9ce3538a1cde4393" [[package]] name = "futures-util" -version = "0.3.31" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81" +checksum = "389ca41296e6190b48053de0321d02a77f32f8a5d2461dd38762c0593805c6d6" dependencies = [ "futures-channel", "futures-core", @@ -412,50 +378,37 @@ dependencies = [ "futures-task", "memchr", "pin-project-lite", - "pin-utils", "slab", ] [[package]] name = "getrandom" -version = "0.2.12" +version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "190092ea657667030ac6a35e305e62fc4dd69fd98ac98631e5d3a2b1575a12b5" +checksum = "ff2abc00be7fca6ebc474524697ae276ad847ad0a6b3faa4bcb027e9a4614ad0" dependencies = [ "cfg-if", "libc", - "wasi 0.11.0+wasi-snapshot-preview1", + "wasi", ] [[package]] name = "getrandom" -version = "0.3.3" +version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26145e563e54f2cadc477553f1ec5ee650b00862f0a58bcd12cbdc5f0ea2d2f4" +checksum = "899def5c37c4fd7b2664648c28120ecec138e4d395b459e5ca34f9cce2dd77fd" dependencies = [ "cfg-if", "libc", "r-efi", - "wasi 0.14.2+wasi-0.2.4", + "wasip2", ] -[[package]] -name = "gimli" -version = "0.28.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253" - [[package]] name = "glob" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" - -[[package]] -name = "hermit-abi" -version = "0.3.9" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024" +checksum = "0cc23270f6e1808e30a928bdc84dea0b9b4136a8bc82338574f23baf47bbd280" [[package]] name = "hex" @@ -463,22 +416,17 @@ version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" -[[package]] -name = "humantime" -version = "2.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" - [[package]] name = "iana-time-zone" -version = "0.1.61" +version = "0.1.65" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "235e081f3925a06703c2d0117ea8b91f042756fd6e7a6e5d901e8ca1a996b220" +checksum = "e31bc9ad994ba00e440a8aa5c9ef0ec67d5cb5e5cb0cc7f8b744a35b389cc470" dependencies = [ "android_system_properties", "core-foundation-sys", "iana-time-zone-haiku", "js-sys", + "log", "wasm-bindgen", "windows-core", ] @@ -492,6 +440,12 @@ dependencies = [ "cc", ] +[[package]] +name = "is_terminal_polyfill" +version = "1.70.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a6cb138bb79a146c1bd460005623e142ef0181e3d0219cb493e02f7d08a35695" + [[package]] name = "itertools" version = "0.13.0" @@ -512,15 +466,39 @@ dependencies = [ [[package]] name = "itoa" -version = "1.0.10" +version = "1.0.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92ecc6618181def0457392ccd0ee51198e065e016d1d527a7ac1b6dc7c1f09d2" + +[[package]] +name = "jiff" +version = "0.2.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a3546dc96b6d42c5f24902af9e2538e82e39ad350b0c766eb3fbf2d8f3d8359" +dependencies = [ + "jiff-static", + "log", + "portable-atomic", + "portable-atomic-util", + "serde_core", +] + +[[package]] +name = "jiff-static" +version = "0.2.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1a46d1a171d865aa5f83f92695765caa047a9b4cbae2cbf37dbd613a793fd4c" +checksum = "2a8c8b344124222efd714b73bb41f8b5120b27a7cc1c75593a6ff768d9d05aa4" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] [[package]] name = "js-sys" -version = "0.3.74" +version = "0.3.91" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a865e038f7f6ed956f788f0d7d60c541fff74c7bd74272c5d4cf15c63743e705" +checksum = "b49715b7073f385ba4bc528e5747d02e66cb39c6146efb66b781f131f0fb399c" dependencies = [ "once_cell", "wasm-bindgen", @@ -528,41 +506,40 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.155" +version = "0.2.183" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c" +checksum = "b5b646652bf6661599e1da8901b3b9522896f01e736bad5f723fe7a3a27f899d" [[package]] name = "libloading" -version = "0.8.1" +version = "0.8.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c571b676ddfc9a8c12f1f3d3085a7b163966a8fd8098a90640953ce5f6170161" +checksum = "d7c4b02199fee7c5d21a5ae7d8cfa79a6ef5bb2fc834d6e9058e89c825efdc55" dependencies = [ "cfg-if", - "windows-sys 0.48.0", + "windows-link", ] [[package]] name = "lock_api" -version = "0.4.13" +version = "0.4.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96936507f153605bddfcda068dd804796c84324ed2510809e5b2a624c81da765" +checksum = "224399e74b87b5f3557511d98dff8b14089b3dadafcab6bb93eab67d3aace965" dependencies = [ - "autocfg", "scopeguard", ] [[package]] name = "log" -version = "0.4.20" +version = "0.4.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f" +checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897" [[package]] name = "memchr" -version = "2.7.1" +version = "2.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "523dc4f511e55ab87b694dc30d0f820d60906ef06413f93d4d7a1385599cc149" +checksum = "f8ca58f447f06ed17d5fc4043ce1b10dd205e060fb3ce5b979b8ed8e59ff3f79" [[package]] name = "minimal-lexical" @@ -570,15 +547,6 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" -[[package]] -name = "miniz_oxide" -version = "0.7.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d811f3e15f28568be3407c8e7fdb6514c1cda3cb30683f15b6a1a1dc4ea14a7" -dependencies = [ - "adler", -] - [[package]] name = "nom" version = "7.1.3" @@ -605,29 +573,16 @@ dependencies = [ ] [[package]] -name = "num_cpus" -version = "1.16.0" +name = "once_cell" +version = "1.21.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" -dependencies = [ - "hermit-abi", - "libc", -] +checksum = "9f7c3e4beb33f85d45ae3e3a1792185706c8e16d043238c593331cc7cd313b50" [[package]] -name = "object" -version = "0.32.2" +name = "once_cell_polyfill" +version = "1.70.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a6a622008b6e321afc04970976f62ee297fdbaa6f95318ca343e3eebb9648441" -dependencies = [ - "memchr", -] - -[[package]] -name = "once_cell" -version = "1.20.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775" +checksum = "384b8ab6d37215f3c5301a95a4accb5d64aa607f1fcb26a11b5303878451b4fe" [[package]] name = "open62541" @@ -658,7 +613,7 @@ dependencies = [ [[package]] name = "open62541-sys" version = "0.5.1" -source = "git+https://github.com/HMIProject/open62541-sys.git?branch=open62541-1.5#9cc00579215d4656a91b5b862b0e08db9051a327" +source = "git+https://github.com/HMIProject/open62541-sys.git?branch=open62541-1.5#4e6df6c5c79217dbe1c5c9ca8f5ec11011c75def" dependencies = [ "bindgen", "cc", @@ -668,9 +623,9 @@ dependencies = [ [[package]] name = "parking_lot" -version = "0.12.4" +version = "0.12.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70d58bf43669b5795d1576d0641cfb6fbb2057bf629506267a92807158584a13" +checksum = "93857453250e3077bd71ff98b6a65ea6621a19bb0f559a85248955ac12c45a1a" dependencies = [ "lock_api", "parking_lot_core", @@ -678,44 +633,53 @@ dependencies = [ [[package]] name = "parking_lot_core" -version = "0.9.11" +version = "0.9.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc838d2a56b5b1a6c25f55575dfc605fabb63bb2365f6c2353ef9159aa69e4a5" +checksum = "2621685985a2ebf1c516881c026032ac7deafcda1a2c9b7850dc81e3dfcb64c1" dependencies = [ "cfg-if", "libc", "redox_syscall", "smallvec", - "windows-targets 0.52.0", + "windows-link", ] [[package]] name = "paste" -version = "1.0.14" +version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "de3145af08024dea9fa9914f381a17b8fc6034dfb00f3a84013f7ff43f29ed4c" +checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" [[package]] name = "pem" -version = "3.0.4" +version = "3.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e459365e590736a54c3fa561947c84837534b8e9af6fc5bf781307e82658fae" +checksum = "1d30c53c26bc5b31a98cd02d20f25a7c8567146caf63ed593a9d87b2775291be" dependencies = [ "base64", - "serde", + "serde_core", ] [[package]] name = "pin-project-lite" -version = "0.2.13" +version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8afb450f006bf6385ca15ef45d71d2288452bc3683ce2e2cacc0d18e4be60b58" +checksum = "a89322df9ebe1c1578d689c92318e070967d1042b512afbe49518723f4e6d5cd" [[package]] -name = "pin-utils" -version = "0.1.0" +name = "portable-atomic" +version = "1.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" +checksum = "c33a9471896f1c69cecef8d20cbe2f7accd12527ce60845ff44c153bb2a21b49" + +[[package]] +name = "portable-atomic-util" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "091397be61a01d4be58e7841595bd4bfedb15f1cd54977d79b8271e94ed799a3" +dependencies = [ + "portable-atomic", +] [[package]] name = "powerfmt" @@ -725,15 +689,18 @@ checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" [[package]] name = "ppv-lite86" -version = "0.2.17" +version = "0.2.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" +checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9" +dependencies = [ + "zerocopy", +] [[package]] name = "prettyplease" -version = "0.2.16" +version = "0.2.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a41cf62165e97c7f814d2221421dbb9afcbcdb0a88068e5ea206e19951c2cbb5" +checksum = "479ca8adacdd7ce8f1fb39ce9ecccbfe93a3f1344b3d0d97f20bc0196208f62b" dependencies = [ "proc-macro2", "syn", @@ -741,18 +708,18 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.83" +version = "1.0.106" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b33eb56c327dec362a9e55b3ad14f9d2f0904fb5a5b03b513ab5465399e9f43" +checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934" dependencies = [ "unicode-ident", ] [[package]] name = "quote" -version = "1.0.35" +version = "1.0.45" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef" +checksum = "41f2619966050689382d2b44f664f4bc593e129785a36d6ee376ddf37259b924" dependencies = [ "proc-macro2", ] @@ -770,7 +737,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6db2770f06117d490610c7488547d543617b21bfa07796d7a12f6f1bd53850d1" dependencies = [ "rand_chacha", - "rand_core 0.9.3", + "rand_core 0.9.5", ] [[package]] @@ -780,7 +747,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb" dependencies = [ "ppv-lite86", - "rand_core 0.9.3", + "rand_core 0.9.5", ] [[package]] @@ -789,32 +756,32 @@ version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" dependencies = [ - "getrandom 0.2.12", + "getrandom 0.2.17", ] [[package]] name = "rand_core" -version = "0.9.3" +version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "99d9a13982dcf210057a8a78572b2217b667c3beacbf3a0d8b454f6f82837d38" +checksum = "76afc826de14238e6e8c374ddcc1fa19e374fd8dd986b0d2af0d02377261d83c" dependencies = [ - "getrandom 0.3.3", + "getrandom 0.3.4", ] [[package]] name = "redox_syscall" -version = "0.5.12" +version = "0.5.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "928fca9cf2aa042393a8325b9ead81d2f0df4cb12e1e24cef072922ccd99c5af" +checksum = "ed2bf2547551a7053d6fdfafda3f938979645c44812fbfcda098faae3f1a362d" dependencies = [ "bitflags", ] [[package]] name = "regex" -version = "1.10.3" +version = "1.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b62dbe01f0b06f9d8dc7d49e05a0785f153b00b2c227856282f671e0318c9b15" +checksum = "e10754a14b9137dd7b1e3e5b0493cc9171fdd105e0ab477f51b72e7f3ac0e276" dependencies = [ "aho-corasick", "memchr", @@ -824,9 +791,9 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.4.5" +version = "0.4.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5bb987efffd3c6d0d8f5f89510bb458559eab11e4f869acb20bf845e016259cd" +checksum = "6e1dd4122fc1595e8162618945476892eefca7b88c52820e74af6262213cae8f" dependencies = [ "aho-corasick", "memchr", @@ -835,41 +802,44 @@ dependencies = [ [[package]] name = "regex-syntax" -version = "0.8.2" +version = "0.8.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f" +checksum = "dc897dd8d9e8bd1ed8cdad82b5966c3e0ecae09fb1907d58efaa013543185d0a" [[package]] name = "ring" -version = "0.17.12" +version = "0.17.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed9b823fa29b721a59671b41d6b06e66b29e0628e207e8b1c3ceeda701ec928d" +checksum = "a4689e6c2294d81e88dc6261c768b63bc4fcdb852be6d1352498b114f61383b7" dependencies = [ "cc", "cfg-if", - "getrandom 0.2.12", + "getrandom 0.2.17", "libc", "untrusted", "windows-sys 0.52.0", ] [[package]] -name = "rustc-demangle" -version = "0.1.23" +name = "rustc-hash" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76" +checksum = "357703d41365b4b27c590e3ed91eabb1b663f07c4c084095e60cbed4362dff0d" [[package]] -name = "rustc-hash" -version = "2.1.0" +name = "rustc_version" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7fb8039b3032c191086b10f11f319a6e99e1e82889c5cc6046f515c9db1d497" +checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92" +dependencies = [ + "semver", +] [[package]] -name = "ryu" -version = "1.0.16" +name = "rustversion" +version = "1.0.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f98d2aa92eebf49b69786be48e4477826b256916e84a57ff2a4f21923b48eb4c" +checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d" [[package]] name = "scopeguard" @@ -877,20 +847,35 @@ version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" +[[package]] +name = "semver" +version = "1.0.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d767eb0aabc880b29956c35734170f26ed551a859dbd361d140cdbeca61ab1e2" + [[package]] name = "serde" -version = "1.0.196" +version = "1.0.228" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "870026e60fa08c69f064aa766c10f10b1d62db9ccd4d0abb206472bee0ce3b32" +checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e" +dependencies = [ + "serde_core", +] + +[[package]] +name = "serde_core" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.196" +version = "1.0.228" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33c85360c95e7d137454dc81d9a4ed2b8efd8fbe19cee57357b32b9771fccb67" +checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" dependencies = [ "proc-macro2", "quote", @@ -899,13 +884,15 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.113" +version = "1.0.149" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "69801b70b1c3dac963ecb03a364ba0ceda9cf60c71cfe475e99864759c8b8a79" +checksum = "83fc039473c5595ace860d8c4fafa220ff474b3fc6bfdb4293327f1a37e94d86" dependencies = [ "itoa", - "ryu", + "memchr", "serde", + "serde_core", + "zmij", ] [[package]] @@ -925,18 +912,15 @@ dependencies = [ [[package]] name = "slab" -version = "0.4.9" +version = "0.4.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" -dependencies = [ - "autocfg", -] +checksum = "0c790de23124f9ab44544d7ac05d60440adc586479ce501c1d6d7da3cd8c9cf5" [[package]] name = "smallvec" -version = "1.13.2" +version = "1.15.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" +checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" [[package]] name = "spki" @@ -950,9 +934,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.87" +version = "2.0.117" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "25aa4ce346d03a6dcd68dd8b4010bcb74e54e62c90c573f394c46eae99aba32d" +checksum = "e665b8803e7b1d2a727f4023456bbbbe74da67099c585258af0ad9c5013b9b99" dependencies = [ "proc-macro2", "quote", @@ -961,18 +945,18 @@ dependencies = [ [[package]] name = "thiserror" -version = "2.0.16" +version = "2.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3467d614147380f2e4e374161426ff399c91084acd2363eaf549172b3d5e60c0" +checksum = "4288b5bcbc7920c07a1149a35cf9590a2aa808e0bc1eafaade0b80947865fbc4" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "2.0.16" +version = "2.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c5e1be1c48b9172ee610da68fd9cd2770e7a4056cb3fc98710ee6906f0c7960" +checksum = "ebc4ee7f67670e9b64d05fa4253e753e016c6c95ff35b89b7941d6b856dec1d5" dependencies = [ "proc-macro2", "quote", @@ -981,30 +965,30 @@ dependencies = [ [[package]] name = "time" -version = "0.3.38" +version = "0.3.45" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb041120f25f8fbe8fd2dbe4671c7c2ed74d83be2e7a77529bf7e0790ae3f472" +checksum = "f9e442fc33d7fdb45aa9bfeb312c095964abdf596f7567261062b2a7107aaabd" dependencies = [ "deranged", "itoa", "num-conv", "powerfmt", - "serde", + "serde_core", "time-core", "time-macros", ] [[package]] name = "time-core" -version = "0.1.3" +version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "765c97a5b985b7c11d7bc27fa927dc4fe6af3a6dfb021d28deb60d3bf51e76ef" +checksum = "8b36ee98fd31ec7426d599183e8fe26932a8dc1fb76ddb6214d05493377d34ca" [[package]] name = "time-macros" -version = "0.2.20" +version = "0.2.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e8093bc3e81c3bc5f7879de09619d06c9a5a5e45ca44dfeeb7225bae38005c5c" +checksum = "71e552d1249bf61ac2a52db88179fd0673def1e1ad8243a00d9ec9ed71fee3dd" dependencies = [ "num-conv", "time-core", @@ -1012,21 +996,19 @@ dependencies = [ [[package]] name = "tokio" -version = "1.38.2" +version = "1.50.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68722da18b0fc4a05fdc1120b302b82051265792a1e1b399086e9b204b10ad3d" +checksum = "27ad5e34374e03cfffefc301becb44e9dc3c17584f414349ebe29ed26661822d" dependencies = [ - "backtrace", - "num_cpus", "pin-project-lite", "tokio-macros", ] [[package]] name = "tokio-macros" -version = "2.3.0" +version = "2.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f5ae998a069d4b5aba8ee9dad856af7d520c3699e6159b185c2acd48155d39a" +checksum = "5c55a2eff8b69ce66c84f85e1da1c233edc36ceb85a2058d11b0d6a3c7e7569c" dependencies = [ "proc-macro2", "quote", @@ -1035,9 +1017,9 @@ dependencies = [ [[package]] name = "unicode-ident" -version = "1.0.12" +version = "1.0.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" +checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75" [[package]] name = "unicode-xid" @@ -1053,17 +1035,19 @@ checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" [[package]] name = "utf8parse" -version = "0.2.1" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a" +checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" [[package]] name = "uuid" -version = "1.16.0" +version = "1.22.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "458f7a779bf54acc9f347480ac654f68407d3aab21269a6e3c9f922acd9e2da9" +checksum = "a68d3c8f01c0cfa54a75291d83601161799e4a89a39e0929f4b0354d88757a37" dependencies = [ - "serde", + "js-sys", + "serde_core", + "wasm-bindgen", ] [[package]] @@ -1074,50 +1058,37 @@ checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" [[package]] name = "wasi" -version = "0.11.0+wasi-snapshot-preview1" +version = "0.11.1+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" +checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" [[package]] -name = "wasi" -version = "0.14.2+wasi-0.2.4" +name = "wasip2" +version = "1.0.1+wasi-0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9683f9a5a998d873c0d21fcbe3c083009670149a8fab228644b8bd36b2c48cb3" +checksum = "0562428422c63773dad2c345a1882263bbf4d65cf3f42e90921f787ef5ad58e7" dependencies = [ - "wit-bindgen-rt", + "wit-bindgen", ] [[package]] name = "wasm-bindgen" -version = "0.2.97" +version = "0.2.114" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d15e63b4482863c109d70a7b8706c1e364eb6ea449b201a76c5b89cedcec2d5c" +checksum = "6532f9a5c1ece3798cb1c2cfdba640b9b3ba884f5db45973a6f442510a87d38e" dependencies = [ "cfg-if", "once_cell", + "rustversion", "wasm-bindgen-macro", -] - -[[package]] -name = "wasm-bindgen-backend" -version = "0.2.97" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d36ef12e3aaca16ddd3f67922bc63e48e953f126de60bd33ccc0101ef9998cd" -dependencies = [ - "bumpalo", - "log", - "once_cell", - "proc-macro2", - "quote", - "syn", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-macro" -version = "0.2.97" +version = "0.2.114" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "705440e08b42d3e4b36de7d66c944be628d579796b8090bfa3471478a2260051" +checksum = "18a2d50fcf105fb33bb15f00e7a77b772945a2ee45dcf454961fd843e74c18e6" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -1125,172 +1096,172 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.97" +version = "0.2.114" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "98c9ae5a76e46f4deecd0f0255cc223cfa18dc9b261213b8aa0c7b36f61b3f1d" +checksum = "03ce4caeaac547cdf713d280eda22a730824dd11e6b8c3ca9e42247b25c631e3" dependencies = [ + "bumpalo", "proc-macro2", "quote", "syn", - "wasm-bindgen-backend", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" -version = "0.2.97" +version = "0.2.114" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ee99da9c5ba11bd675621338ef6fa52296b76b83305e9b6e5c77d4c286d6d49" +checksum = "75a326b8c223ee17883a4251907455a2431acc2791c98c26279376490c378c16" +dependencies = [ + "unicode-ident", +] [[package]] name = "windows-core" -version = "0.52.0" +version = "0.62.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9" +checksum = "b8e83a14d34d0623b51dce9581199302a221863196a1dde71a7663a4c2be9deb" dependencies = [ - "windows-targets 0.52.0", + "windows-implement", + "windows-interface", + "windows-link", + "windows-result", + "windows-strings", ] [[package]] -name = "windows-sys" -version = "0.48.0" +name = "windows-implement" +version = "0.60.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" +checksum = "053e2e040ab57b9dc951b72c264860db7eb3b0200ba345b4e4c3b14f67855ddf" dependencies = [ - "windows-targets 0.48.5", + "proc-macro2", + "quote", + "syn", ] [[package]] -name = "windows-sys" -version = "0.52.0" +name = "windows-interface" +version = "0.59.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +checksum = "3f316c4a2570ba26bbec722032c4099d8c8bc095efccdc15688708623367e358" dependencies = [ - "windows-targets 0.52.0", + "proc-macro2", + "quote", + "syn", ] [[package]] -name = "windows-targets" -version = "0.48.5" +name = "windows-link" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" -dependencies = [ - "windows_aarch64_gnullvm 0.48.5", - "windows_aarch64_msvc 0.48.5", - "windows_i686_gnu 0.48.5", - "windows_i686_msvc 0.48.5", - "windows_x86_64_gnu 0.48.5", - "windows_x86_64_gnullvm 0.48.5", - "windows_x86_64_msvc 0.48.5", -] +checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" [[package]] -name = "windows-targets" -version = "0.52.0" +name = "windows-result" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a18201040b24831fbb9e4eb208f8892e1f50a37feb53cc7ff887feb8f50e7cd" +checksum = "7781fa89eaf60850ac3d2da7af8e5242a5ea78d1a11c49bf2910bb5a73853eb5" dependencies = [ - "windows_aarch64_gnullvm 0.52.0", - "windows_aarch64_msvc 0.52.0", - "windows_i686_gnu 0.52.0", - "windows_i686_msvc 0.52.0", - "windows_x86_64_gnu 0.52.0", - "windows_x86_64_gnullvm 0.52.0", - "windows_x86_64_msvc 0.52.0", + "windows-link", ] [[package]] -name = "windows_aarch64_gnullvm" -version = "0.48.5" +name = "windows-strings" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" +checksum = "7837d08f69c77cf6b07689544538e017c1bfcf57e34b4c0ff58e6c2cd3b37091" +dependencies = [ + "windows-link", +] [[package]] -name = "windows_aarch64_gnullvm" +name = "windows-sys" version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb7764e35d4db8a7921e09562a0304bf2f93e0a51bfccee0bd0bb0b666b015ea" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +dependencies = [ + "windows-targets", +] [[package]] -name = "windows_aarch64_msvc" -version = "0.48.5" +name = "windows-sys" +version = "0.61.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" +checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc" +dependencies = [ + "windows-link", +] [[package]] -name = "windows_aarch64_msvc" -version = "0.52.0" +name = "windows-targets" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbaa0368d4f1d2aaefc55b6fcfee13f41544ddf36801e793edbbfd7d7df075ef" +checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" +dependencies = [ + "windows_aarch64_gnullvm", + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_gnullvm", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc", +] [[package]] -name = "windows_i686_gnu" -version = "0.48.5" +name = "windows_aarch64_gnullvm" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" +checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" [[package]] -name = "windows_i686_gnu" -version = "0.52.0" +name = "windows_aarch64_msvc" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a28637cb1fa3560a16915793afb20081aba2c92ee8af57b4d5f28e4b3e7df313" +checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" [[package]] -name = "windows_i686_msvc" -version = "0.48.5" +name = "windows_i686_gnu" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" +checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" [[package]] -name = "windows_i686_msvc" -version = "0.52.0" +name = "windows_i686_gnullvm" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ffe5e8e31046ce6230cc7215707b816e339ff4d4d67c65dffa206fd0f7aa7b9a" +checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" [[package]] -name = "windows_x86_64_gnu" -version = "0.48.5" +name = "windows_i686_msvc" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" +checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" [[package]] name = "windows_x86_64_gnu" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d6fa32db2bc4a2f5abeacf2b69f7992cd09dca97498da74a151a3132c26befd" - -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.48.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" +checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" [[package]] name = "windows_x86_64_gnullvm" -version = "0.52.0" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a657e1e9d3f514745a572a6846d3c7aa7dbe1658c056ed9c3344c4109a6949e" +checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" [[package]] name = "windows_x86_64_msvc" -version = "0.48.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" +checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" [[package]] -name = "windows_x86_64_msvc" -version = "0.52.0" +name = "wit-bindgen" +version = "0.46.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dff9641d1cd4be8d1a070daf9e3773c5f67e78b4d9d42263020c057706765c04" - -[[package]] -name = "wit-bindgen-rt" -version = "0.39.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f42320e61fe2cfd34354ecb597f86f413484a798ba44a8ca1165c58d42da6c1" -dependencies = [ - "bitflags", -] +checksum = "f17a85883d4e6d00e8a97c586de764dabcc06133f7f1d55dce5cdc070ad7fe59" [[package]] name = "x509-certificate" @@ -1311,22 +1282,48 @@ dependencies = [ "zeroize", ] +[[package]] +name = "zerocopy" +version = "0.8.42" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2578b716f8a7a858b7f02d5bd870c14bf4ddbbcf3a4c05414ba6503640505e3" +dependencies = [ + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.8.42" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7e6cc098ea4d3bd6246687de65af3f920c430e236bee1e3bf2e441463f08a02f" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "zeroize" -version = "1.8.1" +version = "1.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde" +checksum = "b97154e67e32c85465826e8bcc1c59429aaaf107c1e4a9e53c8d8ccd5eff88d0" dependencies = [ "zeroize_derive", ] [[package]] name = "zeroize_derive" -version = "1.4.2" +version = "1.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" +checksum = "85a5b4158499876c763cb03bc4e49185d3cccbabb15b33c627f7884f43db852e" dependencies = [ "proc-macro2", "quote", "syn", ] + +[[package]] +name = "zmij" +version = "1.0.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8848ee67ecc8aedbaf3e4122217aff892639231befc6a1b58d29fff4c2cabaa" diff --git a/src/ua/data_types/status_code.rs b/src/ua/data_types/status_code.rs index db8ffbc3..231a4440 100644 --- a/src/ua/data_types/status_code.rs +++ b/src/ua/data_types/status_code.rs @@ -216,7 +216,6 @@ enum_variants!( BADSERVERURIINVALID, BADSERVERNAMEMISSING, BADDISCOVERYURLMISSING, - BADSEMPAHOREFILEMISSING, BADREQUESTTYPEINVALID, BADSECURITYMODEREJECTED, BADSECURITYPOLICYREJECTED, @@ -333,6 +332,7 @@ enum_variants!( GOODDATAIGNORED, BADREQUESTNOTALLOWED, BADREQUESTNOTCOMPLETE, + BADTRANSACTIONPENDING, BADTICKETREQUIRED, BADTICKETINVALID, GOODEDITED, From 1f204c0104a347611616dc86dadcc73ed6f1a441 Mon Sep 17 00:00:00 2001 From: Uwe Klotz Date: Thu, 19 Mar 2026 10:37:09 +0100 Subject: [PATCH 14/20] Update open62541-sys to fix linker errors --- Cargo.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.lock b/Cargo.lock index a4e17bde..6e7bb9ef 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -613,7 +613,7 @@ dependencies = [ [[package]] name = "open62541-sys" version = "0.5.4" -source = "git+https://github.com/HMIProject/open62541-sys.git?branch=open62541-1.5#dd4b0e2c36ca61ce8a434f112df475cfc0f11885" +source = "git+https://github.com/HMIProject/open62541-sys.git?branch=open62541-1.5#81bab141e0ea03ab0bd8b9de3e9bf546a2c2b577" dependencies = [ "bindgen", "cc", From d627825c4b20b6a38ba4209ad4fc16f6b0867f44 Mon Sep 17 00:00:00 2001 From: Uwe Klotz Date: Wed, 22 Apr 2026 11:58:50 +0200 Subject: [PATCH 15/20] Update to open62541 v1.5.4 --- Cargo.lock | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 6e7bb9ef..32f9300f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -144,9 +144,9 @@ checksum = "1e748733b7cbc798e1434b6ac524f0c1ff2ab456fe201501e6497c8417a4fc33" [[package]] name = "cc" -version = "1.2.57" +version = "1.2.60" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a0dd1ca384932ff3641c8718a02769f1698e7563dc6974ffd03346116310423" +checksum = "43c5703da9466b66a946814e1adf53ea2c90f10063b86290cc9eb67ce3478a20" dependencies = [ "find-msvc-tools", "shlex", @@ -191,9 +191,9 @@ dependencies = [ [[package]] name = "cmake" -version = "0.1.57" +version = "0.1.58" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75443c44cd6b379beb8c5b45d85d0773baf31cce901fe7bb252f4eff3008ef7d" +checksum = "c0f78a02292a74a88ac736019ab962ece0bc380e3f977bf72e376c5d78ff0678" dependencies = [ "cc", ] @@ -612,8 +612,8 @@ dependencies = [ [[package]] name = "open62541-sys" -version = "0.5.4" -source = "git+https://github.com/HMIProject/open62541-sys.git?branch=open62541-1.5#81bab141e0ea03ab0bd8b9de3e9bf546a2c2b577" +version = "0.6.0" +source = "git+https://github.com/HMIProject/open62541-sys.git?branch=open62541-1.5#239beab15a27cb501cfa4544ff816cd9593c14e3" dependencies = [ "bindgen", "cc", From eb0c1e1cbda4b849cbc28b8119e4a0c7c373f5d5 Mon Sep 17 00:00:00 2001 From: Uwe Klotz Date: Wed, 22 Apr 2026 12:05:02 +0200 Subject: [PATCH 16/20] Temporarily disabled packaging step --- .github/workflows/test.yaml | 15 ++++++++------- Cargo.toml | 2 ++ 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml index c4c84e6c..b876d92e 100644 --- a/.github/workflows/test.yaml +++ b/.github/workflows/test.yaml @@ -161,10 +161,11 @@ jobs: --locked --all-features --doc - - name: Build package with all features enabled - # Disable build for GNU targets on Ubuntu 22.04 (unsupported `atomic_uintptr_t`). - # TODO: Try to re-enable this step regardless of the build target in the future. - if: ${{ matrix.runner_os != 'ubuntu-22.04' || endsWith(matrix.target, '-musl') }} - run: >- - cargo package - --locked --all-features + # FIXME: Re-enable this step after switching to open62541-sys v0.6.x. + #- name: Build package with all features enabled + # Disable build for GNU targets on Ubuntu 22.04 (unsupported `atomic_uintptr_t`). + # TODO: Try to re-enable this step regardless of the build target in the future. + #if: ${{ matrix.runner_os != 'ubuntu-22.04' || endsWith(matrix.target, '-musl') }} + #run: >- + # cargo package + # --locked --all-features diff --git a/Cargo.toml b/Cargo.toml index 1437faab..b61a9381 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -21,6 +21,8 @@ futures-channel = "0.3.30" futures-core = { version = "0.3.30", default-features = false } log = "0.4.20" # FIXME: Revert before merge. +# FIXME: After depending on open62541-sys v0.6.x re-enable the final +# packaging step in .github/workflows/test.yaml. open62541-sys = { git = "https://github.com/HMIProject/open62541-sys.git", branch = "open62541-1.5" } parking_lot = "0.12.4" paste = "1.0.14" From c4244c489dabde47ef1d3302b85e4b6cd9e13a5c Mon Sep 17 00:00:00 2001 From: Uwe Klotz Date: Wed, 22 Apr 2026 12:06:27 +0200 Subject: [PATCH 17/20] Use oxfmt for formatting TOML files --- .pre-commit-config.yaml | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index a0909730..b2cd9dfe 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -36,11 +36,13 @@ repos: hooks: - id: check-github-actions - id: check-github-workflows - - repo: https://github.com/ComPWA/taplo-pre-commit - rev: v0.9.3 - hooks: - - id: taplo-format - - id: taplo-lint + # The taplo-lint checks have been disabled, because they only work with + # the newest Rust version and don't respect the `rust-version` field in + # `Cargo.toml`. + # - repo: https://github.com/ComPWA/taplo-pre-commit + # rev: v0.9.3 + # hooks: + # - id: taplo-lint # Format code with oxfmt for supported file types. - repo: https://github.com/oxc-project/mirrors-oxfmt rev: v0.43.0 @@ -49,6 +51,7 @@ repos: types_or: - json - markdown + - toml - yaml - repo: https://github.com/doublify/pre-commit-rust rev: v1.0 From eac45b32012771c9cbd959add5a04f2219a1bfa7 Mon Sep 17 00:00:00 2001 From: Uwe Klotz Date: Wed, 22 Apr 2026 12:09:16 +0200 Subject: [PATCH 18/20] Fix clippy warnings --- examples/server.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/server.rs b/examples/server.rs index a786ede2..eda85ea7 100644 --- a/examples/server.rs +++ b/examples/server.rs @@ -143,7 +143,7 @@ fn statistics_task(server: &Server, cancelled: &AtomicBool) { while !cancelled.load(Ordering::Relaxed) { let statistics = server.statistics(); println!("{statistics:?}"); - thread::sleep(Duration::from_millis(1000)); + thread::sleep(Duration::from_secs(1)); } } @@ -162,7 +162,7 @@ fn server_task( server.write_value(value_node_id, &ua::Variant::scalar(ua::String::new(value)?))?; - thread::sleep(Duration::from_millis(1000)); + thread::sleep(Duration::from_secs(1)); } } } From a35d3a5727ecdc8b1ec325c4fad0dc1cbbdb19fa Mon Sep 17 00:00:00 2001 From: Uwe Klotz Date: Wed, 22 Apr 2026 12:41:54 +0200 Subject: [PATCH 19/20] Temporarily disable cargo package in latest-dependencies --- .github/workflows/latest-dependencies.yaml | 20 +++++++++++--------- Cargo.toml | 4 ++-- 2 files changed, 13 insertions(+), 11 deletions(-) diff --git a/.github/workflows/latest-dependencies.yaml b/.github/workflows/latest-dependencies.yaml index 4d892dee..7dde495b 100644 --- a/.github/workflows/latest-dependencies.yaml +++ b/.github/workflows/latest-dependencies.yaml @@ -139,12 +139,14 @@ jobs: --locked --all-features --doc - - name: Build package with all features enabled - # Disable build for GNU targets on Ubuntu 22.04 (unsupported `atomic_uintptr_t`). - # TODO: Try to re-enable this step regardless of the build target in the future. - if: ${{ matrix.runner_os != 'ubuntu-22.04' || endsWith(matrix.target, '-musl') }} - # We allow dirty state here because it is only expected after update. - run: >- - cargo package - --locked --all-features - --allow-dirty + # FIXME: Re-enable this step after switching to open62541-sys v0.6.x. + #- name: Build package with all features enabled + #- name: Build package with all features enabled + # Disable build for GNU targets on Ubuntu 22.04 (unsupported `atomic_uintptr_t`). + # TODO: Try to re-enable this step regardless of the build target in the future. + #if: ${{ matrix.runner_os != 'ubuntu-22.04' || endsWith(matrix.target, '-musl') }} + # We allow dirty state here because it is only expected after update. + #run: >- + # cargo package + # --locked --all-features + # --allow-dirty diff --git a/Cargo.toml b/Cargo.toml index b61a9381..87d4f0b0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -21,8 +21,8 @@ futures-channel = "0.3.30" futures-core = { version = "0.3.30", default-features = false } log = "0.4.20" # FIXME: Revert before merge. -# FIXME: After depending on open62541-sys v0.6.x re-enable the final -# packaging step in .github/workflows/test.yaml. +# FIXME: After depending on open62541-sys v0.6.x re-enable the final packaging step +# in .github/workflows/test.yaml and .github/workflows/latest-dependencies.yaml. open62541-sys = { git = "https://github.com/HMIProject/open62541-sys.git", branch = "open62541-1.5" } parking_lot = "0.12.4" paste = "1.0.14" From fb9bee209661d86a4e7c8e1afd55a2af5f6db69e Mon Sep 17 00:00:00 2001 From: Uwe Klotz Date: Wed, 27 May 2026 10:33:51 +0200 Subject: [PATCH 20/20] Update open62541-sys dependency --- Cargo.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.lock b/Cargo.lock index 32f9300f..ebe3edb2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -613,7 +613,7 @@ dependencies = [ [[package]] name = "open62541-sys" version = "0.6.0" -source = "git+https://github.com/HMIProject/open62541-sys.git?branch=open62541-1.5#239beab15a27cb501cfa4544ff816cd9593c14e3" +source = "git+https://github.com/HMIProject/open62541-sys.git?branch=open62541-1.5#ffda3c08c1b7eaa7cfa5a5c24b3ea5db58c3c29e" dependencies = [ "bindgen", "cc",