I'm working on a CLI utility which displays an indicatif::ProgressBar.
I made it possible to pass a custom progress bar by passing a lambda (pb_init) to .with_progress_init, so that in tests I can validate the output.
In a function setting up tests, I define a InMemoryTerm that will be used when drawing the progress bar. I need to define it outside of the pb_init, because I need to return it so I can use it in test assertions.
async fn setup_mocks -> ....... {
// other code
// ....
let in_mem = Rc::new(InMemoryTerm::new(10, 80));
let term = in_mem.clone();
let pb_init = move |size| {
ProgressBar::with_draw_target(
Some(size),
ProgressDrawTarget::term_like(Box::new(*term)))
// ----------------------------------------------------^^^^
// 1. cannot move out of an `Rc`
// move occurs because value has type `indicatif::InMemoryTerm`,
// which does not implement the `Copy` trait [E0507]
};
let downloader = asfald::Downloader::new()
.with_client(github_client)
.with_progress_init(pb_init);
// other code
// ....
// fn returns this struct
GithubMock {
cleanup: Box::new(cleanup),
server_url,
downloader,
url,
expected,
pb_term: in_mem.clone(),
}
}
If I dereference it like in the code above, I get the error in comment. If I don't dereference it, I get the error 1. the trait bound std::rc::Rcindicatif::InMemoryTerm: indicatif::TermLike is not satisfied. Does that mean I need to define a struct wrapping the Rc and implement the trait myself for that struct to delegate all calls to trait functions to the Rc value (which is automatically dereferenced)? Is there a trick to make it easy, just as an Rc is automatically dereferenced thanks to the Deref trait?
FYI I'm a recent rust dev, and might have misunderstood something
You have run afoul of the orphan rule.
Loosely stated, it means that whenever you need to implement a trait X for a type T, at least X or T needs to be defined in your own crate.
Wrapping the Rc value and then implementing the trait you mention for the wrapper type may or may not work here, I'm not sure what's involved in implementing that trait.
I'm still wondering if there's a better way, but seems that defining a struct which implements the trait allows it to be passed to term_like (though I also needed to swith to Arc from Rc to implement the trait) :
let in_mem = Arc::new(InMemoryTerm::new(10, 80));
let term = in_mem.clone();
let pb_init = move |size| {
let rc_term = RcTerm {
inner: term.clone(),
};
ProgressBar::with_draw_target(Some(size), ProgressDrawTarget::term_like(Box::new(rc_term)))
};