-
Notifications
You must be signed in to change notification settings - Fork 27
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
Define state consistency within a revision #223
base: main
Are you sure you want to change the base?
Conversation
c0189ab
to
1919a88
Compare
aef6d2c
to
4dfb658
Compare
Codecov Report
@@ Coverage Diff @@
## main #223 +/- ##
==========================================
- Coverage 27.78% 27.24% -0.55%
==========================================
Files 50 50
Lines 11886 11729 -157
Branches 6634 6564 -70
==========================================
- Hits 3303 3195 -108
- Misses 6391 6446 +55
+ Partials 2192 2088 -104
Continue to review full report at Codecov.
|
b368d34
to
6febf59
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry it took so long to get to this! I like this approach a lot, although I have some questions about the public API it exposes -- see my review comments.
@@ -25,6 +25,9 @@ impl super::Runtime { | |||
where | |||
Root: FnMut() -> Out, | |||
{ | |||
// RunLoop always forces it's first revision? | |||
// or maybe just check if current revision is 0 | |||
self.force(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If it's possible to remove the force()
API, I'd prefer that. It's an additional branch at the top of each revision but I don't think this code isn't hot enough to care about that overhead.
/// Runs the root closure once with access to the runtime context, returning | ||
/// the result. `Waker` is set for the next `Revision`, which starts after | ||
/// the start of the run. | ||
pub fn run_once_with(&mut self, waker: Waker) -> Out { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is it possible to make this the only API? Is there a reason we still need to cache the waker and support running without one?
/// which is probably the desired behavior if the embedding system will | ||
/// call `Runtime::run_once` on a regular interval regardless. | ||
pub fn set_state_change_waker(&mut self, wk: Waker) { | ||
self.wk = wk; | ||
pub fn set_state_change_waker(&mut self, waker: Waker) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
At one point we discussed removing this altogether in favor of deleting run_once
and having run_once_with
take a waker -- is that still an option here?
rcs_write.revision.0 += 1; | ||
rcs_write.pending_changes.store(false, std::sync::atomic::Ordering::Relaxed); | ||
drop(rcs_write); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could you extract this to a separate method like RevisionController::increment_revision
? It'll make calls to execute()
a little more verbose but we'll never risk blocking writes to state variables if something changes here, because the write guard can't escape the controller's method body.
@@ -41,6 +43,13 @@ impl std::fmt::Debug for Revision { | |||
} | |||
} | |||
|
|||
#[derive(Debug)] | |||
pub(crate) struct RevisionControlSystem { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: RevisionController
Can you move this type to another file, src/runtime/controller.rs
?
let rcs_read = self.rcs.read(); | ||
let current = rcs_read.revision; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
let rcs_read = self.rcs.read(); | |
let current = rcs_read.revision; | |
let current = rcs.revision(); |
|
||
/// Returns a reference to the current commit. | ||
pub fn current_commit(&mut self) -> &Commit<State> { | ||
let current = self.rcs.read().revision; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
let current = self.rcs.read().revision; | |
let current = self.rcs.revision(); |
@@ -49,7 +49,7 @@ pub fn filter_link(to_set: Visibility) -> Li { | |||
mox! { | |||
<li> | |||
<a style="cursor: pointer;" | |||
class={if *visibility == to_set { "selected" } else { "" }} | |||
class={if *visibility.commit_at_root() == to_set { "selected" } else { "" }} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We shouldn't need to acquire a lock here to get the visibility for the revision, but I think this is a problem for you because of my past laziness.
At the top of this function is this attribute:
#[illicit::from_env(visibility: &Key<Visibility>)]
I think this needs to become
#[illicit::from_env(visibility: &Commit<Visibility>, set_visibility: &Key<Visibility>)]
Which will require exposing the current commit via https://github.com/anp/moxie/blob/main/dom/examples/todo/src/lib.rs#L53 as well.
@@ -97,7 +97,8 @@ mod tests { | |||
pub async fn single_item() { | |||
let root = document().create_element("div"); | |||
crate::App::boot_fn(&[Todo::new("weeeee")], root.clone(), || { | |||
let todo = &illicit::expect::<Key<Vec<Todo>>>()[0]; | |||
let todos_key = &illicit::expect::<Key<Vec<Todo>>>(); | |||
let todo = &todos_key.commit_at_root()[0]; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Similarly to my other comment, I think we need to pass down a Commit<Vec<Todo>>
from the App
.
@@ -35,8 +35,8 @@ pub fn toggle(default_checked: bool) -> Span { | |||
#[illicit::from_env(todos: &Key<Vec<Todo>>, visibility: &Key<Visibility>)] | |||
pub fn todo_list() -> Ul { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
See my comments in other todomvc files, I think if you add Commit<Visibility>
and Commit<Vec<Todo>>
to the illicit environment then you can avoid all the commit_at_root calls in this file.
A question: would this change be easier if |
Removed `commit_at_root` field of the `Key` bc of it being out of date.
increments, commits from the past revisions are lazely commited at first measurement
6febf59
to
cfa7bec
Compare
Resolves #222 #220 #215 #197.