I have a ‘collection of boxed terminal commands’, but now need local path result from one command for another

Thanks to @jendrikw's post I've been able to retain results.

Rust Playground

Unfortunately, I'm getting issues when the data I need to retain is a path.

Rust Playground

Does std::cell only work for primary variables?

It works for types that implement Copy, which is why you're getting this error message:

error[E0599]: the method `get` exists for reference `&Cell<PathBuf>`, but its trait bounds were not satisfied
    --> src/main.rs:54:40
     |
54   |         println!("path: {}", self.path.get());
     |                                        ^^^
     |
    ::: /playground/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/std/src/path.rs:1174:1
     |
1174 | pub struct PathBuf {
     | ------------------ doesn't satisfy `PathBuf: Copy`
     |
     = note: the following trait bounds were not satisfied:
             `PathBuf: Copy`
1 Like

Cell<T> is still usable without T: Copy. All you lose without Copy is .get() because you can’t copy the T out of the cell.

PathBuf: Default, so you can use Cell::take(), and any T[1] has access to Cell::replace() and Cell::set().
You can use those building blocks to Clone a value out of a cell:

fn clone_out<T: Clone + Default>(cell: &Cell<T>) -> T {
    let val = cell.take();
    cell.set(val.clone());
    val
}

You can replace usage of Cell::get with this function when using Clone + Default types like PathBuf/String/Vec<ClonableType>. You can even put it in an extension trait to keep method call syntax:

trait CellExt {
    type Inner;
    fn get_cloned(&self) -> Self::Inner;
}

impl<T: Clone + Default> CellExt for Cell<T> {
    type Inner = T;
    fn get_cloned(&self) -> T {
        let val = self.take();
        self.set(val.clone());
        val
    }
}

  1. where T: Sized ↩︎

4 Likes

I'm glad I can just circumvent the isssue like that.
I'll ask about the other issue in another thread.