Sfoglia il codice sorgente

rust: Improve Rust bindings

The big change here is that all API calls now take a &Handle
rather than making a copy. This, apart from being more sensible
and efficient, allows us to implment Drop on the handle so that
it will call _free() when it goes out of scope.

There's some jiggery-pokery with a clone flag in there now
because of callbacks that can return a valid handle, and we
want those to be Drop'ed sensibly.

Signed-off-by: Christine Caulfield <ccaulfie@redhat.com>
Reviewed-by: Jan Friesse <jfriesse@redhat.com>
Christine Caulfield 2 anni fa
parent
commit
58d654261a

+ 40 - 14
bindings/rust/src/cfg.rs

@@ -31,10 +31,35 @@ pub struct Callbacks {
 }
 
 /// A handle into the cfg library. returned from [initialize] and needed for all other calls
-#[derive(Copy, Clone)]
 pub struct Handle {
     cfg_handle: u64,
     callbacks: Callbacks,
+    clone: bool,
+}
+
+impl Clone for Handle {
+    fn clone(&self) -> Handle {
+        Handle {
+            cfg_handle: self.cfg_handle,
+            callbacks: self.callbacks,
+            clone: true,
+        }
+    }
+}
+
+impl Drop for Handle {
+    fn drop(self: &mut Handle) {
+        if !self.clone {
+            let _e = finalize(self);
+        }
+    }
+}
+
+// Clones count as equivalent
+impl PartialEq for Handle {
+    fn eq(&self, other: &Handle) -> bool {
+        self.cfg_handle == other.cfg_handle
+    }
 }
 
 /// Flags for [try_shutdown]
