Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
bytecodealliance
GitHub Repository: bytecodealliance/wasmtime
Path: blob/main/cranelift/codegen/src/take_and_replace.rs
1693 views
1
//! Helper for temporarily taking values out and then putting them back in.
2
3
/// An RAII type to temporarily take a `U` out of a `T` and then put it back
4
/// again on drop.
5
///
6
/// This allows you to split borrows, if necessary, to satisfy the borrow
7
/// checker.
8
///
9
/// The `F` type parameter must project from the container type `T` to its `U`
10
/// that we want to temporarily take out of it.
11
///
12
/// # Example
13
///
14
/// ```
15
/// use cranelift_codegen::TakeAndReplace;
16
///
17
/// #[derive(Default)]
18
/// struct BigContextStruct {
19
/// items: Vec<u32>,
20
/// count: usize,
21
/// }
22
///
23
/// impl BigContextStruct {
24
/// fn handle_item(&mut self, item: u32) {
25
/// self.count += 1;
26
/// println!("Handled {item}!");
27
/// }
28
/// }
29
///
30
/// let mut ctx = BigContextStruct::default();
31
/// ctx.items.extend([42, 1337, 1312]);
32
///
33
/// {
34
/// // Temporarily take `self.items` out of `ctx`.
35
/// let mut guard = TakeAndReplace::new(&mut ctx, |ctx| &mut ctx.items);
36
/// let (ctx, items) = guard.get();
37
///
38
/// // Now we can both borrow/iterate/mutate `items` and call `&mut self` helper
39
/// // methods on `ctx`. This would not otherwise be possible if we didn't split
40
/// // the borrows, since Rust's borrow checker doesn't see through methods and
41
/// // know that `handle_item` doesn't use `self.items`.
42
/// for item in items.drain(..) {
43
/// ctx.handle_item(item);
44
/// }
45
/// }
46
///
47
/// // When `guard` is dropped, `items` is replaced in `ctx`, allowing us to
48
/// // reuse its capacity and avoid future allocations. ```
49
/// assert!(ctx.items.capacity() >= 3);
50
/// ```
51
pub struct TakeAndReplace<'a, T, U, F>
52
where
53
F: Fn(&mut T) -> &mut U,
54
U: Default,
55
{
56
container: &'a mut T,
57
value: U,
58
proj: F,
59
}
60
61
impl<'a, T, U, F> Drop for TakeAndReplace<'a, T, U, F>
62
where
63
F: Fn(&mut T) -> &mut U,
64
U: Default,
65
{
66
fn drop(&mut self) {
67
*(self.proj)(self.container) = std::mem::take(&mut self.value);
68
}
69
}
70
71
impl<'a, T, U, F> TakeAndReplace<'a, T, U, F>
72
where
73
F: Fn(&mut T) -> &mut U,
74
U: Default,
75
{
76
/// Create a new `TakeAndReplace` that temporarily takes out
77
/// `proj(container)`.
78
pub fn new(mut container: &'a mut T, proj: F) -> Self {
79
let value = std::mem::take(proj(&mut container));
80
TakeAndReplace {
81
container,
82
value,
83
proj,
84
}
85
}
86
87
/// Get the underlying container and taken-out value.
88
pub fn get(&mut self) -> (&mut T, &mut U) {
89
(&mut *self.container, &mut self.value)
90
}
91
}
92
93