How to do it...

Follow these steps:

  1. Open the Cargo.toml file that was generated earlier for you.

  2. In the folder bin, create a file called raii.rs.

  3. Add the following code and run it with cargo run --bin raii:

1   use std::ops::Deref;
2
3 // This represents a low level, close to the metal OS feature
that
4 // needs to be locked and unlocked in some way in order to be
accessed
5 // and is usually unsafe to use directly
6 struct SomeOsSpecificFunctionalityHandle;
7
8 // This is a safe wrapper around the low level struct
9 struct SomeOsFunctionality<T> {
10 // The data variable represents whatever useful information
11 // the user might provide to the OS functionality
12 data: T,
13 // The underlying struct is usually not savely movable,
14 // so it's given a constant address in a box
15 inner: Box<SomeOsSpecificFunctionalityHandle>,
16 }
17
18 // Access to a locked SomeOsFunctionality is wrapped in a guard
19 // that automatically unlocks it when dropped
20 struct SomeOsFunctionalityGuard<'a, T: 'a> {
21 lock: &'a SomeOsFunctionality<T>,
22 }
23
24 impl SomeOsSpecificFunctionalityHandle {
25 unsafe fn lock(&self) {
26 // Here goes the unsafe low level code
27 }
28 unsafe fn unlock(&self) {
29 // Here goes the unsafe low level code
30 }
31 }

Now comes the implementations for the structs:


33 impl<T> SomeOsFunctionality<T> {
34 fn new(data: T) -> Self {
35 let handle = SomeOsSpecificFunctionalityHandle;
36 SomeOsFunctionality {
37 data,
38 inner: Box::new(handle),
39 }
40 }
41
42 fn lock(&self) -> SomeOsFunctionalityGuard<T> {
43 // Lock the underlying resource.
44 unsafe {
45 self.inner.lock();
46 }
47
48 // Wrap a reference to our locked selves in a guard
49 SomeOsFunctionalityGuard { lock: self }
50 }
51 }
52
53 // Automatically unlock the underlying resource on drop
54 impl<'a, T> Drop for SomeOsFunctionalityGuard<'a, T> {
55 fn drop(&mut self) {
56 unsafe {
57 self.lock.inner.unlock();
58 }
59 }
60 }
61
62 // Implementing Deref means we can directly
63 // treat SomeOsFunctionalityGuard as if it was T
64 impl<'a, T> Deref for SomeOsFunctionalityGuard<'a, T> {
65 type Target = T;
66
67 fn deref(&self) -> &T {
68 &self.lock.data
69 }
70 }

And finally, the actual usage:

72  fn main() {
73 let foo = SomeOsFunctionality::new("Hello World");
74 {
75 // Locking foo returns an unlocked guard
76 let bar = foo.lock();
77 // Because of the Deref implementation on the guard,
78 // we can use it as if it was the underlying data
79 println!("The string behind foo is {} characters long",
bar.len());
80
81 // foo is automatically unlocked when we exit this scope
82 }
83 // foo could now be unlocked again if needed
84 }
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
52.15.38.176