Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix #467 #468

Closed
wants to merge 4 commits into from
Closed

Fix #467 #468

wants to merge 4 commits into from

Conversation

rctlmk
Copy link

@rctlmk rctlmk commented Aug 15, 2022

Possible fix for #467.

@rctlmk
Copy link
Author

rctlmk commented Aug 16, 2022

It is possible to use parking_lot::Mutex to avoid a poisoning problem. Or it doesn't really matter, considering a poisoned mutex implies that something already went wrong elsewhere.

@rctlmk
Copy link
Author

rctlmk commented Aug 16, 2022

I thought of implementing Deref and DerefMut for ArcTracker, but then decided against it. Unfortunately, I forgot to remove those before restoring some stuff (which I removed without thinking too much), hence the force-push.

@djc
Copy link
Collaborator

djc commented Aug 16, 2022

Uh, I thought we'd just add a Sync bound to the ProgressTracker trait. Why can't we do that instead?

@rctlmk
Copy link
Author

rctlmk commented Aug 16, 2022

I forgot to mention it. I'm basing this off test_stateful_tracker(). The test fails if we change TestTracker's declaration to struct TestTracker(String). I assumed that we are always supposed to share mutable references, and wrapping all ProgressTracker objects into Arc/Mutex is one way to do that.

@djc
Copy link
Collaborator

djc commented Aug 16, 2022

Well, we should wrap TestTracker in an Arc<Mutex<_>> then (or its inner String, I guess?).

@rctlmk
Copy link
Author

rctlmk commented Aug 16, 2022

I don't know. Is it supposed to work like it does in that test? Or is the test written like that because the inner String of the TestTracker is wrapped in Arc/Mutex? Cloning a ProgressBar essentially gets us the same bar, but cloning a style returns a cloned value, if it isn't wrapped in some kind of smart pointer.

@djc
Copy link
Collaborator

djc commented Aug 16, 2022

Not sure what you mean exactly. The point here is that I don't want to impose Arc (much less Arc<Mutex>) on the implementer of the trait, so instead we just require the bound for the implementer, and then we have to fix our test type to make sure it can match the constraint.

@rctlmk
Copy link
Author

rctlmk commented Aug 16, 2022

I'm sorry if I'm not making sense, I probably don't get how it should to work. Let's suppose there is this ProgressTracker implementation:

#[derive(Debug, Clone)]
struct TestTracker(String);

impl ProgressTracker for TestTracker {
    fn clone_box(&self) -> Box<dyn ProgressTracker> {
        Box::new(self.clone())
    }

    fn tick(&mut self, state: &ProgressState, _: Instant) {
        self.0.clear();
        self.0.push_str(format!("{} {}", state.len().unwrap(), state.pos()).as_str());
    }

    fn reset(&mut self, _state: &ProgressState, _: Instant) {
        self.0.clear();
    }

    fn write(&self, _state: &ProgressState, w: &mut dyn fmt::Write) {
        w.write_str(self.0.as_str()).unwrap()
    }
}

And, like you said, Arc/Mutex is not imposed on the implementor right now. If we run this:

use crate::ProgressBar;

let pb = ProgressBar::new(1);
pb.set_style(
    ProgressStyle::with_template("{{ {foo} }}")
        .unwrap()
        .with_key("foo", TestTracker(String::default()))
        .progress_chars("#>-"),
);

let mut buf = Vec::new();
let style = pb.clone().style();

style.format_state(&pb.state().state, &mut buf, 16);
assert_eq!(&buf[0], "{  }");
buf.clear();
pb.inc(1);
style.format_state(&pb.state().state, &mut buf, 16);
assert_eq!(&buf[0], "{ 1 1 }");
pb.reset();
buf.clear();
style.format_state(&pb.state().state, &mut buf, 16);
assert_eq!(&buf[0], "{  }");
pb.finish_and_clear();

The first assert_eq! is going to pass, but the second one is going to fail. Does it fail because it is expected to do so, or any ProgressTracker should be able to pass it, regardless of its implementation?

@rctlmk
Copy link
Author

rctlmk commented Aug 16, 2022

Does it fail because it is expected to do so, or any ProgressTracker should be able to pass it, regardless of its implementation?

Probably the former:

/// Get a clone of the current progress bar style.
pub fn style(self) -> ProgressStyle {
    self.state().style.clone()
}

Well, then. If the !Sync trackers are still a concern, then instead of a Sync bound for ProgressTracker we can implement Sync for ProgressStyle manually.

@chris-laplante
Copy link
Collaborator

We can close this then, right?

@rctlmk rctlmk closed this Aug 19, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants