-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Update license years, add BiConsumerEvent, clarify javadocs, add clear()
- Loading branch information
Showing
7 changed files
with
347 additions
and
31 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
153 changes: 153 additions & 0 deletions
153
src/main/java/blue/endless/tinyevents/BiConsumerEvent.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,153 @@ | ||
/* | ||
* MIT License | ||
* | ||
* Copyright (c) 2021-2023 Falkreon (Isaac Ellingson) | ||
* | ||
* Permission is hereby granted, free of charge, to any person obtaining a copy | ||
* of this software and associated documentation files (the "Software"), to deal | ||
* in the Software without restriction, including without limitation the rights | ||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
* copies of the Software, and to permit persons to whom the Software is | ||
* furnished to do so, subject to the following conditions: | ||
* | ||
* The above copyright notice and this permission notice shall be included in all | ||
* copies or substantial portions of the Software. | ||
* | ||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
* SOFTWARE. | ||
*/ | ||
|
||
package blue.endless.tinyevents; | ||
|
||
import java.util.concurrent.Executor; | ||
import java.util.function.BiConsumer; | ||
|
||
/** | ||
* Represents an Event where event-responders receive two pieces of information. | ||
* | ||
* <p>To respond to an Event of this type, you need a BiConsumer that accepts the data this event produces - so if it's | ||
* a {@code ConsumerEvent<Integer, String>}, you need to register a {@code BiConsumer<Integer,String>}. You can also | ||
* optionally supply a registration key that can be used to unregister the event, and/or an Executor to defer event | ||
* handler execution to. | ||
* | ||
* <p>To "provide" a new BiConsumerEvent, you might do something like, | ||
* | ||
* <pre> | ||
* public class Foo { | ||
* private final ConsumerEvent<String, String> onNameChanged = ConsumerEvent.create(); | ||
* private String name = "default"; | ||
* | ||
* public ConsumerEvent<String, String> onNameChanged() { | ||
* return onNameChanged; | ||
* } | ||
* | ||
* public void changeName(String name) { | ||
* String oldName = this.name; | ||
* this.name = name; | ||
* | ||
* onNameChange.fire(oldName, name); | ||
* } | ||
* } | ||
* </pre> | ||
* | ||
* Note that generally Events fire after their corresponding logic, and their verb names are past tense, since they're | ||
* best used for situations where you can't change the triggering event, but you're responding to it. | ||
* | ||
* See {@link #register(BiConsumer)} for more info on how to register and respond to events of this type. | ||
*/ | ||
public interface BiConsumerEvent<T, U> { | ||
/** | ||
* Fire this event, causing all the registered handlers to be called. How the handlers | ||
* are scheduled, when they will run, and on what thread, depends on how they registered | ||
* and, if applicable, the Executor they were registered with. | ||
* @param t the first argument the BiConsumer event responders will accept | ||
* @param u the second argument the BiConsumer event responders will accept | ||
*/ | ||
void fire(T t, U u); | ||
|
||
/** | ||
* Registers an event handler to be run when this Event is fired. | ||
* | ||
* <p>Note: Because of the semantics regarding lambdas, the following will not work: | ||
* <pre> | ||
* public void throwSomething(int a, int b) { | ||
* assert(false); | ||
* } | ||
* | ||
* public static void main(String[] args) { | ||
* BiConsumerEvent<Integer, Integer> onRun = ConsumerEvent<Integer, Integer>.create(); | ||
* onRun.register(this::throwSomething); | ||
* onRun.unregister(this::throwSomething); | ||
* onRun.fire(1, 1); | ||
* } | ||
* </pre> | ||
* | ||
* <p>This is because the lambda which {@code this::throwSomething} is implicitly cast | ||
* to, (causing the lambda to be generated by lambdaMetafactory) may be different for | ||
* each capture site. This was done to make lambdas extremely fast, but is inconvenient | ||
* for event systems. A workaround is to say instead, | ||
* | ||
* <pre> | ||
* public void throwSomething(int a, int b) { | ||
* assert(false); | ||
* } | ||
* | ||
* public static void main(String[] args) { | ||
* ConsumerEvent<Integer, Integer> onRun = ConsumerEvent.create(); | ||
* | ||
* Consumer<Integer, Integer> handler = this::throwSomething; //handler is always reference-equal to handler | ||
* | ||
* onRun.register(handler); | ||
* onRun.unregister(handler); | ||
* onRun.fire(1, 1); | ||
* } | ||
* </pre> | ||
* | ||
* or to supply a registration key where reference equality can be guaranteed. | ||
* | ||
* @param handler | ||
*/ | ||
void register(BiConsumer<T, U> handler); | ||
|
||
/** | ||
*Registers an event handler to be run when this Event is fired. | ||
* | ||
* @param handler The event handler to be invoked when {@link #fire(T, U)} is called. | ||
* @param key A key which can be later used to unregister the event handler | ||
*/ | ||
void register(BiConsumer<T, U> handler, Object key); | ||
|
||
/** | ||
* Registers an event handler to be run when this Event is fired. | ||
* @param handler The event handler to be invoked when {@link #fire(T, U)} is called. | ||
* @param executor The executor to run the handler on | ||
*/ | ||
void register(BiConsumer<T, U> handler, Executor executor); | ||
|
||
/** | ||
* Registers an event handler to be run when this Event is fired. | ||
* @param handler The event handler to be invoked when {@link #fire(T, U)} is called. | ||
* @param executor The executor to run the handler on | ||
* @param key A key which can later be used to unregister the event handler | ||
*/ | ||
void register(BiConsumer<T, U> handler, Executor executor, Object key); | ||
|
||
/** | ||
* Unregisters and event handler. The object will be <em>reference-compared</em> (==) with | ||
* the key of each existing event handler to determine whether it should be unregistered. | ||
* If multiple event handlers were registered with this key, all of them will be removed. | ||
* @param key | ||
*/ | ||
void unregister(Object key); | ||
|
||
/** | ||
* Unregisters ALL event handlers attached to this event. If event handlers are currently firing, they may continue | ||
* to fire until the event is complete. | ||
*/ | ||
void clear(); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.