Idiom, I believe that you are just implementing Drop . I do not know any standard types of libraries that implement a template that allows the user to manually manage the resource (method call) and automatically (by deleting).
This even leads to some strange cases. For example, closing a file with a function like fclose can generate errors. However, the Rust destructor cannot return an error code to the user. This means that such errors are swallowed .
This leads to the fact that you can support them. Your close method can return a Result , and then you can ignore this result in Drop .
As Jsor points out , you probably want your close method to accept a type by value. I also realized that you can use a NULL value to indicate whether this value was closed or not.
use std::ptr; enum NativeDevice {} // Opaque pointer to C struct fn ffi_open_native_device() -> *mut NativeDevice { 0x1 as *mut NativeDevice } fn ffi_close_native_device(_: *mut NativeDevice) -> u8 { println!("Close was called"); 0 } struct Device { native_device: *mut NativeDevice, } impl Device { fn new() -> Device { let dev = ffi_open_native_device(); assert!(!dev.is_null()); Device { native_device: dev, } } fn close(mut self) -> Result<(), &'static str> { if self.native_device.is_null() { return Ok(()) } let result = ffi_close_native_device(self.native_device); self.native_device = ptr::null_mut(); // Important to indicate that the device has already been cleaned up match result { 0 => Ok(()), _ => Err("Something wen't boom"), } } } impl Drop for Device { fn drop(&mut self) { if self.native_device.is_null() { return } let _ = ffi_close_native_device(self.native_device); // Ignoring failure to close here! } } fn main() { let _implicit = Device::new(); let explicit = Device::new(); explicit.close().expect("Couldn't close it"); }
If you had some kind of error that could be fixed when closing the device, you can return the object back to the user to try again:
enum Error { RecoverableError(Device), UnknownError, } fn close(mut self) -> Result<(), Error> { if self.native_device.is_null() { return Ok(()); } let result = ffi_close_native_device(self.native_device); match result { 0 => { self.native_device = ptr::null_mut(); // Important to indicate that the device has already been cleaned up Ok(()) }, 1 => Err(Error::RecoverableError(self)), _ => { self.native_device = ptr::null_mut(); // Important to indicate that the device has already been cleaned up Err(Error::UnknownError) }, } }
source share