mirror of
https://github.com/vlang/v.git
synced 2023-08-10 21:13:21 +03:00
eventbus: add generic support for event name (#18805)
This commit is contained in:
parent
97a726b188
commit
b3a6b73306
@ -3,7 +3,7 @@ module some_module
|
|||||||
import eventbus
|
import eventbus
|
||||||
|
|
||||||
const (
|
const (
|
||||||
eb = eventbus.new()
|
eb = eventbus.new[string]()
|
||||||
)
|
)
|
||||||
|
|
||||||
pub struct Duration {
|
pub struct Duration {
|
||||||
@ -29,6 +29,6 @@ pub fn do_work() {
|
|||||||
some_module.eb.publish('event_baz', &Duration{42}, &EventMetadata{'Additional data at the end.'})
|
some_module.eb.publish('event_baz', &Duration{42}, &EventMetadata{'Additional data at the end.'})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_subscriber() eventbus.Subscriber {
|
pub fn get_subscriber() eventbus.Subscriber[string] {
|
||||||
return *some_module.eb.subscriber
|
return *some_module.eb.subscriber
|
||||||
}
|
}
|
||||||
|
@ -4,26 +4,27 @@ A module to provide eventing capabilities using pub/sub.
|
|||||||
|
|
||||||
## API
|
## API
|
||||||
|
|
||||||
1. `new()` - create a new `EventBus`
|
1. `new[T]()` - create a new `EventBus`
|
||||||
|
2. `EventBus.new[T]()` - create a new `EventBus`
|
||||||
|
|
||||||
### Structs:
|
### Structs:
|
||||||
|
|
||||||
**EventBus:**
|
**EventBus:**
|
||||||
|
|
||||||
1. `publish(name string, sender voidptr, args voidptr)` - publish an event with provided
|
1. `publish(name T, sender voidptr, args voidptr)` - publish an event with provided
|
||||||
Params & name
|
Params & name
|
||||||
2. `clear_all()` - clear all subscribers
|
2. `clear_all()` - clear all subscribers
|
||||||
3. `has_subscriber(name string)` - check if a subscriber to an event exists
|
3. `has_subscriber(name T)` - check if a subscriber to an event exists
|
||||||
|
|
||||||
**Subscriber:**
|
**Subscriber:**
|
||||||
|
|
||||||
1. `subscribe(name string, handler EventHandlerFn)` - subscribe to an event
|
1. `subscribe(name T, handler EventHandlerFn)` - subscribe to an event
|
||||||
2. `subscribe_once(name string, handler EventHandlerFn)` - subscribe only once to an event
|
2. `subscribe_once(name T, handler EventHandlerFn)` - subscribe only once to an event
|
||||||
3. `subscribe_method(name string, handler EventHandlerFn, receiver voidptr)` - subscribe to
|
3. `subscribe_method(name T, handler EventHandlerFn, receiver voidptr)` - subscribe to
|
||||||
an event and also set the `receiver` as a parameter.
|
an event and also set the `receiver` as a parameter.
|
||||||
Since it's not yet possible to send methods as parameters, this is a workaround.
|
Since it's not yet possible to send methods as parameters, this is a workaround.
|
||||||
4. `is_subscribed(name string)` - check if we are subscribed to an event
|
4. `is_subscribed(name T)` - check if we are subscribed to an event
|
||||||
5. `unsubscribe(name string)` - unsubscribe from an event
|
5. `unsubscribe(name T)` - unsubscribe from an event
|
||||||
|
|
||||||
**Event Handler Signature:**
|
**Event Handler Signature:**
|
||||||
|
|
||||||
@ -63,7 +64,7 @@ import eventbus
|
|||||||
|
|
||||||
// initialize it globally
|
// initialize it globally
|
||||||
const (
|
const (
|
||||||
eb = eventbus.new()
|
eb = eventbus.new[string]()
|
||||||
)
|
)
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
@ -88,7 +89,7 @@ module main
|
|||||||
|
|
||||||
import eventbus
|
import eventbus
|
||||||
|
|
||||||
const eb = eventbus.new()
|
const eb = eventbus.new[string]()
|
||||||
|
|
||||||
struct Work {
|
struct Work {
|
||||||
hours int
|
hours int
|
||||||
|
@ -2,59 +2,70 @@ module eventbus
|
|||||||
|
|
||||||
pub type EventHandlerFn = fn (receiver voidptr, args voidptr, sender voidptr)
|
pub type EventHandlerFn = fn (receiver voidptr, args voidptr, sender voidptr)
|
||||||
|
|
||||||
pub struct Publisher {
|
pub struct Publisher[T] {
|
||||||
mut:
|
mut:
|
||||||
registry &Registry = unsafe { nil }
|
registry &Registry[T] = unsafe { nil }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Subscriber {
|
pub struct Subscriber[T] {
|
||||||
mut:
|
mut:
|
||||||
registry &Registry = unsafe { nil }
|
registry &Registry[T] = unsafe { nil }
|
||||||
}
|
}
|
||||||
|
|
||||||
struct Registry {
|
struct Registry[T] {
|
||||||
mut:
|
mut:
|
||||||
events []EventHandler
|
events []EventHandler[T]
|
||||||
}
|
}
|
||||||
|
|
||||||
struct EventHandler {
|
struct EventHandler[T] {
|
||||||
name string
|
name T
|
||||||
handler EventHandlerFn
|
handler EventHandlerFn
|
||||||
receiver voidptr = unsafe { nil }
|
receiver voidptr = unsafe { nil }
|
||||||
once bool
|
once bool
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct EventBus {
|
pub struct EventBus[T] {
|
||||||
pub mut:
|
pub mut:
|
||||||
registry &Registry = unsafe { nil }
|
registry &Registry[T] = unsafe { nil }
|
||||||
publisher &Publisher = unsafe { nil }
|
publisher &Publisher[T] = unsafe { nil }
|
||||||
subscriber &Subscriber = unsafe { nil }
|
subscriber &Subscriber[T] = unsafe { nil }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn new() &EventBus {
|
// EventBus.new[T] create a new eventbus with event type T.
|
||||||
registry := &Registry{
|
pub fn EventBus.new[T]() &EventBus[T] {
|
||||||
|
registry := &Registry[T]{
|
||||||
events: []
|
events: []
|
||||||
}
|
}
|
||||||
return &EventBus{registry, &Publisher{registry}, &Subscriber{registry}}
|
return &EventBus[T]{registry, &Publisher[T]{registry}, &Subscriber[T]{registry}}
|
||||||
}
|
}
|
||||||
|
|
||||||
// EventBus Methods
|
// new[T] create a new eventbus with event type T.
|
||||||
pub fn (eb &EventBus) publish(name string, sender voidptr, args voidptr) {
|
pub fn new[T]() &EventBus[T] {
|
||||||
|
registry := &Registry[T]{
|
||||||
|
events: []
|
||||||
|
}
|
||||||
|
return &EventBus[T]{registry, &Publisher[T]{registry}, &Subscriber[T]{registry}}
|
||||||
|
}
|
||||||
|
|
||||||
|
// publish publish an event with provided Params & name.
|
||||||
|
pub fn (eb &EventBus[T]) publish(name T, sender voidptr, args voidptr) {
|
||||||
mut publisher := eb.publisher
|
mut publisher := eb.publisher
|
||||||
publisher.publish(name, sender, args)
|
publisher.publish(name, sender, args)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn (eb &EventBus) clear_all() {
|
// clear_all clear all subscribers.
|
||||||
|
pub fn (eb &EventBus[T]) clear_all() {
|
||||||
mut publisher := eb.publisher
|
mut publisher := eb.publisher
|
||||||
publisher.clear_all()
|
publisher.clear_all()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn (eb &EventBus) has_subscriber(name string) bool {
|
// has_subscriber check if a subscriber to an event exists.
|
||||||
|
pub fn (eb &EventBus[T]) has_subscriber(name T) bool {
|
||||||
return eb.registry.check_subscriber(name)
|
return eb.registry.check_subscriber(name)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Publisher Methods
|
// publish publish an event with provided Params & name.
|
||||||
fn (mut pb Publisher) publish(name string, sender voidptr, args voidptr) {
|
fn (mut pb Publisher[T]) publish(name T, sender voidptr, args voidptr) {
|
||||||
for event in pb.registry.events {
|
for event in pb.registry.events {
|
||||||
if event.name == name {
|
if event.name == name {
|
||||||
event.handler(event.receiver, args, sender)
|
event.handler(event.receiver, args, sender)
|
||||||
@ -63,59 +74,64 @@ fn (mut pb Publisher) publish(name string, sender voidptr, args voidptr) {
|
|||||||
pb.registry.events = pb.registry.events.filter(!(it.name == name && it.once))
|
pb.registry.events = pb.registry.events.filter(!(it.name == name && it.once))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn (mut p Publisher) clear_all() {
|
// clear_all clear all subscribers.
|
||||||
|
fn (mut p Publisher[T]) clear_all() {
|
||||||
p.registry.events.clear()
|
p.registry.events.clear()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Subscriber Methods
|
// subscribe subscribe to an event `name`.
|
||||||
pub fn (mut s Subscriber) subscribe(name string, handler EventHandlerFn) {
|
pub fn (mut s Subscriber[T]) subscribe(name T, handler EventHandlerFn) {
|
||||||
s.registry.events << EventHandler{
|
s.registry.events << EventHandler[T]{
|
||||||
name: name
|
name: name
|
||||||
handler: handler
|
handler: handler
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn (mut s Subscriber) subscribe_method(name string, handler EventHandlerFn, receiver voidptr) {
|
// subscribe_method subscribe to an event `name` and also set the `receiver` as a parameter.
|
||||||
s.registry.events << EventHandler{
|
pub fn (mut s Subscriber[T]) subscribe_method(name T, handler EventHandlerFn, receiver voidptr) {
|
||||||
|
s.registry.events << EventHandler[T]{
|
||||||
name: name
|
name: name
|
||||||
handler: handler
|
handler: handler
|
||||||
receiver: receiver
|
receiver: receiver
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// unsubscribe_method unsubscribe a receiver for only one method
|
// unsubscribe_method unsubscribe a receiver for only one method.
|
||||||
pub fn (mut s Subscriber) unsubscribe_method(name string, receiver voidptr) {
|
pub fn (mut s Subscriber[T]) unsubscribe_method(name T, receiver voidptr) {
|
||||||
s.registry.events = s.registry.events.filter(!(it.name == name && it.receiver == receiver))
|
s.registry.events = s.registry.events.filter(!(it.name == name && it.receiver == receiver))
|
||||||
}
|
}
|
||||||
|
|
||||||
// unsubscribe_receiver unsubscribes a receiver from all events
|
// unsubscribe_receiver unsubscribes a receiver from all events.
|
||||||
pub fn (mut s Subscriber) unsubscribe_receiver(receiver voidptr) {
|
pub fn (mut s Subscriber[T]) unsubscribe_receiver(receiver voidptr) {
|
||||||
s.registry.events = s.registry.events.filter(it.receiver != receiver)
|
s.registry.events = s.registry.events.filter(it.receiver != receiver)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn (mut s Subscriber) subscribe_once(name string, handler EventHandlerFn) {
|
// subscribe_once subscribe only once to an event `name`.
|
||||||
s.registry.events << EventHandler{
|
pub fn (mut s Subscriber[T]) subscribe_once(name T, handler EventHandlerFn) {
|
||||||
|
s.registry.events << EventHandler[T]{
|
||||||
name: name
|
name: name
|
||||||
handler: handler
|
handler: handler
|
||||||
once: true
|
once: true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn (s &Subscriber) is_subscribed(name string) bool {
|
// is_subscribed check if we are subscribed to an event `name`.
|
||||||
|
pub fn (s &Subscriber[T]) is_subscribed(name T) bool {
|
||||||
return s.registry.check_subscriber(name)
|
return s.registry.check_subscriber(name)
|
||||||
}
|
}
|
||||||
|
|
||||||
// is_subscribed_method checks whether a receiver was already subscribed for any events
|
// is_subscribed_method checks whether a receiver was already subscribed for any events.
|
||||||
pub fn (s &Subscriber) is_subscribed_method(name string, receiver voidptr) bool {
|
pub fn (s &Subscriber[T]) is_subscribed_method(name T, receiver voidptr) bool {
|
||||||
return s.registry.events.any(it.name == name && it.receiver == receiver)
|
return s.registry.events.any(it.name == name && it.receiver == receiver)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn (mut s Subscriber) unsubscribe(name string, handler EventHandlerFn) {
|
// unsubscribe unsubscribe from an event `name`.
|
||||||
|
pub fn (mut s Subscriber[T]) unsubscribe(name T, handler EventHandlerFn) {
|
||||||
// v := voidptr(handler)
|
// v := voidptr(handler)
|
||||||
s.registry.events = s.registry.events.filter(!(it.name == name && it.handler == handler))
|
s.registry.events = s.registry.events.filter(!(it.name == name && it.handler == handler))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Registry Methods
|
// Registry Methods
|
||||||
fn (r &Registry) check_subscriber(name string) bool {
|
fn (r &Registry[T]) check_subscriber(name T) bool {
|
||||||
return r.events.any(it.name == name)
|
return r.events.any(it.name == name)
|
||||||
}
|
}
|
||||||
|
@ -8,11 +8,12 @@ struct FakeReceiver {
|
|||||||
ok bool
|
ok bool
|
||||||
}
|
}
|
||||||
|
|
||||||
fn test_eventbus() {
|
fn test_eventbus_string() {
|
||||||
ev_data := &EventData{'hello'}
|
ev_data := &EventData{'hello'}
|
||||||
mut eb := eventbus.new()
|
mut eb := eventbus.new[string]()
|
||||||
eb.subscriber.subscribe_once('on_test', on_test)
|
eb.subscriber.subscribe_once('on_test', on_test)
|
||||||
assert eb.has_subscriber('on_test')
|
assert eb.has_subscriber('on_test')
|
||||||
|
assert !eb.has_subscriber('not_exist')
|
||||||
assert eb.subscriber.is_subscribed('on_test')
|
assert eb.subscriber.is_subscribed('on_test')
|
||||||
eb.publish('on_test', eb, ev_data)
|
eb.publish('on_test', eb, ev_data)
|
||||||
assert !eb.has_subscriber('on_test')
|
assert !eb.has_subscriber('on_test')
|
||||||
@ -25,10 +26,52 @@ fn test_eventbus() {
|
|||||||
assert !eb.subscriber.is_subscribed('on_test')
|
assert !eb.subscriber.is_subscribed('on_test')
|
||||||
}
|
}
|
||||||
|
|
||||||
|
enum Events {
|
||||||
|
event_1
|
||||||
|
event_2
|
||||||
|
event_3
|
||||||
|
}
|
||||||
|
|
||||||
|
fn test_eventbus_enum() {
|
||||||
|
ev_data := &EventData{'hello'}
|
||||||
|
mut eb := eventbus.EventBus.new[Events]()
|
||||||
|
eb.subscriber.subscribe_once(Events.event_1, on_test)
|
||||||
|
assert eb.has_subscriber(Events.event_1)
|
||||||
|
assert !eb.has_subscriber(Events.event_2)
|
||||||
|
assert eb.subscriber.is_subscribed(Events.event_1)
|
||||||
|
eb.publish(Events.event_1, eb, ev_data)
|
||||||
|
assert !eb.has_subscriber(Events.event_1)
|
||||||
|
assert !eb.subscriber.is_subscribed(Events.event_1)
|
||||||
|
eb.subscriber.subscribe(Events.event_1, on_test)
|
||||||
|
assert eb.has_subscriber(Events.event_1)
|
||||||
|
assert eb.subscriber.is_subscribed(Events.event_1)
|
||||||
|
eb.clear_all()
|
||||||
|
assert !eb.has_subscriber(Events.event_1)
|
||||||
|
assert !eb.subscriber.is_subscribed(Events.event_1)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn test_eventbus_int() {
|
||||||
|
ev_data := &EventData{'hello'}
|
||||||
|
mut eb := eventbus.EventBus.new[int]()
|
||||||
|
eb.subscriber.subscribe_once(9999, on_test)
|
||||||
|
assert eb.has_subscriber(9999)
|
||||||
|
assert !eb.has_subscriber(1111)
|
||||||
|
assert eb.subscriber.is_subscribed(9999)
|
||||||
|
eb.publish(9999, eb, ev_data)
|
||||||
|
assert !eb.has_subscriber(9999)
|
||||||
|
assert !eb.subscriber.is_subscribed(9999)
|
||||||
|
eb.subscriber.subscribe(9999, on_test)
|
||||||
|
assert eb.has_subscriber(9999)
|
||||||
|
assert eb.subscriber.is_subscribed(9999)
|
||||||
|
eb.clear_all()
|
||||||
|
assert !eb.has_subscriber(9999)
|
||||||
|
assert !eb.subscriber.is_subscribed(9999)
|
||||||
|
}
|
||||||
|
|
||||||
fn test_subscribe_method() {
|
fn test_subscribe_method() {
|
||||||
// Does not really test subscribe_method idinvidually though
|
// Does not really test subscribe_method idinvidually though
|
||||||
// given
|
// given
|
||||||
mut eb := eventbus.new()
|
mut eb := eventbus.new[string]()
|
||||||
r := FakeReceiver{}
|
r := FakeReceiver{}
|
||||||
|
|
||||||
assert !eb.subscriber.is_subscribed_method('on_test_with_receiver', r)
|
assert !eb.subscriber.is_subscribed_method('on_test_with_receiver', r)
|
||||||
@ -41,7 +84,7 @@ fn test_subscribe_method() {
|
|||||||
|
|
||||||
fn test_unsubscribe_method() {
|
fn test_unsubscribe_method() {
|
||||||
// given
|
// given
|
||||||
mut eb := eventbus.new()
|
mut eb := eventbus.new[string]()
|
||||||
r := FakeReceiver{}
|
r := FakeReceiver{}
|
||||||
r2 := FakeReceiver{}
|
r2 := FakeReceiver{}
|
||||||
|
|
||||||
@ -58,7 +101,7 @@ fn test_unsubscribe_method() {
|
|||||||
fn test_publish() {
|
fn test_publish() {
|
||||||
// given
|
// given
|
||||||
ev_data := &EventData{'hello'}
|
ev_data := &EventData{'hello'}
|
||||||
mut eb := eventbus.new()
|
mut eb := eventbus.new[string]()
|
||||||
|
|
||||||
// when
|
// when
|
||||||
eb.subscriber.subscribe_once('on_test', on_test)
|
eb.subscriber.subscribe_once('on_test', on_test)
|
||||||
@ -71,7 +114,7 @@ fn test_publish() {
|
|||||||
|
|
||||||
fn test_publish_with_receiver() {
|
fn test_publish_with_receiver() {
|
||||||
// given
|
// given
|
||||||
mut eb := eventbus.new()
|
mut eb := eventbus.new[string]()
|
||||||
ev_data := &EventData{'hello'}
|
ev_data := &EventData{'hello'}
|
||||||
r := FakeReceiver{}
|
r := FakeReceiver{}
|
||||||
|
|
||||||
@ -85,7 +128,7 @@ fn test_publish_with_receiver() {
|
|||||||
|
|
||||||
fn test_unsubscribe_reveiver() {
|
fn test_unsubscribe_reveiver() {
|
||||||
// given
|
// given
|
||||||
mut eb := eventbus.new()
|
mut eb := eventbus.new[string]()
|
||||||
r := &FakeReceiver{}
|
r := &FakeReceiver{}
|
||||||
|
|
||||||
// when
|
// when
|
||||||
|
@ -5,7 +5,7 @@ struct MyMessage {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn test_fn_call_with_nonpointer_rvalue() {
|
fn test_fn_call_with_nonpointer_rvalue() {
|
||||||
eb := eventbus.new()
|
eb := eventbus.new[string]()
|
||||||
mut subscriber := eb.subscriber
|
mut subscriber := eb.subscriber
|
||||||
|
|
||||||
subscriber.subscribe('my_publish', subscriber_method)
|
subscriber.subscribe('my_publish', subscriber_method)
|
||||||
@ -18,6 +18,6 @@ fn subscriber_method(receiver voidptr, ev &MyMessage, sender voidptr) {
|
|||||||
println(ev)
|
println(ev)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn do_something(eb &eventbus.EventBus) {
|
fn do_something[T](eb &eventbus.EventBus[T]) {
|
||||||
eb.publish('my_publish', eb, MyMessage{ msg: 'this is my message' })
|
eb.publish('my_publish', eb, MyMessage{ msg: 'this is my message' })
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user