This code takes some of the ideas of replace_with
and extends it to structures, allowing a function to be applied to a container in a way that cleans up after itself if there's a panic. Unlike running replace_with
on all the elements, one doesn't need a default value for the element types, only the container type.
I can't get the lifetimes right. If I replace TStruct
with Vec<T>
everything works fine without lifetime annotations, it's only when I try to generalise the function that I get lifetime issues. What lifetimes do I need to put in here to satisfy the borrow checker?
fn inplace_map<T, TStruct: IntoIterator<Item = T> + Default>(
f: impl Fn(T) -> T,
mut x: TStruct,
) -> TStruct
where
&mut TStruct: IntoIterator<Item = &mut T>,
&TStruct: IntoIterator<Item = &T>,
{
let x_ptr: *mut TStruct = &mut x;
for item_ref in &mut x {
let ptr: *mut T = item_ref;
unsafe {
let y1: T = std::ptr::read(ptr);
let fix_missing_elem = RunOnDrop {
f: || {
let y: TStruct = std::ptr::read(x_ptr);
let mut i = 0;
for item_ref in &y {
let current_item_ptr: *const T = item_ref;
if current_item_ptr == ptr {
break;
}
i += 1;
}
let mut j = 0;
for elem_ref in y {
if j == i {
std::mem::forget(elem_ref);
}
j += 1;
}
std::ptr::write(x_ptr, <TStruct as Default>::default());
},
};
let result = f(y1);
std::mem::forget(fix_missing_elem);
std::ptr::write(ptr, result);
}
}
x
}
struct RunOnDrop<F: FnMut()> {
f: F,
}
impl<'a, F: FnMut()> Drop for RunOnDrop<F> {
fn drop(&mut self) {
(self.f)()
}
}
error[E0637]: `&` without an explicit lifetime name cannot be used here
--> src/lib.rs:6:5
|
6 | &mut TStruct: IntoIterator<Item = &mut T>,
| ^ explicit lifetime name needed here
error[E0637]: `&` without an explicit lifetime name cannot be used here
--> src/lib.rs:6:39
|
6 | &mut TStruct: IntoIterator<Item = &mut T>,
| ^ explicit lifetime name needed here
error[E0637]: `&` without an explicit lifetime name cannot be used here
--> src/lib.rs:7:5
|
7 | &TStruct: IntoIterator<Item = &T>,
| ^ explicit lifetime name needed here
error[E0637]: `&` without an explicit lifetime name cannot be used here
--> src/lib.rs:7:35
|
7 | &TStruct: IntoIterator<Item = &T>,
| ^ explicit lifetime name needed here
error[E0310]: the parameter type `T` may not live long enough
--> src/lib.rs:1:1
|
1 | fn inplace_map<T, TStruct: IntoIterator<Item = T> + Default>(
| ^ - help: consider adding an explicit lifetime bound `T: 'static`...
| _|
| |
2 | | f: impl Fn(T) -> T,
3 | | mut x: TStruct,
4 | | ) -> TStruct
... |
41 | | x
42 | | }
| |_^
|
note: ...so that the reference type `&'static mut T` does not outlive the data it points at
--> src/lib.rs:1:1
|
1 | / fn inplace_map<T, TStruct: IntoIterator<Item = T> + Default>(
2 | | f: impl Fn(T) -> T,
3 | | mut x: TStruct,
4 | | ) -> TStruct
... |
41 | | x
42 | | }
| |_^
error[E0310]: the parameter type `TStruct` may not live long enough
--> src/lib.rs:1:1
|
1 | fn inplace_map<T, TStruct: IntoIterator<Item = T> + Default>(
| ^ -------- help: consider adding an explicit lifetime bound `TStruct: 'static`...
| _|
| |
2 | | f: impl Fn(T) -> T,
3 | | mut x: TStruct,
4 | | ) -> TStruct
... |
41 | | x
42 | | }
| |_^
|
note: ...so that the reference type `&'static mut TStruct` does not outlive the data it points at
--> src/lib.rs:1:1
|
1 | / fn inplace_map<T, TStruct: IntoIterator<Item = T> + Default>(
2 | | f: impl Fn(T) -> T,
3 | | mut x: TStruct,
4 | | ) -> TStruct
... |
41 | | x
42 | | }
| |_^