@@ -114,8 +139,9 @@ pub fn initialize(callbacks: &Callbacks) -> Result<Handle> {
             let rhandle = Handle {
                 cfg_handle: handle,
                 callbacks: *callbacks,
+                clone: false,
             };
-            HANDLE_HASH.lock().unwrap().insert(handle, rhandle);
+            HANDLE_HASH.lock().unwrap().insert(handle, rhandle.clone());
             Ok(rhandle)
         } else {
             Err(CsError::from_c(res))
@@ -124,7 +150,7 @@ pub fn initialize(callbacks: &Callbacks) -> Result<Handle> {
 }
 
 /// Finish with a connection to corosync, after calling this the [Handle] is invalid
-pub fn finalize(handle: Handle) -> Result<()> {
+pub fn finalize(handle: &Handle) -> Result<()> {
     let res = unsafe { ffi::corosync_cfg_finalize(handle.cfg_handle) };
     if res == ffi::CS_OK {
         HANDLE_HASH.lock().unwrap().remove(&handle.cfg_handle);
@@ -136,7 +162,7 @@ pub fn finalize(handle: Handle) -> Result<()> {
 
 // not sure if an fd is the right thing to return here, but it will do for now.
 /// Returns a file descriptor to use for poll/select on the CFG handle
-pub fn fd_get(handle: Handle) -> Result<i32> {
+pub fn fd_get(handle: &Handle) -> Result<i32> {
     let c_fd: *mut c_int = &mut 0 as *mut _ as *mut c_int;
     let res = unsafe { ffi::corosync_cfg_fd_get(handle.cfg_handle, c_fd) };
     if res == ffi::CS_OK {
@@ -147,7 +173,7 @@ pub fn fd_get(handle: Handle) -> Result<i32> {
 }
 
 /// Get the local [NodeId]
-pub fn local_get(handle: Handle) -> Result<NodeId> {
+pub fn local_get(handle: &Handle) -> Result<NodeId> {
     let mut nodeid: u32 = 0;
     let res = unsafe { ffi::corosync_cfg_local_get(handle.cfg_handle, &mut nodeid) };
     if res == ffi::CS_OK {
@@ -158,7 +184,7 @@ pub fn local_get(handle: Handle) -> Result<NodeId> {
 }
 
 /// Reload the cluster configuration on all nodes
-pub fn reload_cnfig(handle: Handle) -> Result<()> {
+pub fn reload_cnfig(handle: &Handle) -> Result<()> {
     let res = unsafe { ffi::corosync_cfg_reload_config(handle.cfg_handle) };
     if res == ffi::CS_OK {
         Ok(())
@@ -168,7 +194,7 @@ pub fn reload_cnfig(handle: Handle) -> Result<()> {
 }
 
 /// Re-open the cluster log files, on this node only
-pub fn reopen_log_files(handle: Handle) -> Result<()> {
+pub fn reopen_log_files(handle: &Handle) -> Result<()> {
     let res = unsafe { ffi::corosync_cfg_reopen_log_files(handle.cfg_handle) };
     if res == ffi::CS_OK {
         Ok(())
@@ -179,7 +205,7 @@ pub fn reopen_log_files(handle: Handle) -> Result<()> {
 
 /// Tell another cluster node to shutdown. reason is a string that
 /// will be written to the system log files.
-pub fn kill_node(handle: Handle, nodeid: NodeId, reason: &str) -> Result<()> {
+pub fn kill_node(handle: &Handle, nodeid: NodeId, reason: &str) -> Result<()> {
     let c_string = {
         match CString::new(reason) {
             Ok(cs) => cs,
@@ -200,7 +226,7 @@ pub fn kill_node(handle: Handle, nodeid: NodeId, reason: &str) -> Result<()> {
 /// Ask this cluster node to shutdown. If [ShutdownFlags] is set to Request then
 ///it may be refused by other applications
 /// that have registered for shutdown callbacks.
-pub fn try_shutdown(handle: Handle, flags: ShutdownFlags) -> Result<()> {
+pub fn try_shutdown(handle: &Handle, flags: ShutdownFlags) -> Result<()> {
     let c_flags = match flags {
         ShutdownFlags::Request => 0,
         ShutdownFlags::Regardless => 1,
@@ -215,7 +241,7 @@ pub fn try_shutdown(handle: Handle, flags: ShutdownFlags) -> Result<()> {
 }
 
 /// Reply to a shutdown request with Yes or No [ShutdownReply]
-pub fn reply_to_shutdown(handle: Handle, flags: ShutdownReply) -> Result<()> {
+pub fn reply_to_shutdown(handle: &Handle, flags: ShutdownReply) -> Result<()> {
     let c_flags = match flags {
         ShutdownReply::No => 0,
         ShutdownReply::Yes => 1,
@@ -229,7 +255,7 @@ pub fn reply_to_shutdown(handle: Handle, flags: ShutdownReply) -> Result<()> {
 }
 
 /// Call any/all active CFG callbacks for this [Handle] see [DispatchFlags] for details
-pub fn dispatch(handle: Handle, flags: DispatchFlags) -> Result<()> {
+pub fn dispatch(handle: &Handle, flags: DispatchFlags) -> Result<()> {
     let res = unsafe { ffi::corosync_cfg_dispatch(handle.cfg_handle, flags as u32) };
     if res == ffi::CS_OK {
         Ok(())
@@ -293,7 +319,7 @@ fn new_ls() -> ffi::corosync_knet_link_status_v1 {
 /// Get the extended status of a node in the cluster (including active links) from its [NodeId].
 /// Returns a filled in [NodeStatus] struct
 pub fn node_status_get(
-    handle: Handle,
+    handle: &Handle,
     nodeid: NodeId,
     _version: NodeStatusVersion,
 ) -> Result<NodeStatus> {
@@ -328,7 +354,7 @@ pub fn node_status_get(
 }
 
 /// Start tracking for shutdown notifications
-pub fn track_start(handle: Handle, _flags: TrackFlags) -> Result<()> {
+pub fn track_start(handle: &Handle, _flags: TrackFlags) -> Result<()> {
     let res = unsafe { ffi::corosync_cfg_trackstart(handle.cfg_handle, 0) };
     if res == ffi::CS_OK {
         Ok(())
@@ -338,7 +364,7 @@ pub fn track_start(handle: Handle, _flags: TrackFlags) -> Result<()> {
 }
 
 /// Stop tracking for shutdown notifications
-pub fn track_stop(handle: Handle) -> Result<()> {
+pub fn track_stop(handle: &Handle) -> Result<()> {
     let res = unsafe { ffi::corosync_cfg_trackstop(handle.cfg_handle) };
     if res == ffi::CS_OK {
         Ok(())

+ 50 - 26
bindings/rust/src/cmap.rs

@@ -62,10 +62,33 @@ impl fmt::Display for TrackType {
     }
 }
 
-#[derive(Copy, Clone)]
 /// A handle returned from [initialize], needs to be passed to all other cmap API calls
 pub struct Handle {
     cmap_handle: u64,
+    clone: bool,
+}
+
+impl Clone for Handle {
+    fn clone(&self) -> Handle {
+        Handle {
+            cmap_handle: self.cmap_handle,
+            clone: true,
+        }
+    }
+}
+
+impl Drop for Handle {
+    fn drop(self: &mut Handle) {
+        if !self.clone {
+            let _e = finalize(self);
+        }
+    }
+}
+// Clones count as equivalent
+impl PartialEq for Handle {
+    fn eq(&self, other: &Handle) -> bool {
+        self.cmap_handle == other.cmap_handle
+    }
 }
 
 #[derive(Copy, Clone)]
@@ -97,8 +120,9 @@ pub fn initialize(map: Map) -> Result<Handle> {
         if res == ffi::CS_OK {
             let rhandle = Handle {
                 cmap_handle: handle,
+                clone: false,
             };
-            HANDLE_HASH.lock().unwrap().insert(handle, rhandle);
+            HANDLE_HASH.lock().unwrap().insert(handle, rhandle.clone());
             Ok(rhandle)
         } else {
             Err(CsError::from_c(res))
@@ -108,7 +132,7 @@ pub fn initialize(map: Map) -> Result<Handle> {
 
 /// Finish with a connection to corosync.
 /// Takes a [Handle] as returned from [initialize]
-pub fn finalize(handle: Handle) -> Result<()> {
+pub fn finalize(handle: &Handle) -> Result<()> {
     let res = unsafe { ffi::cmap_finalize(handle.cmap_handle) };
     if res == ffi::CS_OK {
         HANDLE_HASH.lock().unwrap().remove(&handle.cmap_handle);
@@ -121,7 +145,7 @@ pub fn finalize(handle: Handle) -> Result<()> {
 /// Return a file descriptor to use for poll/select on the CMAP handle.
 /// Takes a [Handle] as returned from [initialize],
 /// returns a C file descriptor as i32
-pub fn fd_get(handle: Handle) -> Result<i32> {
+pub fn fd_get(handle: &Handle) -> Result<i32> {
     let c_fd: *mut c_int = &mut 0 as *mut _ as *mut c_int;
     let res = unsafe { ffi::cmap_fd_get(handle.cmap_handle, c_fd) };
     if res == ffi::CS_OK {
@@ -134,7 +158,7 @@ pub fn fd_get(handle: Handle) -> Result<i32> {
 /// Dispatch any/all active CMAP callbacks.
 /// Takes a [Handle] as returned from [initialize],
 /// flags [DispatchFlags] tells it how many items to dispatch before returning
-pub fn dispatch(handle: Handle, flags: DispatchFlags) -> Result<()> {
+pub fn dispatch(handle: &Handle, flags: DispatchFlags) -> Result<()> {
     let res = unsafe { ffi::cmap_dispatch(handle.cmap_handle, flags as u32) };
     if res == ffi::CS_OK {
         Ok(())
@@ -146,7 +170,7 @@ pub fn dispatch(handle: Handle, flags: DispatchFlags) -> Result<()> {
 /// Get the current 'context' value for this handle
 /// The context value is an arbitrary value that is always passed
 /// back to callbacks to help identify the source
-pub fn context_get(handle: Handle) -> Result<u64> {
+pub fn context_get(handle: &Handle) -> Result<u64> {
     let (res, context) = unsafe {
         let mut context: u64 = 0;
         let c_context: *mut c_void = &mut context as *mut _ as *mut c_void;
@@ -164,7 +188,7 @@ pub fn context_get(handle: Handle) -> Result<u64> {
 /// The context value is an arbitrary value that is always passed
 /// back to callbacks to help identify the source.
 /// Normally this is set in [initialize], but this allows it to be changed
-pub fn context_set(handle: Handle, context: u64) -> Result<()> {
+pub fn context_set(handle: &Handle, context: u64) -> Result<()> {
     let res = unsafe {
         let c_context = context as *mut c_void;
         ffi::cmap_context_set(handle.cmap_handle, c_context)
@@ -274,7 +298,7 @@ fn string_to_cstring_validated(key: &str, maxlen: usize) -> Result<CString> {
 }
 
 fn set_value(
-    handle: Handle,
+    handle: &Handle,
     key_name: &str,
     datatype: DataType,
     value: *mut c_void,
@@ -333,7 +357,7 @@ fn is_numeric_type(dtype: DataType) -> bool {
 
 /// Function to set a generic numeric value
 /// This doesn't work for strings or binaries
-pub fn set_number<T: Copy>(handle: Handle, key_name: &str, value: T) -> Result<()> {
+pub fn set_number<T: Copy>(handle: &Handle, key_name: &str, value: T) -> Result<()> {
     let (c_type, c_size) = generic_to_cmap(value);
 
     if is_numeric_type(c_type) {
@@ -345,21 +369,21 @@ pub fn set_number<T: Copy>(handle: Handle, key_name: &str, value: T) -> Result<(
     }
 }
 
-pub fn set_u8(handle: Handle, key_name: &str, value: u8) -> Result<()> {
+pub fn set_u8(handle: &Handle, key_name: &str, value: u8) -> Result<()> {
     let mut tmp = value;
     let c_value: *mut c_void = &mut tmp as *mut _ as *mut c_void;
     set_value(handle, key_name, DataType::UInt8, c_value as *mut c_void, 1)
 }
 
 /// Sets an i8 value into cmap
-pub fn set_i8(handle: Handle, key_name: &str, value: i8) -> Result<()> {
+pub fn set_i8(handle: &Handle, key_name: &str, value: i8) -> Result<()> {
     let mut tmp = value;
     let c_value: *mut c_void = &mut tmp as *mut _ as *mut c_void;
     set_value(handle, key_name, DataType::Int8, c_value as *mut c_void, 1)
 }
 
 /// Sets a u16 value into cmap
-pub fn set_u16(handle: Handle, key_name: &str, value: u16) -> Result<()> {
+pub fn set_u16(handle: &Handle, key_name: &str, value: u16) -> Result<()> {
     let mut tmp = value;
     let c_value: *mut c_void = &mut tmp as *mut _ as *mut c_void;
     set_value(
@@ -372,28 +396,28 @@ pub fn set_u16(handle: Handle, key_name: &str, value: u16) -> Result<()> {
 }
 
 /// Sets an i16 value into cmap
-pub fn set_i16(handle: Handle, key_name: &str, value: i16) -> Result<()> {
+pub fn set_i16(handle: &Handle, key_name: &str, value: i16) -> Result<()> {
     let mut tmp = value;
     let c_value: *mut c_void = &mut tmp as *mut _ as *mut c_void;
     set_value(handle, key_name, DataType::Int16, c_value as *mut c_void, 2)
 }
 
 /// Sets a u32 value into cmap
-pub fn set_u32(handle: Handle, key_name: &str, value: u32) -> Result<()> {
+pub fn set_u32(handle: &Handle, key_name: &str, value: u32) -> Result<()> {
     let mut tmp = value;
     let c_value: *mut c_void = &mut tmp as *mut _ as *mut c_void;
     set_value(handle, key_name, DataType::UInt32, c_value, 4)
 }
 
 /// Sets an i32 value into cmap
-pub fn set_i132(handle: Handle, key_name: &str, value: i32) -> Result<()> {
+pub fn set_i132(handle: &Handle, key_name: &str, value: i32) -> Result<()> {
     let mut tmp = value;
     let c_value: *mut c_void = &mut tmp as *mut _ as *mut c_void;
     set_value(handle, key_name, DataType::Int32, c_value as *mut c_void, 4)
 }
 
 /// Sets a u64 value into cmap
-pub fn set_u64(handle: Handle, key_name: &str, value: u64) -> Result<()> {
+pub fn set_u64(handle: &Handle, key_name: &str, value: u64) -> Result<()> {
     let mut tmp = value;
     let c_value: *mut c_void = &mut tmp as *mut _ as *mut c_void;
     set_value(
@@ -406,14 +430,14 @@ pub fn set_u64(handle: Handle, key_name: &str, value: u64) -> Result<()> {
 }
 
 /// Sets an i64 value into cmap
-pub fn set_i164(handle: Handle, key_name: &str, value: i64) -> Result<()> {
+pub fn set_i164(handle: &Handle, key_name: &str, value: i64) -> Result<()> {
     let mut tmp = value;
     let c_value: *mut c_void = &mut tmp as *mut _ as *mut c_void;
     set_value(handle, key_name, DataType::Int64, c_value as *mut c_void, 8)
 }
 
 /// Sets a string value into cmap
-pub fn set_string(handle: Handle, key_name: &str, value: &str) -> Result<()> {
+pub fn set_string(handle: &Handle, key_name: &str, value: &str) -> Result<()> {
     let v_string = string_to_cstring_validated(value, 0)?;
     set_value(
         handle,
@@ -425,7 +449,7 @@ pub fn set_string(handle: Handle, key_name: &str, value: &str) -> Result<()> {
 }
 
 /// Sets a binary value into cmap
-pub fn set_binary(handle: Handle, key_name: &str, value: &[u8]) -> Result<()> {
+pub fn set_binary(handle: &Handle, key_name: &str, value: &[u8]) -> Result<()> {
     set_value(
         handle,
         key_name,
@@ -436,7 +460,7 @@ pub fn set_binary(handle: Handle, key_name: &str, value: &[u8]) -> Result<()> {
 }
 
 /// Sets a [Data] type into cmap
-pub fn set(handle: Handle, key_name: &str, data: &Data) -> Result<()> {
+pub fn set(handle: &Handle, key_name: &str, data: &Data) -> Result<()> {
     let (datatype, datalen, c_value) = match data {
         Data::Int8(v) => {
             let mut tmp = *v;
@@ -597,7 +621,7 @@ fn c_to_data(value_size: usize, c_key_type: u32, c_value: *const u8) -> Result<D
 const INITIAL_SIZE: usize = 256;
 
 /// Get a value from cmap, returned as a [Data] struct, so could be anything
-pub fn get(handle: Handle, key_name: &str) -> Result<Data> {
+pub fn get(handle: &Handle, key_name: &str) -> Result<Data> {
     let csname = string_to_cstring_validated(key_name, CMAP_KEYNAME_MAXLENGTH)?;
     let mut value_size: usize = 16;
     let mut c_key_type: u32 = 0;
@@ -638,7 +662,7 @@ pub fn get(handle: Handle, key_name: &str) -> Result<Data> {
 }
 
 /// increment the value in a cmap key (must be a numeric type)
-pub fn inc(handle: Handle, key_name: &str) -> Result<()> {
+pub fn inc(handle: &Handle, key_name: &str) -> Result<()> {
     let csname = string_to_cstring_validated(key_name, CMAP_KEYNAME_MAXLENGTH)?;
     let res = unsafe { ffi::cmap_inc(handle.cmap_handle, csname.as_ptr()) };
     if res == ffi::CS_OK {
@@ -649,7 +673,7 @@ pub fn inc(handle: Handle, key_name: &str) -> Result<()> {
 }
 
 /// decrement the value in a cmap key (must be a numeric type)
-pub fn dec(handle: Handle, key_name: &str) -> Result<()> {
+pub fn dec(handle: &Handle, key_name: &str) -> Result<()> {
     let csname = string_to_cstring_validated(key_name, CMAP_KEYNAME_MAXLENGTH)?;
     let res = unsafe { ffi::cmap_dec(handle.cmap_handle, csname.as_ptr()) };
     if res == ffi::CS_OK {
@@ -721,7 +745,7 @@ pub struct NotifyCallback {
 
 /// Track changes in cmap values, multiple [TrackHandle]s per [Handle] are allowed
 pub fn track_add(
-    handle: Handle,
+    handle: &Handle,
     key_name: &str,
     track_type: TrackType,
     notify_callback: &NotifyCallback,
@@ -755,7 +779,7 @@ pub fn track_add(
 }
 
 /// Remove a tracker frm this [Handle]
-pub fn track_delete(handle: Handle, track_handle: TrackHandle) -> Result<()> {
+pub fn track_delete(handle: &Handle, track_handle: TrackHandle) -> Result<()> {
     let res = unsafe { ffi::cmap_track_delete(handle.cmap_handle, track_handle.track_handle) };
     if res == ffi::CS_OK {
         TRACKHANDLE_HASH
@@ -864,7 +888,7 @@ impl Iterator for CmapIntoIter {
 
 impl CmapIterStart {
     /// Create a new [CmapIterStart] object for iterating over a list of cmap keys
-    pub fn new(cmap_handle: Handle, prefix: &str) -> Result<CmapIterStart> {
+    pub fn new(cmap_handle: &Handle, prefix: &str) -> Result<CmapIterStart> {
         let mut iter_handle: u64 = 0;
         let res = unsafe {
             let c_prefix = string_to_cstring_validated(prefix, CMAP_KEYNAME_MAXLENGTH)?;

+ 41 - 15
bindings/rust/src/cpg.rs

@@ -160,10 +160,35 @@ pub enum ModelData {
 }
 
 /// A handle into the cpg library. Returned from [initialize] and needed for all other calls
-#[derive(Copy, Clone)]
 pub struct Handle {
     cpg_handle: u64, // Corosync library handle
     model_data: ModelData,
+    clone: bool,
+}
+
+impl Clone for Handle {
+    fn clone(&self) -> Handle {
+        Handle {
+            cpg_handle: self.cpg_handle,
+            model_data: self.model_data,
+            clone: true,
+        }
+    }
+}
+
+impl Drop for Handle {
+    fn drop(self: &mut Handle) {
+        if !self.clone {
+            let _e = finalize(self);
+        }
+    }
+}
+
+// Clones count as equivalent
+impl PartialEq for Handle {
+    fn eq(&self, other: &Handle) -> bool {
+        self.cpg_handle == other.cpg_handle
+    }
 }
 
 // Used to convert a CPG handle into one of ours
@@ -329,8 +354,9 @@ pub fn initialize(model_data: &ModelData, context: u64) -> Result<Handle> {
             let rhandle = Handle {
                 cpg_handle: handle,
                 model_data: *model_data,
+                clone: false,
             };
-            HANDLE_HASH.lock().unwrap().insert(handle, rhandle);
+            HANDLE_HASH.lock().unwrap().insert(handle, rhandle.clone());
             Ok(rhandle)
         } else {
             Err(CsError::from_c(res))
@@ -339,7 +365,7 @@ pub fn initialize(model_data: &ModelData, context: u64) -> Result<Handle> {
 }
 
 /// Finish with a connection to corosync
-pub fn finalize(handle: Handle) -> Result<()> {
+pub fn finalize(handle: &Handle) -> Result<()> {
     let res = unsafe { ffi::cpg_finalize(handle.cpg_handle) };
     if res == ffi::CS_OK {
         HANDLE_HASH.lock().unwrap().remove(&handle.cpg_handle);
@@ -351,7 +377,7 @@ pub fn finalize(handle: Handle) -> Result<()> {
 
 // Not sure if an FD is the right thing to return here, but it will do for now.
 /// Returns a file descriptor to use for poll/select on the CPG handle
-pub fn fd_get(handle: Handle) -> Result<i32> {
+pub fn fd_get(handle: &Handle) -> Result<i32> {
     let c_fd: *mut c_int = &mut 0 as *mut _ as *mut c_int;
     let res = unsafe { ffi::cpg_fd_get(handle.cpg_handle, c_fd) };
     if res == ffi::CS_OK {
@@ -362,7 +388,7 @@ pub fn fd_get(handle: Handle) -> Result<i32> {
 }
 
 /// Call any/all active CPG callbacks for this [Handle] see [DispatchFlags] for details
-pub fn dispatch(handle: Handle, flags: DispatchFlags) -> Result<()> {
+pub fn dispatch(handle: &Handle, flags: DispatchFlags) -> Result<()> {
     let res = unsafe { ffi::cpg_dispatch(handle.cpg_handle, flags as u32) };
     if res == ffi::CS_OK {
         Ok(())
@@ -372,7 +398,7 @@ pub fn dispatch(handle: Handle, flags: DispatchFlags) -> Result<()> {
 }
 
 /// Joins a CPG group for sending and receiving messages
-pub fn join(handle: Handle, group: &str) -> Result<()> {
+pub fn join(handle: &Handle, group: &str) -> Result<()> {
     let res = unsafe {
         let c_group = string_to_cpg_name(group)?;
         ffi::cpg_join(handle.cpg_handle, &c_group)
@@ -386,7 +412,7 @@ pub fn join(handle: Handle, group: &str) -> Result<()> {
 
 /// Leave the currently joined CPG group, another group can now be joined on
 /// the same [Handle] or [finalize] can be called to finish using CPG
-pub fn leave(handle: Handle, group: &str) -> Result<()> {
+pub fn leave(handle: &Handle, group: &str) -> Result<()> {
     let res = unsafe {
         let c_group = string_to_cpg_name(group)?;
         ffi::cpg_leave(handle.cpg_handle, &c_group)
@@ -399,7 +425,7 @@ pub fn leave(handle: Handle, group: &str) -> Result<()> {
 }
 
 /// Get the local node ID
-pub fn local_get(handle: Handle) -> Result<NodeId> {
+pub fn local_get(handle: &Handle) -> Result<NodeId> {
     let mut nodeid: u32 = 0;
     let res = unsafe { ffi::cpg_local_get(handle.cpg_handle, &mut nodeid) };
     if res == ffi::CS_OK {
@@ -410,7 +436,7 @@ pub fn local_get(handle: Handle) -> Result<NodeId> {
 }
 
 /// Get a list of members of a CPG group as a vector of [Address] structs
-pub fn membership_get(handle: Handle, group: &str) -> Result<Vec<Address>> {
+pub fn membership_get(handle: &Handle, group: &str) -> Result<Vec<Address>> {
     let mut member_list_entries: i32 = 0;
     let member_list = [ffi::cpg_address {
         nodeid: 0,
@@ -440,7 +466,7 @@ pub fn membership_get(handle: Handle, group: &str) -> Result<Vec<Address>> {
 /// Get the maximum size that CPG can send in one corosync message,
 /// any messages sent via [mcast_joined] that are larger than this
 /// will be fragmented
-pub fn max_atomic_msgsize_get(handle: Handle) -> Result<u32> {
+pub fn max_atomic_msgsize_get(handle: &Handle) -> Result<u32> {
     let mut asize: u32 = 0;
     let res = unsafe { ffi::cpg_max_atomic_msgsize_get(handle.cpg_handle, &mut asize) };
     if res == ffi::CS_OK {
@@ -453,7 +479,7 @@ pub fn max_atomic_msgsize_get(handle: Handle) -> Result<u32> {
 /// Get the current 'context' value for this handle.
 /// The context value is an arbitrary value that is always passed
 /// back to callbacks to help identify the source
-pub fn context_get(handle: Handle) -> Result<u64> {
+pub fn context_get(handle: &Handle) -> Result<u64> {
     let mut c_context: *mut c_void = &mut 0u64 as *mut _ as *mut c_void;
     let (res, context) = unsafe {
         let r = ffi::cpg_context_get(handle.cpg_handle, &mut c_context);
@@ -471,7 +497,7 @@ pub fn context_get(handle: Handle) -> Result<u64> {
 /// The context value is an arbitrary value that is always passed
 /// back to callbacks to help identify the source.
 /// Normally this is set in [initialize], but this allows it to be changed
-pub fn context_set(handle: Handle, context: u64) -> Result<()> {
+pub fn context_set(handle: &Handle, context: u64) -> Result<()> {
     let res = unsafe {
         let c_context = context as *mut c_void;
         ffi::cpg_context_set(handle.cpg_handle, c_context)
@@ -484,7 +510,7 @@ pub fn context_set(handle: Handle, context: u64) -> Result<()> {
 }
 
 /// Get the flow control state of corosync CPG
-pub fn flow_control_state_get(handle: Handle) -> Result<bool> {
+pub fn flow_control_state_get(handle: &Handle) -> Result<bool> {
     let mut fc_state: u32 = 0;
     let res = unsafe { ffi::cpg_flow_control_state_get(handle.cpg_handle, &mut fc_state) };
     if res == ffi::CS_OK {
@@ -499,7 +525,7 @@ pub fn flow_control_state_get(handle: Handle) -> Result<bool> {
 }
 
 /// Send a message to the currently joined CPG group
-pub fn mcast_joined(handle: Handle, guarantee: Guarantee, msg: &[u8]) -> Result<()> {
+pub fn mcast_joined(handle: &Handle, guarantee: Guarantee, msg: &[u8]) -> Result<()> {
     let c_iovec = ffi::iovec {
         iov_base: msg.as_ptr() as *mut c_void,
         iov_len: msg.len(),
@@ -589,7 +615,7 @@ impl Iterator for CpgIntoIter {
 
 impl CpgIterStart {
     /// Create a new [CpgIterStart] object for iterating over a list of active CPG groups
-    pub fn new(cpg_handle: Handle, group: &str, iter_type: CpgIterType) -> Result<CpgIterStart> {
+    pub fn new(cpg_handle: &Handle, group: &str, iter_type: CpgIterType) -> Result<CpgIterStart> {
         let mut iter_handle: u64 = 0;
         let res = unsafe {
             let mut c_group = string_to_cpg_name(group)?;

+ 36 - 10
bindings/rust/src/quorum.rs

@@ -137,10 +137,35 @@ pub struct Model1Data {
 }
 
 /// A handle into the quorum library. Returned from [initialize] and needed for all other calls
-#[derive(Copy, Clone)]
 pub struct Handle {
     quorum_handle: u64,
     model_data: ModelData,
+    clone: bool,
+}
+
+impl Clone for Handle {
+    fn clone(&self) -> Handle {
+        Handle {
+            quorum_handle: self.quorum_handle,
+            model_data: self.model_data,
+            clone: true,
+        }
+    }
+}
+
+impl Drop for Handle {
+    fn drop(self: &mut Handle) {
+        if !self.clone {
+            let _e = finalize(self);
+        }
+    }
+}
+
+// Clones count as equivalent
+impl PartialEq for Handle {
+    fn eq(&self, other: &Handle) -> bool {
+        self.quorum_handle == other.quorum_handle
+    }
 }
 
 /// Initialize a connection to the quorum library. You must call this before doing anything
@@ -187,13 +212,14 @@ pub fn initialize(model_data: &ModelData, context: u64) -> Result<(Handle, Quoru
     let rhandle = Handle {
         quorum_handle: handle,
         model_data: *model_data,
+        clone: false,
     };
-    HANDLE_HASH.lock().unwrap().insert(handle, rhandle);
+    HANDLE_HASH.lock().unwrap().insert(handle, rhandle.clone());
     Ok((rhandle, quorum_type))
 }
 
 /// Finish with a connection to corosync
-pub fn finalize(handle: Handle) -> Result<()> {
+pub fn finalize(handle: &Handle) -> Result<()> {
     let res = unsafe { ffi::quorum_finalize(handle.quorum_handle) };
     if res == ffi::CS_OK {
         HANDLE_HASH.lock().unwrap().remove(&handle.quorum_handle);
@@ -205,7 +231,7 @@ pub fn finalize(handle: Handle) -> Result<()> {
 
 // Not sure if an FD is the right thing to return here, but it will do for now.
 /// Return a file descriptor to use for poll/select on the QUORUM handle
-pub fn fd_get(handle: Handle) -> Result<i32> {
+pub fn fd_get(handle: &Handle) -> Result<i32> {
     let c_fd: *mut c_int = &mut 0 as *mut _ as *mut c_int;
     let res = unsafe { ffi::quorum_fd_get(handle.quorum_handle, c_fd) };
     if res == ffi::CS_OK {
@@ -216,7 +242,7 @@ pub fn fd_get(handle: Handle) -> Result<i32> {
 }
 
 /// Display any/all active QUORUM callbacks for this [Handle], see [DispatchFlags] for details
-pub fn dispatch(handle: Handle, flags: DispatchFlags) -> Result<()> {
+pub fn dispatch(handle: &Handle, flags: DispatchFlags) -> Result<()> {
     let res = unsafe { ffi::quorum_dispatch(handle.quorum_handle, flags as u32) };
     if res == ffi::CS_OK {
         Ok(())
@@ -226,7 +252,7 @@ pub fn dispatch(handle: Handle, flags: DispatchFlags) -> Result<()> {
 }
 
 /// Return the quorate status of the cluster
-pub fn getquorate(handle: Handle) -> Result<bool> {
+pub fn getquorate(handle: &Handle) -> Result<bool> {
     let c_quorate: *mut c_int = &mut 0 as *mut _ as *mut c_int;
     let (res, r_quorate) = unsafe {
         let res = ffi::quorum_getquorate(handle.quorum_handle, c_quorate);
@@ -245,7 +271,7 @@ pub fn getquorate(handle: Handle) -> Result<bool> {
 }
 
 /// Track node and quorum changes
-pub fn trackstart(handle: Handle, flags: TrackFlags) -> Result<()> {
+pub fn trackstart(handle: &Handle, flags: TrackFlags) -> Result<()> {
     let res = unsafe { ffi::quorum_trackstart(handle.quorum_handle, flags as u32) };
     if res == ffi::CS_OK {
         Ok(())
@@ -255,7 +281,7 @@ pub fn trackstart(handle: Handle, flags: TrackFlags) -> Result<()> {
 }
 
 /// Stop tracking node and quorum changes
-pub fn trackstop(handle: Handle) -> Result<()> {
+pub fn trackstop(handle: &Handle) -> Result<()> {
     let res = unsafe { ffi::quorum_trackstop(handle.quorum_handle) };
     if res == ffi::CS_OK {
         Ok(())
@@ -267,7 +293,7 @@ pub fn trackstop(handle: Handle) -> Result<()> {
 /// Get the current 'context' value for this handle.
 /// The context value is an arbitrary value that is always passed
 /// back to callbacks to help identify the source
-pub fn context_get(handle: Handle) -> Result<u64> {
+pub fn context_get(handle: &Handle) -> Result<u64> {
     let (res, context) = unsafe {
         let mut context: u64 = 0;
         let c_context: *mut c_void = &mut context as *mut _ as *mut c_void;
@@ -285,7 +311,7 @@ pub fn context_get(handle: Handle) -> Result<u64> {
 /// The context value is an arbitrary value that is always passed
 /// back to callbacks to help identify the source.
 /// Normally this is set in [initialize], but this allows it to be changed
-pub fn context_set(handle: Handle, context: u64) -> Result<()> {
+pub fn context_set(handle: &Handle, context: u64) -> Result<()> {
     let res = unsafe {
         let c_context = context as *mut c_void;
         ffi::quorum_context_set(handle.quorum_handle, c_context)

+ 43 - 17
bindings/rust/src/votequorum.rs

@@ -189,10 +189,35 @@ pub struct Callbacks {
 }
 
 /// A handle into the votequorum library. Returned from [initialize] and needed for all other calls
-#[derive(Copy, Clone)]
 pub struct Handle {
     votequorum_handle: u64,
     callbacks: Callbacks,
+    clone: bool,
+}
+
+impl Clone for Handle {
+    fn clone(&self) -> Handle {
+        Handle {
+            votequorum_handle: self.votequorum_handle,
+            callbacks: self.callbacks,
+            clone: true,
+        }
+    }
+}
+
+impl Drop for Handle {
+    fn drop(self: &mut Handle) {
+        if !self.clone {
+            let _e = finalize(self);
+        }
+    }
+}
+
+// Clones count as equivalent
+impl PartialEq for Handle {
+    fn eq(&self, other: &Handle) -> bool {
+        self.votequorum_handle == other.votequorum_handle
+    }
 }
 
 /// Initialize a connection to the votequorum library. You must call this before doing anything
@@ -213,8 +238,9 @@ pub fn initialize(callbacks: &Callbacks) -> Result<Handle> {
             let rhandle = Handle {
                 votequorum_handle: handle,
                 callbacks: *callbacks,
+                clone: false,
             };
-            HANDLE_HASH.lock().unwrap().insert(handle, rhandle);
+            HANDLE_HASH.lock().unwrap().insert(handle, rhandle.clone());
             Ok(rhandle)
         } else {
             Err(CsError::from_c(res))
@@ -223,7 +249,7 @@ pub fn initialize(callbacks: &Callbacks) -> Result<Handle> {
 }
 
 /// Finish with a connection to corosync
-pub fn finalize(handle: Handle) -> Result<()> {
+pub fn finalize(handle: &Handle) -> Result<()> {
     let res = unsafe { ffi::votequorum_finalize(handle.votequorum_handle) };
     if res == ffi::CS_OK {
         HANDLE_HASH
@@ -238,7 +264,7 @@ pub fn finalize(handle: Handle) -> Result<()> {
 
 // Not sure if an FD is the right thing to return here, but it will do for now.
 /// Return a file descriptor to use for poll/select on the VOTEQUORUM handle
-pub fn fd_get(handle: Handle) -> Result<i32> {
+pub fn fd_get(handle: &Handle) -> Result<i32> {
     let c_fd: *mut c_int = &mut 0 as *mut _ as *mut c_int;
     let res = unsafe { ffi::votequorum_fd_get(handle.votequorum_handle, c_fd) };
     if res == ffi::CS_OK {
@@ -251,7 +277,7 @@ pub fn fd_get(handle: Handle) -> Result<i32> {
 const VOTEQUORUM_QDEVICE_MAX_NAME_LEN: usize = 255;
 
 /// Returns detailed information about a node in a [NodeInfo] structure
-pub fn get_info(handle: Handle, nodeid: NodeId) -> Result<NodeInfo> {
+pub fn get_info(handle: &Handle, nodeid: NodeId) -> Result<NodeInfo> {
     let mut c_info = ffi::votequorum_info {
         node_id: 0,
         node_state: 0,
@@ -293,7 +319,7 @@ pub fn get_info(handle: Handle, nodeid: NodeId) -> Result<NodeInfo> {
 }
 
 /// Call any/all active votequorum callbacks for this [Handle]. see [DispatchFlags] for details
-pub fn dispatch(handle: Handle, flags: DispatchFlags) -> Result<()> {
+pub fn dispatch(handle: &Handle, flags: DispatchFlags) -> Result<()> {
     let res = unsafe { ffi::votequorum_dispatch(handle.votequorum_handle, flags as u32) };
     if res == ffi::CS_OK {
         Ok(())
@@ -303,7 +329,7 @@ pub fn dispatch(handle: Handle, flags: DispatchFlags) -> Result<()> {
 }
 
 /// Track node and votequorum changes
-pub fn trackstart(handle: Handle, context: u64, flags: TrackFlags) -> Result<()> {
+pub fn trackstart(handle: &Handle, context: u64, flags: TrackFlags) -> Result<()> {
     let res =
         unsafe { ffi::votequorum_trackstart(handle.votequorum_handle, context, flags as u32) };
     if res == ffi::CS_OK {
@@ -314,7 +340,7 @@ pub fn trackstart(handle: Handle, context: u64, flags: TrackFlags) -> Result<()>
 }
 
 /// Stop tracking node and votequorum changes
-pub fn trackstop(handle: Handle) -> Result<()> {
+pub fn trackstop(handle: &Handle) -> Result<()> {
     let res = unsafe { ffi::votequorum_trackstop(handle.votequorum_handle) };
     if res == ffi::CS_OK {
         Ok(())
@@ -326,7 +352,7 @@ pub fn trackstop(handle: Handle) -> Result<()> {
 /// Get the current 'context' value for this handle.
 /// The context value is an arbitrary value that is always passed
 /// back to callbacks to help identify the source
-pub fn context_get(handle: Handle) -> Result<u64> {
+pub fn context_get(handle: &Handle) -> Result<u64> {
     let (res, context) = unsafe {
         let mut c_context: *mut c_void = &mut 0u64 as *mut _ as *mut c_void;
         let r = ffi::votequorum_context_get(handle.votequorum_handle, &mut c_context);
@@ -344,7 +370,7 @@ pub fn context_get(handle: Handle) -> Result<u64> {
 /// The context value is an arbitrary value that is always passed
 /// back to callbacks to help identify the source.
 /// Normally this is set in [trackstart], but this allows it to be changed
-pub fn context_set(handle: Handle, context: u64) -> Result<()> {
+pub fn context_set(handle: &Handle, context: u64) -> Result<()> {
     let res = unsafe {
         let c_context = context as *mut c_void;
         ffi::votequorum_context_set(handle.votequorum_handle, c_context)
@@ -358,7 +384,7 @@ pub fn context_set(handle: Handle, context: u64) -> Result<()> {
 
 /// Set the current expected_votes for the cluster, this value must
 /// be valid and not result in an inquorate cluster.
-pub fn set_expected(handle: Handle, expected_votes: u32) -> Result<()> {
+pub fn set_expected(handle: &Handle, expected_votes: u32) -> Result<()> {
     let res = unsafe { ffi::votequorum_setexpected(handle.votequorum_handle, expected_votes) };
     if res == ffi::CS_OK {
         Ok(())
@@ -368,7 +394,7 @@ pub fn set_expected(handle: Handle, expected_votes: u32) -> Result<()> {
 }
 
 /// Set the current votes for a node
-pub fn set_votes(handle: Handle, nodeid: NodeId, votes: u32) -> Result<()> {
+pub fn set_votes(handle: &Handle, nodeid: NodeId, votes: u32) -> Result<()> {
     let res =
         unsafe { ffi::votequorum_setvotes(handle.votequorum_handle, u32::from(nodeid), votes) };
     if res == ffi::CS_OK {
@@ -379,7 +405,7 @@ pub fn set_votes(handle: Handle, nodeid: NodeId, votes: u32) -> Result<()> {
 }
 
 /// Register a quorum device
-pub fn qdevice_register(handle: Handle, name: &str) -> Result<()> {
+pub fn qdevice_register(handle: &Handle, name: &str) -> Result<()> {
     let c_string = {
         match CString::new(name) {
             Ok(cs) => cs,
@@ -397,7 +423,7 @@ pub fn qdevice_register(handle: Handle, name: &str) -> Result<()> {
 }
 
 /// Unregister a quorum device
-pub fn qdevice_unregister(handle: Handle, name: &str) -> Result<()> {
+pub fn qdevice_unregister(handle: &Handle, name: &str) -> Result<()> {
     let c_string = {
         match CString::new(name) {
             Ok(cs) => cs,
@@ -415,7 +441,7 @@ pub fn qdevice_unregister(handle: Handle, name: &str) -> Result<()> {
 }
 
 /// Update the name of a quorum device
-pub fn qdevice_update(handle: Handle, oldname: &str, newname: &str) -> Result<()> {
+pub fn qdevice_update(handle: &Handle, oldname: &str, newname: &str) -> Result<()> {
     let on_string = {
         match CString::new(oldname) {
             Ok(cs) => cs,
@@ -446,7 +472,7 @@ pub fn qdevice_update(handle: Handle, oldname: &str, newname: &str) -> Result<()
 /// Poll a quorum device
 /// This must be done more often than the qdevice timeout (default 10s) while the device is active
 /// and the [RingId] must match the current value returned from the callbacks for it to be accepted.
-pub fn qdevice_poll(handle: Handle, name: &str, cast_vote: bool, ring_id: &RingId) -> Result<()> {
+pub fn qdevice_poll(handle: &Handle, name: &str, cast_vote: bool, ring_id: &RingId) -> Result<()> {
     let c_string = {
         match CString::new(name) {
             Ok(cs) => cs,
@@ -476,7 +502,7 @@ pub fn qdevice_poll(handle: Handle, name: &str, cast_vote: bool, ring_id: &RingI
 }
 
 /// Allow qdevice to tell votequorum if master_wins can be enabled or not
-pub fn qdevice_master_wins(handle: Handle, name: &str, master_wins: bool) -> Result<()> {
+pub fn qdevice_master_wins(handle: &Handle, name: &str, master_wins: bool) -> Result<()> {
     let c_string = {
         match CString::new(name) {
             Ok(cs) => cs,

+ 10 - 10
bindings/rust/tests/src/bin/cfg-test.rs

@@ -5,7 +5,7 @@ use corosync::{cfg, NodeId};
 
 use std::thread::spawn;
 
-fn dispatch_thread(handle: cfg::Handle) {
+fn dispatch_thread(handle: &cfg::Handle) {
     loop {
         if cfg::dispatch(handle, corosync::DispatchFlags::One).is_err() {
             return;
@@ -18,7 +18,7 @@ fn shutdown_check_fn(handle: &cfg::Handle, _flags: u32) {
     println!("in shutdown callback");
 
     // DON'T shutdown corosync - we're just testing
-    if let Err(e) = cfg::reply_to_shutdown(*handle, cfg::ShutdownReply::No) {
+    if let Err(e) = cfg::reply_to_shutdown(handle, cfg::ShutdownReply::No) {
         println!("Error in CFG replyto_shutdown: {e}");
     }
 }
@@ -52,10 +52,10 @@ fn main() {
         }
     };
 
-    match cfg::track_start(handle2, cfg::TrackFlags::None) {
+    match cfg::track_start(&handle2, cfg::TrackFlags::None) {
         Ok(_) => {
             // Run handle2 dispatch in its own thread
-            spawn(move || dispatch_thread(handle2));
+            spawn(move || dispatch_thread(&handle2));
         }
         Err(e) => {
             println!("Error in CFG track_start: {e}");
@@ -63,7 +63,7 @@ fn main() {
     };
 
     let local_nodeid = {
-        match cfg::local_get(handle) {
+        match cfg::local_get(&handle) {
             Ok(n) => {
                 println!("Local nodeid is {n}");
                 Some(n)
@@ -82,10 +82,10 @@ fn main() {
     if let Some(our_nodeid) = local_nodeid {
         let us_plus1 = NodeId::from(u32::from(our_nodeid) + 1);
         let us_less1 = NodeId::from(u32::from(our_nodeid) - 1);
-        let mut res = cfg::node_status_get(handle, us_plus1, cfg::NodeStatusVersion::V1);
+        let mut res = cfg::node_status_get(&handle, us_plus1, cfg::NodeStatusVersion::V1);
         if let Err(e) = res {
             println!("Error from node_status_get on nodeid {us_plus1}: {e}");
-            res = cfg::node_status_get(handle, us_less1, cfg::NodeStatusVersion::V1);
+            res = cfg::node_status_get(&handle, us_less1, cfg::NodeStatusVersion::V1);
         };
         match res {
             Ok(ns) => {
@@ -113,8 +113,8 @@ fn main() {
         }
     }
 
-    // This should not shutdown corosync because the callback on handle2 will refuse it.
-    match cfg::try_shutdown(handle, cfg::ShutdownFlags::Request) {
+    // This should not shutdown corosync because the callback on &handle2 will refuse it.
+    match cfg::try_shutdown(&handle, cfg::ShutdownFlags::Request) {
         Ok(_) => {
             println!("CFG try_shutdown suceeded, should return busy");
         }
@@ -127,7 +127,7 @@ fn main() {
 
     // Wait for events
     loop {
-        if cfg::dispatch(handle, corosync::DispatchFlags::One).is_err() {
+        if cfg::dispatch(&handle, corosync::DispatchFlags::One).is_err() {
             break;
         }
     }

+ 17 - 17
bindings/rust/tests/src/bin/cmap-test.rs

@@ -31,47 +31,47 @@ fn main() {
     };
 
     // Test some SETs
-    if let Err(e) = cmap::set_u32(handle, "test.test_uint32", 456) {
+    if let Err(e) = cmap::set_u32(&handle, "test.test_uint32", 456) {
         println!("Error in CMAP set_u32: {e}");
         return;
     };
 
-    if let Err(e) = cmap::set_i16(handle, "test.test_int16", -789) {
+    if let Err(e) = cmap::set_i16(&handle, "test.test_int16", -789) {
         println!("Error in CMAP set_i16: {e}");
         return;
     };
 
-    if let Err(e) = cmap::set_number(handle, "test.test_num_1", 6809u32) {
+    if let Err(e) = cmap::set_number(&handle, "test.test_num_1", 6809u32) {
         println!("Error in CMAP set_number(u32): {e}");
         return;
     };
 
     // NOT PI (just to avoid clippy whingeing)
-    if let Err(e) = cmap::set_number(handle, "test.test_num_2", 3.24159265) {
+    if let Err(e) = cmap::set_number(&handle, "test.test_num_2", 3.24159265) {
         println!("Error in CMAP set_number(f32): {e}");
         return;
     };
 
-    if let Err(e) = cmap::set_string(handle, "test.test_string", "Hello from Rust") {
+    if let Err(e) = cmap::set_string(&handle, "test.test_string", "Hello from Rust") {
         println!("Error in CMAP set_string: {e}");
         return;
     };
 
     let test_d = cmap::Data::UInt64(0xdeadbeefbacecafe);
-    if let Err(e) = cmap::set(handle, "test.test_data", &test_d) {
+    if let Err(e) = cmap::set(&handle, "test.test_data", &test_d) {
         println!("Error in CMAP set_data: {e}");
         return;
     };
 
     //    let test_d2 = cmap::Data::UInt32(6809);
     let test_d2 = cmap::Data::String("Test string in data 12345".to_string());
-    if let Err(e) = cmap::set(handle, "test.test_again", &test_d2) {
+    if let Err(e) = cmap::set(&handle, "test.test_again", &test_d2) {
         println!("Error in CMAP set_data2: {e}");
         return;
     };
 
     // get them back again
-    match cmap::get(handle, "test.test_uint32") {
+    match cmap::get(&handle, "test.test_uint32") {
         Ok(v) => {
             println!("GOT uint32 {v}");
         }
@@ -81,7 +81,7 @@ fn main() {
             return;
         }
     };
-    match cmap::get(handle, "test.test_int16") {
+    match cmap::get(&handle, "test.test_int16") {
         Ok(v) => {
             println!("GOT uint16 {v}");
         }
@@ -92,7 +92,7 @@ fn main() {
         }
     };
 
-    match cmap::get(handle, "test.test_num_1") {
+    match cmap::get(&handle, "test.test_num_1") {
         Ok(v) => {
             println!("GOT num {v}");
         }
@@ -102,7 +102,7 @@ fn main() {
             return;
         }
     };
-    match cmap::get(handle, "test.test_num_2") {
+    match cmap::get(&handle, "test.test_num_2") {
         Ok(v) => {
             println!("GOT num {v}");
         }
@@ -112,7 +112,7 @@ fn main() {
             return;
         }
     };
-    match cmap::get(handle, "test.test_string") {
+    match cmap::get(&handle, "test.test_string") {
         Ok(v) => {
             println!("GOT string {v}");
         }
@@ -123,7 +123,7 @@ fn main() {
         }
     };
 
-    match cmap::get(handle, "test.test_data") {
+    match cmap::get(&handle, "test.test_data") {
         Ok(v) => match v {
             cmap::Data::UInt64(u) => println!("GOT data value {u:x}"),
             _ => println!("ERROR type was not UInt64, got {v}"),
@@ -136,7 +136,7 @@ fn main() {
     };
 
     // Test an iterator
-    match cmap::CmapIterStart::new(handle, "totem.") {
+    match cmap::CmapIterStart::new(&handle, "totem.") {
         Ok(cmap_iter) => {
             for i in cmap_iter {
                 println!("ITER: {i:?}");
@@ -149,7 +149,7 @@ fn main() {
     }
 
     // Close this handle
-    if let Err(e) = cmap::finalize(handle) {
+    if let Err(e) = cmap::finalize(&handle) {
         println!("Error in CMAP get: {e}");
         return;
     };
@@ -167,7 +167,7 @@ fn main() {
         notify_fn: Some(track_notify_fn),
     };
     let _track_handle = match cmap::track_add(
-        handle,
+        &handle,
         "stats.srp.memb_merge_detect_tx",
         cmap::TrackType::MODIFY | cmap::TrackType::ADD | cmap::TrackType::DELETE,
         &cb,
@@ -183,7 +183,7 @@ fn main() {
     // Wait for events
     let mut event_num = 0;
     loop {
-        if let Err(e) = cmap::dispatch(handle, corosync::DispatchFlags::One) {
+        if let Err(e) = cmap::dispatch(&handle, corosync::DispatchFlags::One) {
             println!("Error from CMAP dispatch: {e}");
         }
         // Just do 5

+ 8 - 8
bindings/rust/tests/src/bin/cpg-test.rs

@@ -66,12 +66,12 @@ fn main() {
         }
     };
 
-    if let Err(e) = cpg::join(handle, "TEST") {
+    if let Err(e) = cpg::join(&handle, "TEST") {
         println!("Error in CPG join: {e}");
         return;
     }
 
-    match cpg::local_get(handle) {
+    match cpg::local_get(&handle) {
         Ok(n) => {
             println!("Local nodeid is {n}");
         }
@@ -81,7 +81,7 @@ fn main() {
     }
 
     // Test membership_get()
-    match cpg::membership_get(handle, "TEST") {
+    match cpg::membership_get(&handle, "TEST") {
         Ok(m) => {
             println!("  members: {m:?}");
             println!();
@@ -93,13 +93,13 @@ fn main() {
 
     // Test context APIs
     let set_context: u64 = 0xabcdbeefcafe;
-    if let Err(e) = cpg::context_set(handle, set_context) {
+    if let Err(e) = cpg::context_set(&handle, set_context) {
         println!("Error in CPG context_set: {e}");
         return;
     }
 
     // NOTE This will fail on 32 bit systems because void* is not u64
-    match cpg::context_get(handle) {
+    match cpg::context_get(&handle) {
         Ok(c) => {
             if c != set_context {
                 println!("Error: context_get() returned {c:x}, context should be {set_context:x}");
@@ -111,7 +111,7 @@ fn main() {
     }
 
     // Test iterator
-    match cpg::CpgIterStart::new(handle, "", cpg::CpgIterType::All) {
+    match cpg::CpgIterStart::new(&handle, "", cpg::CpgIterType::All) {
         Ok(cpg_iter) => {
             for i in cpg_iter {
                 println!("ITER: {i:?}");
@@ -125,7 +125,7 @@ fn main() {
 
     // We should receive our own message (at least) in the event loop
     if let Err(e) = cpg::mcast_joined(
-        handle,
+        &handle,
         cpg::Guarantee::TypeAgreed,
         &"This is a test".to_string().into_bytes(),
     ) {
@@ -134,7 +134,7 @@ fn main() {
 
     // Wait for events
     loop {
-        if cpg::dispatch(handle, corosync::DispatchFlags::One).is_err() {
+        if cpg::dispatch(&handle, corosync::DispatchFlags::One).is_err() {
             break;
         }
     }

+ 4 - 4
bindings/rust/tests/src/bin/quorum-test.rs

@@ -51,13 +51,13 @@ fn main() {
 
     // Test context APIs
     let set_context: u64 = 0xabcdbeefcafe;
-    if let Err(e) = quorum::context_set(handle, set_context) {
+    if let Err(e) = quorum::context_set(&handle, set_context) {
         println!("Error in QUORUM context_set: {e}");
         return;
     }
 
     // NOTE This will fail on 32 bit systems because void* is not u64
-    match quorum::context_get(handle) {
+    match quorum::context_get(&handle) {
         Ok(c) => {
             if c != set_context {
                 println!("Error: context_get() returned {c:x}, context should be {set_context:x}");
@@ -68,14 +68,14 @@ fn main() {
         }
     }
 
-    if let Err(e) = quorum::trackstart(handle, corosync::TrackFlags::Changes) {
+    if let Err(e) = quorum::trackstart(&handle, corosync::TrackFlags::Changes) {
         println!("Error in QUORUM trackstart: {e}");
         return;
     }
 
     // Wait for events
     loop {
-        if quorum::dispatch(handle, corosync::DispatchFlags::One).is_err() {
+        if quorum::dispatch(&handle, corosync::DispatchFlags::One).is_err() {
             break;
         }
     }

+ 7 - 7
bindings/rust/tests/src/bin/votequorum-test.rs

@@ -51,12 +51,12 @@ fn main() {
 
     // Test context APIs
     let set_context: u64 = 0xabcdbeefcafe;
-    if let Err(e) = votequorum::context_set(handle, set_context) {
+    if let Err(e) = votequorum::context_set(&handle, set_context) {
         println!("Error in VOTEQUORUM context_set: {e}");
     }
 
     // NOTE This will fail on 32 bit systems because void* is not u64
-    match votequorum::context_get(handle) {
+    match votequorum::context_get(&handle) {
         Ok(c) => {
             if c != set_context {
                 println!("Error: context_get() returned {c:x}, context should be {set_context:x}");
@@ -69,11 +69,11 @@ fn main() {
 
     const QDEVICE_NAME: &str = "RustQdevice";
 
-    if let Err(e) = votequorum::qdevice_register(handle, QDEVICE_NAME) {
+    if let Err(e) = votequorum::qdevice_register(&handle, QDEVICE_NAME) {
         println!("Error in VOTEQUORUM qdevice_register: {e}");
     }
 
-    match votequorum::get_info(handle, corosync::NodeId::from(1u32)) {
+    match votequorum::get_info(&handle, corosync::NodeId::from(1u32)) {
         Ok(i) => {
             println!("Node info for nodeid 1");
             println!("  nodeid: {}", i.node_id);
@@ -98,18 +98,18 @@ fn main() {
         }
     }
 
-    if let Err(e) = votequorum::qdevice_unregister(handle, QDEVICE_NAME) {
+    if let Err(e) = votequorum::qdevice_unregister(&handle, QDEVICE_NAME) {
         println!("Error in VOTEQUORUM qdevice_unregister: {e}");
     }
 
-    if let Err(e) = votequorum::trackstart(handle, 99_u64, corosync::TrackFlags::Changes) {
+    if let Err(e) = votequorum::trackstart(&handle, 99_u64, corosync::TrackFlags::Changes) {
         println!("Error in VOTEQUORUM trackstart: {e}");
         return;
     }
 
     // Wait for events
     loop {
-        if votequorum::dispatch(handle, corosync::DispatchFlags::One).is_err() {
+        if votequorum::dispatch(&handle, corosync::DispatchFlags::One).is_err() {
             break;
         }
     }