-
Notifications
You must be signed in to change notification settings - Fork 8
Event engine implementation #139
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
Conversation
Provide generic event engine implementation which can operate over different states. feat(ee): provide subscribe states Provide list of states which correspond to subscribe state machine. feat(ee): provide list of subscribe state machine events Provide list of events which trigger transition between states in subscribe state machine. feat(ee): define transitions Define transition directions in response of event depending from current state machine state. feat(ee): provide list of effects and invocations Provide list of effects invocation and effects which can be called as part of transitions.
|
FYI: Clippy won't be happy with this because a lot of code detached (it needs to be bound with actual effect implementation and EE usage). |
|
You can add |
Xavrax
left a comment
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.
Overall LGTM but I have some questions.
src/core/event_engine/mod.rs
Outdated
| let mut writable_state = self.current_state.write(); | ||
| *writable_state = transition.state; | ||
| drop(writable_state); |
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.
This pattern is also pretty common in rust community:
| let mut writable_state = self.current_state.write(); | |
| *writable_state = transition.state; | |
| drop(writable_state); | |
| { | |
| let mut writable_state = self.current_state.write(); | |
| *writable_state = transition.state; | |
| } |
I prefer that one above but take this one which is preferred by you.
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.
Made this change in recent push.
Xavrax
left a comment
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.
What thing makes me worried. There are 1.5k lines without any test ;o
Xavrax
left a comment
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.
Some question that I found during working with effects.
| F: Fn(Vec<E>), | ||
| { | ||
| if let Some(effect) = self.handler.create(invocation) { | ||
| let effect = Rc::new(effect); |
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.
Why do we need that RC here?
Why do we passing the remove_managed_effect into the effect and call it inside of it?
Additionally, if we need reference counter it probably won't work with our client as it needs to be thread safe.
Use Arc instead.
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.
Why do we need that RC here?
I have a requirement to store managed effect in a vector and make it possible to remove the same effect from list after run completion.
I tried to filter in completion block, but borrow checker won't let me go this way. Furthermore, I used Rc just to make clone once to add it vector and don't need Rc functionality after that.
Why do we passing the remove_managed_effect into the effect and call it inside of it?
I can't follow this one.
The idea was that run function of effect has completion closure, with which we will be able to remove effect from the list of managed effects.
Additionally, if we need reference counter it probably won't work with our client as it needs to be thread safe.
Use Arc instead.
Rc functionality used once (I mean clone) within dispatch function, and that is all. All other access to it through vector which stores it should be safe enough because of RwLock.
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.
The idea was that run function of effect has completion closure, with which we will be able to remove effect from the list of managed effects.
This one is still confusing to me.
How effects are allowed to managed the call?
Currently in SubscribeEffect it doesn't make any decision about it. Do you think that some effects will affect that?
We still can casually call that line after calling run function.
I will work on this. |
| F: Fn(Vec<E>), | ||
| { | ||
| if let Some(effect) = self.handler.create(invocation) { | ||
| let effect = Rc::new(effect); |
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.
The idea was that run function of effect has completion closure, with which we will be able to remove effect from the list of managed effects.
This one is still confusing to me.
How effects are allowed to managed the call?
Currently in SubscribeEffect it doesn't make any decision about it. Do you think that some effects will affect that?
We still can casually call that line after calling run function.
| // Notify about effect run completion. | ||
| // Placeholder for effect events processing (pass to effects handler). | ||
| f(events); |
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.
So these lines assume's that f() have to be called after the Effect.
As it's synchronous - I still don't see sense of that call. Maybe Am I missing something ;o?
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 don't have implemented effects yet, but I assume that some of them would return events, which should be processed by the event engine.
It is exactly as it says – it is a placeholder for functionality, which I expect to appear with implemented effects.
The function pointer can be passed to the created effect, so it will be called from it.
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.
I'm still not sure about that.
Anyway imo you can merge that.
Rest of code looks good.
Xavrax
left a comment
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.
LGTM (except that part with function)
feat(ee): event engine implementation
Provide generic event engine implementation which can operate over different states.
feat(ee): provide subscribe states
Provide a list of states which correspond to subscribe state machine.
feat(ee): provide list of subscribe state machine events
Provide a list of events which trigger transition between states in subscribe state machine.
feat(ee): define transitions
Define transition directions in response to event, depending on from current state machine state.
feat(ee): provide list of effects and invocations
Provide a list of effects invocation and effects which can be called as part of transitions.