iceoryx2_bb_elementary/scope_guard.rs
1// Copyright (c) 2023 Contributors to the Eclipse Foundation
2//
3// See the NOTICE file(s) distributed with this work for additional
4// information regarding copyright ownership.
5//
6// This program and the accompanying materials are made available under the
7// terms of the Apache Software License 2.0 which is available at
8// https://www.apache.org/licenses/LICENSE-2.0, or the MIT license
9// which is available at https://opensource.org/licenses/MIT.
10//
11// SPDX-License-Identifier: Apache-2.0 OR MIT
12
13//! A building block to handle resources that need to be explicitly cleaned up.
14//!
15//! Useful when building higher level abstractions of low level hardware/OS resources.
16//!
17//! # Example
18//!
19//! ```
20//! use iceoryx2_bb_elementary::scope_guard::*;
21//!
22//! fn acquire_resource() -> u64 { 123 }
23//! fn release_resource(value: u64) { println!("release resource {}", value); }
24//! fn do_stuff_with_resource(value: u64) { println!("do stuff with resource {}", value); }
25//!
26//! pub enum ResourceCreationFailure {
27//! OutOfResources
28//! }
29//!
30//! pub fn do_things_with_resources() -> Result<(), ResourceCreationFailure> {
31//! let resource = ScopeGuardBuilder::new(acquire_resource())
32//! .on_init(|resource| {
33//! if *resource == 0 {
34//! return Err(ResourceCreationFailure::OutOfResources);
35//! }
36//!
37//! println!("acquired resource: {}", resource);
38//! Ok(())
39//! })
40//! .on_drop(|resource| {
41//! release_resource(*resource);
42//! }).create()?;
43//!
44//! do_stuff_with_resource(*resource.get());
45//!
46//! // resource goes out of scope and `release_resource` is called automatically
47//! Ok(())
48//! }
49//! ```
50
51/// The builder to create a [`ScopeGuard`].
52pub struct ScopeGuardBuilder<T, E, Finit: FnOnce(&mut T) -> Result<(), E>, Fdrop: FnOnce(&mut T)> {
53 value: T,
54 on_drop: Option<Fdrop>,
55 on_init: Option<Finit>,
56}
57
58impl<T, E, Finit: FnOnce(&mut T) -> Result<(), E>, Fdrop: FnOnce(&mut T)>
59 ScopeGuardBuilder<T, E, Finit, Fdrop>
60{
61 /// Creates a new scope guard be providing the initial value of the guarded object
62 pub fn new(value: T) -> Self {
63 ScopeGuardBuilder {
64 value,
65 on_drop: None,
66 on_init: None,
67 }
68 }
69
70 /// Callback which is called directly after create. Can be used to verify if the resource
71 /// was acquired correctly. Must return a [`Result`] of type `Result<(), E>`
72 pub fn on_init(mut self, on_init: Finit) -> Self {
73 self.on_init = Some(on_init);
74 self
75 }
76
77 /// Callback which is called when the [`ScopeGuard`] goes out of scope. It shall be used to
78 /// clean up the acquired resource.
79 pub fn on_drop(mut self, on_drop: Fdrop) -> Self {
80 self.on_drop = Some(on_drop);
81 self
82 }
83
84 /// Creates a new scope guard. If the provided callback in [`ScopeGuardBuilder::on_init()`]
85 /// succeeds it returns the [`ScopeGuard`] otherwise the error value which was returned by the
86 /// init function.
87 pub fn create(mut self) -> Result<ScopeGuard<T, Fdrop>, E> {
88 if self.on_init.is_some() {
89 self.on_init.unwrap()(&mut self.value)?;
90 }
91
92 Ok(ScopeGuard {
93 value: self.value,
94 on_drop: self.on_drop,
95 })
96 }
97}
98
99/// A guard which calls a callback to cleanup resources when it goes out of scope. Can be created
100/// with the [`ScopeGuardBuilder`].
101pub struct ScopeGuard<T, F: FnOnce(&mut T)> {
102 value: T,
103 on_drop: Option<F>,
104}
105
106impl<T, F: FnOnce(&mut T)> ScopeGuard<T, F> {
107 /// Returns a mutable reference to the underlying object
108 pub fn get_mut(&mut self) -> &mut T {
109 &mut self.value
110 }
111
112 /// Returns a reference to the underlying object
113 pub fn get(&self) -> &T {
114 &self.value
115 }
116}
117
118impl<T, F: FnOnce(&mut T)> Drop for ScopeGuard<T, F> {
119 fn drop(&mut self) {
120 if let Some(f) = self.on_drop.take() {
121 f(&mut self.value);
122 }
123 }
124}