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