Skip to content

Commit 195911f

Browse files
committed
tutorial-ffi: add example of a custom destructor
1 parent 721e114 commit 195911f

File tree

1 file changed

+68
-0
lines changed

1 file changed

+68
-0
lines changed

doc/tutorial-ffi.md

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,74 @@ pub fn uncompress(src: &[u8]) -> Option<~[u8]> {
139139
For reference, the examples used here are also available as an [library on
140140
GitHub](https://github.com/thestinger/rust-snappy).
141141

142+
# Destructors
143+
144+
Foreign libraries often hand off ownership of resources to the calling code,
145+
which should be wrapped in a destructor to provide safety and guarantee their
146+
release.
147+
148+
A type with the same functionality as owned boxes can be implemented by
149+
wrapping `malloc` and `free`:
150+
151+
~~~~
152+
use core::libc::{c_void, size_t, malloc, free};
153+
154+
#[abi = "rust-intrinsic"]
155+
extern "rust-intrinsic" mod rusti {
156+
fn init<T>() -> T;
157+
}
158+
159+
// a wrapper around the handle returned by the foreign code
160+
pub struct Unique<T> {
161+
priv ptr: *mut T
162+
}
163+
164+
pub impl<'self, T: Owned> Unique<T> {
165+
fn new(value: T) -> Unique<T> {
166+
unsafe {
167+
let ptr = malloc(core::sys::size_of::<T>() as size_t) as *mut T;
168+
assert!(!ptr::is_null(ptr));
169+
*ptr = value;
170+
Unique{ptr: ptr}
171+
}
172+
}
173+
174+
// the 'self lifetime results in the same semantics as `&*x` with ~T
175+
fn borrow(&self) -> &'self T {
176+
unsafe { cast::transmute(self.ptr) }
177+
}
178+
179+
// the 'self lifetime results in the same semantics as `&mut *x` with ~T
180+
fn borrow_mut(&mut self) -> &'self mut T {
181+
unsafe { cast::transmute(self.ptr) }
182+
}
183+
}
184+
185+
#[unsafe_destructor]
186+
impl<T: Owned> Drop for Unique<T> {
187+
fn finalize(&self) {
188+
unsafe {
189+
let mut x = rusti::init(); // dummy value to swap in
190+
x <-> *self.ptr; // moving the object out is needed to call the destructor
191+
free(self.ptr as *c_void)
192+
}
193+
}
194+
}
195+
196+
// A comparison between the built-in ~ and this reimplementation
197+
fn main() {
198+
{
199+
let mut x = ~5;
200+
*x = 10;
201+
} // `x` is freed here
202+
203+
{
204+
let mut y = Unique::new(5);
205+
*y.borrow_mut() = 10;
206+
} // `y` is freed here
207+
}
208+
~~~~
209+
142210
# Linking
143211

144212
In addition to the `#[link_args]` attribute for explicitly passing arguments to the linker, an

0 commit comments

Comments
 (0)