diff --git a/src/main/java/net/minecraftforge/eventbus/api/bus/BusGroup.java b/src/main/java/net/minecraftforge/eventbus/api/bus/BusGroup.java index 3bb9559..f2548bc 100644 --- a/src/main/java/net/minecraftforge/eventbus/api/bus/BusGroup.java +++ b/src/main/java/net/minecraftforge/eventbus/api/bus/BusGroup.java @@ -9,25 +9,47 @@ import net.minecraftforge.eventbus.api.listener.SubscribeEvent; import net.minecraftforge.eventbus.internal.BusGroupImpl; +import java.lang.invoke.LambdaMetafactory; import java.lang.invoke.MethodHandles; import java.util.Collection; /** - * A collection of {@link EventBus} instances that are grouped together for easier management. + * A collection of {@link EventBus} instances that are grouped together for easier management, allowing for bulk + * operations. */ public sealed interface BusGroup permits BusGroupImpl { + /** + * The default BusGroup, which is used when an {@link EventBus} is created without specifying a BusGroup. + */ BusGroup DEFAULT = create("default"); + /** + * Creates a new BusGroup with the given name. + * + * @param name The unique name of the BusGroup + * @return A new BusGroup with the given name + * @throws IllegalArgumentException if the name is already in use by another BusGroup + * @apiNote To enforce a base type for all events in this BusGroup, use {@link #create(String, Class)}. + */ static BusGroup create(String name) { return new BusGroupImpl(name, Event.class); } + /** + * Creates a new BusGroup with the given name and base type. + * + * @param name The unique name of the BusGroup + * @param baseType The base type that all events in this BusGroup must extend or implement + * @return A new BusGroup with the given name and base type + * @throws IllegalArgumentException if the name is already in use by another BusGroup + */ static BusGroup create(String name, Class> baseType) { return new BusGroupImpl(name, baseType); } /** * The unique name of this BusGroup. + *
The uniqueness of this name is enforced when the bus group is {@linkplain #create(String) created}.
*/ String name(); @@ -40,21 +62,30 @@ static BusGroup create(String name, Class> baseType) { /** * Shuts down all EventBus instances associated with this BusGroup, preventing any further events from being posted * until {@link #startup()} is called. + * + * @apiNote If you don't intend on using this BusGroup again, prefer {@link #dispose()} instead as that will also + * free up resources. */ void shutdown(); /** - * Shuts down all EventBus instances associated with this BusGroup, unregisters all listeners and frees resources - * no longer needed. - *Warning: This is a destructive operation - this BusGroup should not be used again after calling this method.
+ * {@linkplain #shutdown() Shuts down} all EventBus instances associated with this BusGroup, + * {@linkplain #unregister(Collection) unregisters} all listeners and frees no longer needed resources. + * + *Warning: This is a destructive operation - this BusGroup should not be used again after calling this method - + * attempting to do so may throw exceptions or act as a no-op.
+ * + * @apiNote If you plan on using this BusGroup again, prefer {@link #shutdown()} instead. */ void dispose(); /** - * Experimental feature - may be removed, renamed or otherwise changed without notice. - *Trims the backing lists of all EventBus instances associated with this BusGroup to free up resources.
+ * Trims the backing lists of all EventBus instances associated with this BusGroup to free up resources. + * *Warning: This is only intended to be called once after all listeners are registered - calling this * repeatedly may hurt performance.
+ * + * @apiNote This is an experimental feature that may be removed, renamed or otherwise changed without notice. */ void trim(); @@ -68,6 +99,11 @@ static BusGroup create(String name, Class> baseType) { * @apiNote This method only registers static listeners. *If you want to register both instance and static methods, use * {@link BusGroup#register(MethodHandles.Lookup, Object)} instead.
+ * @implNote Internally, bulk registration uses {@link LambdaMetafactory} to create method references to the + * annotated methods using the provided {@code callerLookup} - said lookup must have + * {@linkplain MethodHandles.Lookup#hasFullPrivilegeAccess() full privilege access} as + * {@linkplain LambdaMetafactory LMF} may need to spin an inner class for implementing the lambda, which + * inherently allows access to private fields and methods. */ CollectionMore advanced techniques like protected fields and methods are also possible, where the supertype may be a + * protected abstract class with some internals handled for you, but only the concrete types are actual events.
+ * + *Consider {@link RecordEvent} for better performance and conciseness if field mutability and direct extendability + * aren't needed.
+ * + * @see RecordEvent + */ public non-sealed abstract class MutableEvent extends MutableEventInternals implements Event {} diff --git a/src/main/java/net/minecraftforge/eventbus/api/event/RecordEvent.java b/src/main/java/net/minecraftforge/eventbus/api/event/RecordEvent.java index 7ed4ecd..5cdfe34 100644 --- a/src/main/java/net/minecraftforge/eventbus/api/event/RecordEvent.java +++ b/src/main/java/net/minecraftforge/eventbus/api/event/RecordEvent.java @@ -4,9 +4,34 @@ */ package net.minecraftforge.eventbus.api.event; +import net.minecraftforge.eventbus.api.bus.EventBus; +import net.minecraftforge.eventbus.api.event.characteristic.Cancellable; import net.minecraftforge.eventbus.internal.Event; /** * For read-only or shallowly-immutable records. + *Provides a means for declaring events in a concise and performant manner.
+ * + *Here are some conceptual examples of record events:
+ *Note that while records are final and cannot extend other classes, inheritance is still possible through other + * means, such as by implementing a sealed interface and using the Java module system.
+ * + * @apiNote Cancellation is supported for record events as long as they also implement the {@link Cancellable} + * characteristic - this is possible thanks to the cancellation state being kept on the stack separately from + * the record instance itself. + * @implSpec This event base type can only be applied to {@linkplain Record Java record classes}. + * If you implement this interface on an ordinary class, an exception will be thrown when attempting to + * create an associated {@link EventBus}. */ public non-sealed interface RecordEvent extends Event {} diff --git a/src/main/java/net/minecraftforge/eventbus/api/event/characteristic/Cancellable.java b/src/main/java/net/minecraftforge/eventbus/api/event/characteristic/Cancellable.java index a01cebd..1d126c9 100644 --- a/src/main/java/net/minecraftforge/eventbus/api/event/characteristic/Cancellable.java +++ b/src/main/java/net/minecraftforge/eventbus/api/event/characteristic/Cancellable.java @@ -5,11 +5,25 @@ package net.minecraftforge.eventbus.api.event.characteristic; import net.minecraftforge.eventbus.api.bus.CancellableEventBus; +import net.minecraftforge.eventbus.api.event.RecordEvent; +import net.minecraftforge.eventbus.api.listener.Priority; import net.minecraftforge.eventbus.internal.Event; import net.minecraftforge.eventbus.internal.EventCharacteristic; +import java.util.function.Consumer; +import java.util.function.Predicate; + /** - * A cancellable event returns {@code true} from {@link CancellableEventBus#post(Event)} if it was cancelled. - *When an event is cancelled, it will not be passed to any further non-monitor listeners.
+ * A cancellable event returns {@code true} from {@link CancellableEventBus#post(Event)} if it was cancelled by a + * {@linkplain CancellableEventBus#addListener(Predicate) 'maybe cancelling'} or + * {@linkplain CancellableEventBus#addListener(boolean, Consumer) 'always cancelling'} listener. + * + *When an event is cancelled, it will not be passed to any further non-{@linkplain Priority#MONITOR monitor} + * listeners. + * For further details on a cancellable event's interactions with an EventBus, see {@link CancellableEventBus}.
+ * + * @implNote Internally, the cancellation state is kept on the stack separately from the event instance itself, allowing + * for this characteristic to be applied to any event type - even {@link RecordEvent}s. + * @see CancellableEventBus */ public non-sealed interface Cancellable extends EventCharacteristic {} diff --git a/src/main/java/net/minecraftforge/eventbus/api/event/characteristic/MonitorAware.java b/src/main/java/net/minecraftforge/eventbus/api/event/characteristic/MonitorAware.java index 266d505..815d6d4 100644 --- a/src/main/java/net/minecraftforge/eventbus/api/event/characteristic/MonitorAware.java +++ b/src/main/java/net/minecraftforge/eventbus/api/event/characteristic/MonitorAware.java @@ -4,15 +4,21 @@ */ package net.minecraftforge.eventbus.api.event.characteristic; +import net.minecraftforge.eventbus.api.bus.EventBus; import net.minecraftforge.eventbus.api.event.MutableEvent; +import net.minecraftforge.eventbus.api.event.RecordEvent; +import net.minecraftforge.eventbus.api.listener.Priority; import net.minecraftforge.eventbus.internal.EventCharacteristic; import net.minecraftforge.eventbus.internal.MutableEventInternals; /** - * Experimental feature - may be removed, renamed or otherwise changed without notice. - *Events that are {@link MonitorAware} can provide stronger immutability guarantees to monitor listeners by - * returning unmodifiable views or throwing exceptions on mutation attempts when monitoring.
- *Only supported for {@link MutableEvent} at this time.
+ * Events that are {@linkplain Priority#MONITOR monitor}-aware are able to provide stronger immutability guarantees to + * monitoring listeners by returning unmodifiable views or throwing exceptions on mutation attempts when monitoring. + * + * @apiNote This is an experimental feature that may be removed, renamed or otherwise changed without notice. + * @implNote This characteristic is only supported for the {@link MutableEvent} base type at this time. + * If combined with a different base type (such as {@link RecordEvent}), an exception will be thrown when + * attempting to create an associated {@link EventBus}. */ public non-sealed interface MonitorAware extends EventCharacteristic { default boolean isMonitoring() { diff --git a/src/main/java/net/minecraftforge/eventbus/api/event/characteristic/SelfDestructing.java b/src/main/java/net/minecraftforge/eventbus/api/event/characteristic/SelfDestructing.java index 04fc80d..c70856e 100644 --- a/src/main/java/net/minecraftforge/eventbus/api/event/characteristic/SelfDestructing.java +++ b/src/main/java/net/minecraftforge/eventbus/api/event/characteristic/SelfDestructing.java @@ -4,13 +4,16 @@ */ package net.minecraftforge.eventbus.api.event.characteristic; +import net.minecraftforge.eventbus.api.bus.BusGroup; import net.minecraftforge.eventbus.api.bus.EventBus; -import net.minecraftforge.eventbus.internal.AbstractEventBusImpl; import net.minecraftforge.eventbus.internal.EventCharacteristic; /** - * A self-destructing event will {@link AbstractEventBusImpl#dispose() dispose} of its associated {@link EventBus} - * after it has been posted to free up resources, after which it cannot be posted to again. + * A self-destructing event will {@link BusGroup#dispose() dispose} of its associated {@link EventBus} after it has + * been posted to free up resources, after which it cannot be posted to again. *This is useful for single-use lifecycle events.
+ * + * @apiNote The dispose action is similar to {@link BusGroup#dispose()}, but applies to only this event rather than to + * all events in the group. */ public non-sealed interface SelfDestructing extends EventCharacteristic {} diff --git a/src/main/java/net/minecraftforge/eventbus/api/event/characteristic/SelfPosting.java b/src/main/java/net/minecraftforge/eventbus/api/event/characteristic/SelfPosting.java index fdf21f1..d3fefea 100644 --- a/src/main/java/net/minecraftforge/eventbus/api/event/characteristic/SelfPosting.java +++ b/src/main/java/net/minecraftforge/eventbus/api/event/characteristic/SelfPosting.java @@ -9,12 +9,14 @@ import net.minecraftforge.eventbus.internal.EventCharacteristic; /** - * Experimental feature - may be removed, renamed or otherwise changed without notice. - *{@link SelfPosting} events are associated with a default {@link EventBus} in order to offer some convenience - * instance methods.
- * Example + * Self-posting events are associated with a default {@link EventBus}, allowing for some convenience methods on the + * instance. + * + *Internally, this acts as a wrapper over lambdas to give them identity, enrich debug info and to allow - * various conversion operations to different lambda types.
+ * + * @implNote Internally, this acts as a wrapper over lambdas to give them identity, enrich debug info and to allow + * various conversion operations to different lambda types. */ public sealed interface EventListener permits EventListenerImpl { @SuppressWarnings("ClassEscapesDefinedScope") // ? can be a subtype of Event which is publicly accessible Class extends Event> eventType(); /** + * The priority of this listener. Higher numbers are called first. * @see Priority */ byte priority(); /** + * Whether this listener is known to always cancel the {@link Cancellable} event when called. * @see CancellableEventBus#addListener(boolean, Consumer) */ default boolean alwaysCancelling() { diff --git a/src/main/java/net/minecraftforge/eventbus/internal/Event.java b/src/main/java/net/minecraftforge/eventbus/internal/Event.java index b76cc27..0e79d5a 100644 --- a/src/main/java/net/minecraftforge/eventbus/internal/Event.java +++ b/src/main/java/net/minecraftforge/eventbus/internal/Event.java @@ -8,4 +8,23 @@ import net.minecraftforge.eventbus.api.event.MutableEvent; import net.minecraftforge.eventbus.api.event.RecordEvent; +/** + * The internal marker interface for all event base types. This is internal and sealed for many reasons: + *Library users should use one of the three base types instead:
+ *