diff --git a/eventbus-jmh/src/main/java/net/minecraftforge/eventbus/benchmarks/EventBusBenchmark.java b/eventbus-jmh/src/main/java/net/minecraftforge/eventbus/benchmarks/EventBusBenchmark.java index dc998c6..c10162b 100644 --- a/eventbus-jmh/src/main/java/net/minecraftforge/eventbus/benchmarks/EventBusBenchmark.java +++ b/eventbus-jmh/src/main/java/net/minecraftforge/eventbus/benchmarks/EventBusBenchmark.java @@ -20,6 +20,7 @@ public class EventBusBenchmark { private Consumer postStatic; private Consumer postDynamic; private Consumer postLambda; + private Consumer postClassLambda; private Consumer postCombined; @SuppressWarnings("unchecked") @@ -37,6 +38,7 @@ public void setup() throws Exception { postDynamic = (Consumer)cls.getField("postDynamic").get(null); postLambda = (Consumer)cls.getField("postLambda").get(null); postCombined = (Consumer)cls.getField("postCombined").get(null); + postClassLambda = (Consumer)cls.getField("postClassLambda").get(null); } public static class TestCallback { @@ -70,6 +72,13 @@ public int testModLauncherCombined() throws Throwable { return 0; } + @Benchmark + public int testModLauncherClassLambda() + { + postClassLambda.accept(ModLauncher); + return 0; + } + // ClassLoader ASM Factory @Benchmark public int testClassLoaderDynamic() throws Throwable { @@ -94,4 +103,11 @@ public int testClassLoaderCombined() throws Throwable { postCombined.accept(ClassLoader); return 0; } + + @Benchmark + public int testClassLoaderClassLambda() + { + postClassLambda.accept(ClassLoader); + return 0; + } } diff --git a/eventbus-jmh/src/main/java/net/minecraftforge/eventbus/benchmarks/EventBusBenchmarkNoLoader.java b/eventbus-jmh/src/main/java/net/minecraftforge/eventbus/benchmarks/EventBusBenchmarkNoLoader.java index a58fe1b..7e764a6 100644 --- a/eventbus-jmh/src/main/java/net/minecraftforge/eventbus/benchmarks/EventBusBenchmarkNoLoader.java +++ b/eventbus-jmh/src/main/java/net/minecraftforge/eventbus/benchmarks/EventBusBenchmarkNoLoader.java @@ -32,4 +32,10 @@ public int testNoLoaderCombined() { BenchmarkArmsLength.postCombined(BenchmarkArmsLength.NoLoader); return 0; } + + @Benchmark + public int testNoLoaderClassLambda() { + BenchmarkArmsLength.postClassLambda(BenchmarkArmsLength.NoLoader); + return 0; + } } diff --git a/eventbus-test/src/test/java/net/minecraftforge/eventbus/test/TestModLauncher.java b/eventbus-test/src/test/java/net/minecraftforge/eventbus/test/TestModLauncher.java index 410b4f4..b370597 100644 --- a/eventbus-test/src/test/java/net/minecraftforge/eventbus/test/TestModLauncher.java +++ b/eventbus-test/src/test/java/net/minecraftforge/eventbus/test/TestModLauncher.java @@ -3,6 +3,7 @@ import org.junit.jupiter.api.Test; import net.minecraftforge.eventbus.test.general.AbstractEventListenerTest; +import net.minecraftforge.eventbus.test.general.ClassLambdaHandlerTest; import net.minecraftforge.eventbus.test.general.DeadlockingEventTest; import net.minecraftforge.eventbus.test.general.EventBusSubtypeFilterTest; import net.minecraftforge.eventbus.test.general.EventFiringEventTest; @@ -69,6 +70,16 @@ public void lambdaGenerics() { doTest(new LambdaHandlerTest.Generics() {}); } + @Test + public void classLambdaBasic() { + doTest(new ClassLambdaHandlerTest.Basic() {}); + } + + @Test + public void classLambdaSubClass() { + doTest(new ClassLambdaHandlerTest.SubClassEvent() {}); + } + @Disabled @RepeatedTest(500) public void deadlockTest() { diff --git a/eventbus-test/src/test/java/net/minecraftforge/eventbus/test/TestNoLoader.java b/eventbus-test/src/test/java/net/minecraftforge/eventbus/test/TestNoLoader.java index 50600bf..891ebec 100644 --- a/eventbus-test/src/test/java/net/minecraftforge/eventbus/test/TestNoLoader.java +++ b/eventbus-test/src/test/java/net/minecraftforge/eventbus/test/TestNoLoader.java @@ -3,6 +3,7 @@ import org.junit.jupiter.api.Test; import net.minecraftforge.eventbus.test.general.AbstractEventListenerTest; +import net.minecraftforge.eventbus.test.general.ClassLambdaHandlerTest; import net.minecraftforge.eventbus.test.general.DeadlockingEventTest; import net.minecraftforge.eventbus.test.general.EventBusSubtypeFilterTest; import net.minecraftforge.eventbus.test.general.EventFiringEventTest; @@ -75,6 +76,16 @@ public void lambdaGenerics() { doTest(new LambdaHandlerTest.Generics() {}); } + @Test + public void classLambdaBasic() { + doTest(new ClassLambdaHandlerTest.Basic() {}); + } + + @Test + public void classLambdaSubClass() { + doTest(new ClassLambdaHandlerTest.SubClassEvent() {}); + } + @Disabled @RepeatedTest(500) public void deadlockTest() { diff --git a/eventbus-test/src/test/java/net/minecraftforge/eventbus/test/general/ClassLambdaHandlerTest.java b/eventbus-test/src/test/java/net/minecraftforge/eventbus/test/general/ClassLambdaHandlerTest.java new file mode 100644 index 0000000..3d1f7c8 --- /dev/null +++ b/eventbus-test/src/test/java/net/minecraftforge/eventbus/test/general/ClassLambdaHandlerTest.java @@ -0,0 +1,69 @@ +package net.minecraftforge.eventbus.test.general; + +import net.minecraftforge.eventbus.api.*; +import net.minecraftforge.eventbus.test.ITestHandler; + +import java.util.function.Consumer; +import java.util.function.Function; +import java.util.function.Supplier; + +import static org.junit.jupiter.api.Assertions.assertTrue; + +public abstract class ClassLambdaHandlerTest implements ITestHandler { + boolean hit; + + @Override + public void before(Consumer> validator, Supplier builder) { + validator.accept(SubEvent.class); + validator.accept(CancellableEvent.class); + hit = false; + } + + public void consumeEvent(Event e) { hit = true; } + public void consumeSubEvent(SubEvent e) { hit = true; } + + public static class Basic extends ClassLambdaHandlerTest + { + @Override + public void test(Consumer> validator, Supplier builder) { + final IEventBus iEventBus = builder.get().build(); + // Inline + iEventBus.addListener(Event.class, (e)-> hit = true); + iEventBus.post(new Event()); + assertTrue(hit, "Inline Lambda was not called"); + hit = false; + // Method reference + iEventBus.addListener(Event.class, this::consumeEvent); + iEventBus.post(new Event()); + assertTrue(hit, "Method reference was not called"); + hit = false; + } + } + + public static class SubClassEvent extends ClassLambdaHandlerTest + { + @Override + public void test(Consumer> validator, Supplier builder) { + final IEventBus iEventBus = builder.get().build(); + // Inline + iEventBus.addListener(SubEvent.class, (e) -> hit = true); + iEventBus.post(new SubEvent()); + assertTrue(hit, "Inline was not called"); + hit = false; + iEventBus.post(new Event()); + assertTrue(!hit, "Inline was called on root event"); + // Method Reference + iEventBus.addListener(SubEvent.class, this::consumeSubEvent); + iEventBus.post(new SubEvent()); + assertTrue(hit, "Method reference was not called"); + hit = false; + iEventBus.post(new Event()); + assertTrue(!hit, "Method reference was called on root event"); + } + } + + public static class SubEvent extends Event {} + + @Cancelable + public static class CancellableEvent extends Event {} +} diff --git a/eventbus-testjars/src/main/java/net/minecraftforge/eventbus/benchmarks/compiled/BenchmarkArmsLength.java b/eventbus-testjars/src/main/java/net/minecraftforge/eventbus/benchmarks/compiled/BenchmarkArmsLength.java index 08768ab..0f3640b 100644 --- a/eventbus-testjars/src/main/java/net/minecraftforge/eventbus/benchmarks/compiled/BenchmarkArmsLength.java +++ b/eventbus-testjars/src/main/java/net/minecraftforge/eventbus/benchmarks/compiled/BenchmarkArmsLength.java @@ -11,7 +11,8 @@ public record Bus( IEventBus staticSubscriberBus, IEventBus dynamicSubscriberBus, IEventBus lambdaSubscriberBus, - IEventBus combinedSubscriberBus + IEventBus combinedSubscriberBus, + IEventBus classLambdaSubscriberBus ) { public Bus register() { staticSubscriberBus.register(SubscriberStatic.class); @@ -20,6 +21,7 @@ public Bus register() { combinedSubscriberBus.register(new SubscriberDynamic()); SubscriberLambda.register(lambdaSubscriberBus); SubscriberLambda.register(combinedSubscriberBus); + SubscriberClassLambda.register(classLambdaSubscriberBus); return this; } }; @@ -36,12 +38,14 @@ public static Runnable supplier() { BusBuilder.builder().useModLauncher().build(), BusBuilder.builder().useModLauncher().build(), BusBuilder.builder().useModLauncher().build(), + BusBuilder.builder().useModLauncher().build(), BusBuilder.builder().useModLauncher().build() ).register(); ClassLoader = new Bus( BusBuilder.builder().build(), BusBuilder.builder().build(), BusBuilder.builder().build(), + BusBuilder.builder().build(), BusBuilder.builder().build() ).register(); }; @@ -53,6 +57,7 @@ public static Runnable supplier() { BusBuilder.builder().build(), BusBuilder.builder().build(), BusBuilder.builder().build(), + BusBuilder.builder().build(), BusBuilder.builder().build() ).register(); @@ -60,6 +65,7 @@ public static Runnable supplier() { public static final Consumer postDynamic = BenchmarkArmsLength::postDynamic; public static final Consumer postLambda = BenchmarkArmsLength::postLambda; public static final Consumer postCombined = BenchmarkArmsLength::postCombined; + public static final Consumer postClassLambda = BenchmarkArmsLength::postLambda; public static void postStatic(Object bus) { @@ -81,6 +87,11 @@ public static void postCombined(Object bus) postAll(((Bus)bus).combinedSubscriberBus); } + public static void postClassLambda(Object bus) + { + postAll(((Bus)bus).classLambdaSubscriberBus); + } + private static void postAll(IEventBus bus) { bus.post(new CancelableEvent()); diff --git a/eventbus-testjars/src/main/java/net/minecraftforge/eventbus/benchmarks/compiled/SubscriberClassLambda.java b/eventbus-testjars/src/main/java/net/minecraftforge/eventbus/benchmarks/compiled/SubscriberClassLambda.java new file mode 100644 index 0000000..24b0509 --- /dev/null +++ b/eventbus-testjars/src/main/java/net/minecraftforge/eventbus/benchmarks/compiled/SubscriberClassLambda.java @@ -0,0 +1,29 @@ +package net.minecraftforge.eventbus.benchmarks.compiled; + +import net.minecraftforge.eventbus.api.IEventBus; + +public class SubscriberClassLambda +{ + + public static void register(IEventBus bus) + { + bus.addListener(CancelableEvent.class, SubscriberClassLambda::onCancelableEvent); + bus.addListener(ResultEvent.class, SubscriberClassLambda::onResultEvent); + bus.addListener(EventWithData.class, SubscriberClassLambda::onSimpleEvent); + } + + public static void onCancelableEvent(CancelableEvent event) + { + + } + + public static void onResultEvent(ResultEvent event) + { + + } + + public static void onSimpleEvent(EventWithData event) + { + + } +} diff --git a/src/main/java/net/minecraftforge/eventbus/EventBus.java b/src/main/java/net/minecraftforge/eventbus/EventBus.java index 9c51ccc..274304a 100644 --- a/src/main/java/net/minecraftforge/eventbus/EventBus.java +++ b/src/main/java/net/minecraftforge/eventbus/EventBus.java @@ -187,12 +187,24 @@ public void addListener(final Consumer consumer) { addListener(EventPriority.NORMAL, consumer); } + @Override + public void addListener(final Class eventType, final Consumer consumer) { + checkNotGeneric(eventType); + addListener(EventPriority.NORMAL, eventType, consumer); + } + @Override public void addListener(final EventPriority priority, final Consumer consumer) { checkNotGeneric(consumer); addListener(priority, false, consumer); } + @Override + public void addListener(final EventPriority priority, final Class eventType, final Consumer consumer) { + checkNotGeneric(eventType); + addListener(priority, false, eventType, consumer); + } + @Override public void addListener(final EventPriority priority, final boolean receiveCancelled, final Consumer consumer) { checkNotGeneric(consumer); @@ -210,11 +222,21 @@ public , F> void addGenericListener(final Cl addGenericListener(genericClassFilter, EventPriority.NORMAL, consumer); } + @Override + public , F> void addGenericListener(final Class genericClassFilter, final Class eventType, final Consumer consumer) { + addGenericListener(genericClassFilter, EventPriority.NORMAL, eventType, consumer); + } + @Override public , F> void addGenericListener(final Class genericClassFilter, final EventPriority priority, final Consumer consumer) { addGenericListener(genericClassFilter, priority, false, consumer); } + @Override + public , F> void addGenericListener(final Class genericClassFilter, final EventPriority priority, final Class eventType, final Consumer consumer) { + addGenericListener(genericClassFilter, priority, false, eventType, consumer); + } + @Override public , F> void addGenericListener(final Class genericClassFilter, final EventPriority priority, final boolean receiveCancelled, final Consumer consumer) { addListener(priority, passGenericFilter(genericClassFilter).and(passCancelled(receiveCancelled)), consumer); diff --git a/src/main/java/net/minecraftforge/eventbus/api/IEventBus.java b/src/main/java/net/minecraftforge/eventbus/api/IEventBus.java index e266356..d257a86 100644 --- a/src/main/java/net/minecraftforge/eventbus/api/IEventBus.java +++ b/src/main/java/net/minecraftforge/eventbus/api/IEventBus.java @@ -37,6 +37,15 @@ public interface IEventBus { */ void addListener(Consumer consumer); + /** + * Add a consumer listener with default {@link EventPriority#NORMAL} and not recieving cancelled events. + * + * @param eventType The concrete {@link Event} subclass to subscribe to + * @param consumer Callback to invoke when a matching event is received + * @param The {@link Event} subclass to listen for + */ + void addListener(Class eventType, Consumer consumer); + /** * Add a consumer listener with the specified {@link EventPriority} and not receiving cancelled events. * @@ -46,6 +55,16 @@ public interface IEventBus { */ void addListener(EventPriority priority, Consumer consumer); + /** + * Add a consumer listener with the specified {@link EventPriority} and not receiving cancelled events. + * + * @param priority {@link EventPriority} for this listener + * @param eventType The concrete {@link Event} subclass to subscribe to + * @param consumer Callback to invoke when a matching event is received + * @param The {@link Event} subclass to listen for + */ + void addListener(EventPriority priority, Class eventType, Consumer consumer); + /** * Add a consumer listener with the specified {@link EventPriority} and potentially cancelled events. * @@ -81,6 +100,18 @@ public interface IEventBus { */ , F> void addGenericListener(Class genericClassFilter, Consumer consumer); + /** + * Add a consumer listener for a {@link GenericEvent} subclass, filtered to only be called for the specified + * filter {@link Class}. + * + * @param genericClassFilter A {@link Class} which the {@link GenericEvent} should be filtered for + * @param eventType The concrete {@link Event} subclass to subscribe to + * @param consumer Callback to invoke when a matching event is received + * @param The {@link GenericEvent} subclass to listen for + * @param The {@link Class} to filter the {@link GenericEvent} for + */ + , F> void addGenericListener(Class genericClassFilter, Class eventType, Consumer consumer); + /** * Add a consumer listener with the specified {@link EventPriority} and not receiving cancelled events, * for a {@link GenericEvent} subclass, filtered to only be called for the specified @@ -94,6 +125,19 @@ public interface IEventBus { */ , F> void addGenericListener(Class genericClassFilter, EventPriority priority, Consumer consumer); + /** + * Add a consumer listener with the specified {@link EventPriority} and not receiving cancelled events, + * for a {@link GenericEvent} subclass, filtered to only be called for the specified + * filter {@link Class}. + * + * @param genericClassFilter A {@link Class} which the {@link GenericEvent} should be filtered for + * @param priority {@link EventPriority} for this listener + * @param consumer Callback to invoke when a matching event is received + * @param The {@link GenericEvent} subclass to listen for + * @param The {@link Class} to filter the {@link GenericEvent} for + */ + , F> void addGenericListener(Class genericClassFilter, EventPriority priority, Class eventType, Consumer consumer); + /** * Add a consumer listener with the specified {@link EventPriority} and potentially cancelled events, * for a {@link GenericEvent} subclass, filtered to only be called for the specified