diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 2252a01ab..0e96e1439 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -27,7 +27,7 @@ jobs: run: chmod +x gradlew - name: Build with Gradle - run: ./gradlew clean build + run: ./gradlew clean test clean build env: GIT_BRANCH: ${{ github.ref }} GIT_COMMIT: ${{ github.sha }} \ No newline at end of file diff --git a/buildSrc/build.gradle.kts b/buildSrc/build.gradle.kts index 39bd02261..7919c163c 100644 --- a/buildSrc/build.gradle.kts +++ b/buildSrc/build.gradle.kts @@ -7,7 +7,6 @@ repositories { } dependencies { - implementation("me.champeau.jmh:jmh-gradle-plugin:0.7.2") implementation("net.kyori:indra-git:3.1.3") implementation("com.google.guava:guava:30.1.1-jre") } diff --git a/buildSrc/src/main/kotlin/litecommands-java-benchmark.gradle.kts b/buildSrc/src/main/kotlin/litecommands-java-benchmark.gradle.kts deleted file mode 100644 index cc3dd7028..000000000 --- a/buildSrc/src/main/kotlin/litecommands-java-benchmark.gradle.kts +++ /dev/null @@ -1,13 +0,0 @@ -plugins { - - id("me.champeau.jmh") -} - -sourceSets.getByName("jmh") { - java.setSrcDirs(listOf("benchmark")) - resources.setSrcDirs(emptyList()) -} - -dependencies { - jmhAnnotationProcessor("org.openjdk.jmh:jmh-generator-annprocess:1.37") -} \ No newline at end of file diff --git a/litecommands-annotations/benchmark/dev/rollczi/litecommands/benchmark/LiteBenchmark.java b/litecommands-annotations/benchmark/dev/rollczi/litecommands/benchmark/LiteBenchmark.java deleted file mode 100644 index fc262c3bd..000000000 --- a/litecommands-annotations/benchmark/dev/rollczi/litecommands/benchmark/LiteBenchmark.java +++ /dev/null @@ -1,37 +0,0 @@ -package dev.rollczi.litecommands.benchmark; - -import dev.rollczi.litecommands.annotations.argument.Arg; -import dev.rollczi.litecommands.annotations.command.Command; -import dev.rollczi.litecommands.annotations.execute.Execute; -import dev.rollczi.litecommands.unit.LiteCommandsTestFactory; -import dev.rollczi.litecommands.unit.TestPlatform; -import org.openjdk.jmh.runner.RunnerException; - -import java.util.Optional; - -public class LiteBenchmark { - - static TestPlatform testPlatform; - - @Command(name = "test") - static class TestCommand { - @Execute - void execute(@Arg String first, @Arg String second) {} - @Execute(name = "sub") - void execute(@Arg String first, @Arg Optional second) {} - } - - public static void main(String[] args) throws RunnerException { - testPlatform = LiteCommandsTestFactory.startPlatform(builder -> builder - .commands( - new TestCommand() - ) - ); - - for (int i = 0; i < 1_000_000; i++) { - testPlatform.execute("test first second"); - testPlatform.execute("test sub first second"); - } - } - -} diff --git a/litecommands-annotations/build.gradle.kts b/litecommands-annotations/build.gradle.kts index 22d1c1c85..7d4c8aad3 100644 --- a/litecommands-annotations/build.gradle.kts +++ b/litecommands-annotations/build.gradle.kts @@ -4,12 +4,10 @@ plugins { `litecommands-java-unit-test` `litecommands-repositories` `litecommands-publish` - `litecommands-java-benchmark` } dependencies { api(project(":litecommands-core")) - jmhImplementation(project(":litecommands-unit")) } litecommandsUnit { diff --git a/litecommands-annotations/src/dev/rollczi/litecommands/annotations/MethodCommandExecutor.java b/litecommands-annotations/src/dev/rollczi/litecommands/annotations/MethodCommandExecutor.java index daa7dfe54..3cf777624 100644 --- a/litecommands-annotations/src/dev/rollczi/litecommands/annotations/MethodCommandExecutor.java +++ b/litecommands-annotations/src/dev/rollczi/litecommands/annotations/MethodCommandExecutor.java @@ -18,10 +18,12 @@ import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.lang.reflect.Parameter; +import java.util.function.Supplier; class MethodCommandExecutor extends AbstractCommandExecutor { private final Method method; + private final Parameter[] parameters; private final Object instance; private final MethodDefinition definition; private final MethodValidatorService validatorService; @@ -37,6 +39,7 @@ class MethodCommandExecutor extends AbstractCommandExecutor { super(parent, definition.getArguments(), definition.getContextRequirements(), definition.getBindRequirements()); this.method = method; this.method.setAccessible(true); + this.parameters = method.getParameters(); this.instance = instance; this.definition = definition; this.validatorService = validatorService; @@ -47,17 +50,18 @@ class MethodCommandExecutor extends AbstractCommandExecutor { public CommandExecutorMatchResult match(RequirementsResult results) { Object[] objects = new Object[method.getParameterCount()]; - for (int parameterIndex = 0; parameterIndex < method.getParameterCount(); parameterIndex++) { - Requirement requirement = definition.getRequirement(parameterIndex); + int parameterIndex = 0; + for (Requirement requirement : definition.getRequirements()) { String name = requirement.getName(); - if (!results.has(name)) { + RequirementMatch requirementMatch = results.get(name); + + if (requirementMatch == null) { return CommandExecutorMatchResult.failed(new IllegalStateException("Not all parameters are resolved, missing " + name)); } - RequirementMatch requirementMatch = results.get(name); Object unwrapped = requirementMatch.getResult().unwrap(); - Parameter parameter = method.getParameters()[parameterIndex]; + Parameter parameter = parameters[parameterIndex]; Class type = parameter.getType(); if (unwrapped == null && type.isPrimitive()) { @@ -71,6 +75,7 @@ public CommandExecutorMatchResult match(RequirementsResult results) { } objects[parameterIndex] = unwrapped; + parameterIndex++; } ValidatorResult result = validatorService.validate(new MethodValidatorContext<>(results, definition, instance, method, objects)); @@ -79,23 +84,31 @@ public CommandExecutorMatchResult match(RequirementsResult results) { return CommandExecutorMatchResult.failed(result.getInvalidResult()); } - return CommandExecutorMatchResult.success(() -> { + return CommandExecutorMatchResult.success(new FinalCommandExecutor(objects)); + } + + private class FinalCommandExecutor implements Supplier { + private final Object[] objects; + + public FinalCommandExecutor(Object[] objects) { + this.objects = objects; + } + + @Override + public CommandExecuteResult get() { try { - return CommandExecuteResult.success(this, this.method.invoke(this.instance, objects)); - } - catch (IllegalAccessException exception) { - throw new LiteCommandsReflectInvocationException(this.method, "Cannot access method", exception); - } - catch (InvocationTargetException exception) { + return CommandExecuteResult.success(MethodCommandExecutor.this, MethodCommandExecutor.this.method.invoke(MethodCommandExecutor.this.instance, objects)); + } catch (IllegalAccessException exception) { + throw new LiteCommandsReflectInvocationException(MethodCommandExecutor.this.method, "Cannot access method", exception); + } catch (InvocationTargetException exception) { Throwable targetException = exception.getTargetException(); if (targetException instanceof InvalidUsageException) { //TODO: Use invalid usage handler (when InvalidUsage.Cause is mapped to InvalidUsage) - return CommandExecuteResult.failed(this, ((InvalidUsageException) targetException).getErrorResult()); + return CommandExecuteResult.failed(MethodCommandExecutor.this, ((InvalidUsageException) targetException).getErrorResult()); } - throw new LiteCommandsReflectInvocationException(this.method, "Command method threw " + targetException.getClass().getSimpleName(), targetException); + throw new LiteCommandsReflectInvocationException(MethodCommandExecutor.this.method, "Command method threw " + targetException.getClass().getSimpleName(), targetException); } - }); + } } - } diff --git a/litecommands-annotations/src/dev/rollczi/litecommands/annotations/MethodDefinition.java b/litecommands-annotations/src/dev/rollczi/litecommands/annotations/MethodDefinition.java index ebccf066b..d8d771431 100644 --- a/litecommands-annotations/src/dev/rollczi/litecommands/annotations/MethodDefinition.java +++ b/litecommands-annotations/src/dev/rollczi/litecommands/annotations/MethodDefinition.java @@ -9,8 +9,10 @@ import java.lang.reflect.Method; import java.lang.reflect.Parameter; +import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; +import java.util.List; import java.util.Map; public class MethodDefinition { @@ -20,11 +22,32 @@ public class MethodDefinition { private final Map> contextRequirements = new HashMap<>(); private final Map> bindRequirements = new HashMap<>(); + private List> indexedRequirements; + MethodDefinition(Method method) { this.method = method; } public Requirement getRequirement(int parameterIndex) { + return getRequirements().get(parameterIndex); + } + + public List> getRequirements() { + if (indexedRequirements == null) { + List> indexedRequirements = new ArrayList<>(); + + for (int i = 0; i < method.getParameterCount(); i++) { + indexedRequirements.add(getRequirement0(i)); + } + + this.indexedRequirements = indexedRequirements; + return indexedRequirements; + } + + return indexedRequirements; + } + + private Requirement getRequirement0(int parameterIndex) { Argument argument = arguments.get(parameterIndex); if (argument != null) { diff --git a/litecommands-annotations/test/dev/rollczi/litecommands/annotations/async/AsyncCommandTest.java b/litecommands-annotations/test/dev/rollczi/litecommands/annotations/async/AsyncCommandTest.java index 9db872415..ee5f88708 100644 --- a/litecommands-annotations/test/dev/rollczi/litecommands/annotations/async/AsyncCommandTest.java +++ b/litecommands-annotations/test/dev/rollczi/litecommands/annotations/async/AsyncCommandTest.java @@ -14,6 +14,7 @@ import dev.rollczi.litecommands.scheduler.SchedulerExecutorPoolImpl; import dev.rollczi.litecommands.unit.AssertExecute; import dev.rollczi.litecommands.unit.TestSender; +import static org.assertj.core.api.AssertionsForClassTypes.assertThat; import org.junit.jupiter.api.Test; import java.util.Date; @@ -24,11 +25,14 @@ class AsyncCommandTest extends LiteTestSpec { + private static final int DELAY = 500; + private static final int MARGIN = 200; + static LiteConfig config = builder -> builder .scheduler(new SchedulerExecutorPoolImpl("test", 1)) .context(Date.class, invocation -> ContextResult.ok(() -> { try { - Thread.sleep(800); + Thread.sleep(DELAY); } catch (InterruptedException e) { throw new RuntimeException(e); } @@ -104,7 +108,8 @@ void testAsyncArgs() { CompletableFuture result = platform.executeAsync("test async-args first second"); await() - .atLeast(300, TimeUnit.MILLISECONDS) + .atLeast(DELAY - MARGIN, TimeUnit.MILLISECONDS) + .atMost(DELAY + MARGIN, TimeUnit.MILLISECONDS) .until(() -> result.isDone()); result.join() @@ -116,7 +121,8 @@ void testAsyncArgsAndMethod() { CompletableFuture result = platform.executeAsync("test async-args-and-method first second"); await() - .atLeast(300, TimeUnit.MILLISECONDS) + .atLeast(DELAY - MARGIN, TimeUnit.MILLISECONDS) + .atMost(DELAY + MARGIN, TimeUnit.MILLISECONDS) .until(() -> result.isDone()); result.join() diff --git a/litecommands-annotations/test/dev/rollczi/litecommands/annotations/async/ParallelAsyncCommandTest.java b/litecommands-annotations/test/dev/rollczi/litecommands/annotations/async/ParallelAsyncCommandTest.java new file mode 100644 index 000000000..be672724b --- /dev/null +++ b/litecommands-annotations/test/dev/rollczi/litecommands/annotations/async/ParallelAsyncCommandTest.java @@ -0,0 +1,79 @@ +package dev.rollczi.litecommands.annotations.async; + +import dev.rollczi.litecommands.annotations.LiteConfig; +import dev.rollczi.litecommands.annotations.LiteTestSpec; +import dev.rollczi.litecommands.annotations.argument.Arg; +import dev.rollczi.litecommands.annotations.command.Command; +import dev.rollczi.litecommands.annotations.context.Context; +import dev.rollczi.litecommands.annotations.execute.Execute; +import dev.rollczi.litecommands.argument.Argument; +import dev.rollczi.litecommands.argument.parser.ParseResult; +import dev.rollczi.litecommands.argument.resolver.ArgumentResolver; +import dev.rollczi.litecommands.context.ContextResult; +import dev.rollczi.litecommands.invocation.Invocation; +import dev.rollczi.litecommands.scheduler.SchedulerExecutorPoolImpl; +import dev.rollczi.litecommands.unit.AssertExecute; +import dev.rollczi.litecommands.unit.TestSender; +import java.util.ArrayList; +import java.util.Date; +import java.util.List; +import java.util.concurrent.CompletableFuture; +import org.junit.jupiter.api.Test; + +public class ParallelAsyncCommandTest extends LiteTestSpec { + + private static final int DELAY = 100; + + static LiteConfig config = builder -> builder + .scheduler(new SchedulerExecutorPoolImpl("test", 50)) + .context(Date.class, invocation -> ContextResult.ok(() -> { + try { + Thread.sleep(DELAY); + } catch (InterruptedException e) { + throw new RuntimeException(e); + } + + return new Date(); + })) + .argumentParser(String.class, new StringArgumentResolver()); + + static class StringArgumentResolver extends ArgumentResolver { + @Override + protected ParseResult parse(Invocation invocation, Argument context, String argument) { + try { + Thread.sleep(DELAY); + } catch (InterruptedException e) { + throw new RuntimeException(e); + } + + return ParseResult.success(argument); + } + } + + @Command(name = "async") + static class TestCommand { + + @Async + @Execute + public String testAsyncArgs2(@Async @Context Date date, @Async @Arg String first, @Async @Arg String second) { + return first + " " + second; + } + + } + + @Test + void testAsyncArgsAndMethod() { + List> results = new ArrayList<>(); + + for (int i = 0; i < 500; i++) { + results.add(platform.executeAsync("async first second")); + } + + for (CompletableFuture result : results) { + result.join() + .assertSuccess("first second"); + } + } + + +} diff --git a/litecommands-chatgpt/src/dev/rollczi/litecommands/chatgpt/ChatGptStringSuggester.java b/litecommands-chatgpt/src/dev/rollczi/litecommands/chatgpt/ChatGptStringSuggester.java index 5862c165d..8e7635f7e 100644 --- a/litecommands-chatgpt/src/dev/rollczi/litecommands/chatgpt/ChatGptStringSuggester.java +++ b/litecommands-chatgpt/src/dev/rollczi/litecommands/chatgpt/ChatGptStringSuggester.java @@ -7,7 +7,6 @@ import dev.rollczi.litecommands.argument.suggester.Suggester; import dev.rollczi.litecommands.identifier.Identifier; import dev.rollczi.litecommands.input.raw.RawCommand; -import dev.rollczi.litecommands.input.raw.RawInput; import dev.rollczi.litecommands.invocation.Invocation; import dev.rollczi.litecommands.join.JoinStringArgumentResolver; import dev.rollczi.litecommands.scheduler.Scheduler; @@ -16,7 +15,6 @@ import dev.rollczi.litecommands.suggestion.SuggestionContext; import dev.rollczi.litecommands.suggestion.SuggestionResult; -import java.time.Instant; import java.time.temporal.ChronoUnit; import java.util.Collection; import java.util.HashMap; @@ -29,9 +27,8 @@ import java.util.concurrent.ExecutionException; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; -import java.util.logging.Logger; -class ChatGptStringSuggester extends JoinStringArgumentResolver implements Suggester, ArgumentResolverBase { +class ChatGptStringSuggester extends JoinStringArgumentResolver implements Suggester, ArgumentResolverBase { private final Scheduler scheduler; private final ChatGptClient chatGptClient; diff --git a/litecommands-core/src/dev/rollczi/litecommands/argument/SimpleArgument.java b/litecommands-core/src/dev/rollczi/litecommands/argument/SimpleArgument.java index 665df65f1..36b9cf1a6 100644 --- a/litecommands-core/src/dev/rollczi/litecommands/argument/SimpleArgument.java +++ b/litecommands-core/src/dev/rollczi/litecommands/argument/SimpleArgument.java @@ -14,6 +14,9 @@ public class SimpleArgument implements Argument { private final WrapFormat wrapperFormat; private final Meta meta = Meta.create(); private final boolean nullable; + // cache last argument + private String lastKeyName; + private ArgumentKey lastKey; public SimpleArgument(String name, WrapFormat wrapperFormat, boolean nullable) { this.name = name; @@ -32,6 +35,17 @@ public String getName() { return name; } + @Override + public ArgumentKey getKey() { + String keyName = this.getKeyName(); + if (lastKeyName == null || !lastKeyName.equals(keyName)) { + lastKey = Argument.super.getKey(); + lastKeyName = keyName; + } + + return lastKey; + } + @Override public WrapFormat getWrapperFormat() { return this.wrapperFormat; diff --git a/litecommands-core/src/dev/rollczi/litecommands/argument/parser/EmptyParserSetImpl.java b/litecommands-core/src/dev/rollczi/litecommands/argument/parser/EmptyParserSetImpl.java index d0b5a6b14..23f1970b2 100644 --- a/litecommands-core/src/dev/rollczi/litecommands/argument/parser/EmptyParserSetImpl.java +++ b/litecommands-core/src/dev/rollczi/litecommands/argument/parser/EmptyParserSetImpl.java @@ -7,7 +7,7 @@ class EmptyParserSetImpl implements ParserSet { @Override - public @Nullable Parser getValidParser(Class input, Invocation invocation, Argument argument) { + public @Nullable Parser getValidParser(Invocation invocation, Argument argument) { return null; } diff --git a/litecommands-core/src/dev/rollczi/litecommands/argument/parser/MergedParserSetImpl.java b/litecommands-core/src/dev/rollczi/litecommands/argument/parser/MergedParserSetImpl.java index f0a6025c7..e2a4aca75 100644 --- a/litecommands-core/src/dev/rollczi/litecommands/argument/parser/MergedParserSetImpl.java +++ b/litecommands-core/src/dev/rollczi/litecommands/argument/parser/MergedParserSetImpl.java @@ -2,30 +2,26 @@ import dev.rollczi.litecommands.argument.Argument; import dev.rollczi.litecommands.invocation.Invocation; -import dev.rollczi.litecommands.shared.IterableReferences; -import java.util.List; import org.jetbrains.annotations.Nullable; class MergedParserSetImpl implements ParserSet { - private final Iterable.BucketByArgument> bucketByArguments; + private final Iterable> parserSets; - public MergedParserSetImpl(Iterable.BucketByArgument> bucketByArguments) { - this.bucketByArguments = bucketByArguments; + public MergedParserSetImpl(Iterable> parserSets) { + this.parserSets = parserSets; } @Override - public @Nullable Parser getValidParser(Class input, Invocation invocation, Argument argument) { - for (ParserRegistryImpl.BucketByArgument bucketByArgument : bucketByArguments) { - ParserRegistryImpl.BucketByArgument bucket = (ParserRegistryImpl.BucketByArgument) bucketByArgument; - ParserSet parserSet = bucket.getParserSet(argument.getKey()); + public @Nullable Parser getValidParser(Invocation invocation, Argument argument) { + for (ParserSet parserSet : parserSets) { if (parserSet == null) { continue; } - Parser validParser = parserSet.getValidParser(input, invocation, argument); + Parser validParser = parserSet.getValidParser(invocation, argument); if (validParser != null) { return validParser; diff --git a/litecommands-core/src/dev/rollczi/litecommands/argument/parser/ParseResult.java b/litecommands-core/src/dev/rollczi/litecommands/argument/parser/ParseResult.java index e41d1e86a..85b5bf7a8 100644 --- a/litecommands-core/src/dev/rollczi/litecommands/argument/parser/ParseResult.java +++ b/litecommands-core/src/dev/rollczi/litecommands/argument/parser/ParseResult.java @@ -9,6 +9,8 @@ public class ParseResult implements RequirementResult { + private static final ParseResult NULL_SUCCESS = new ParseResult<>(null, null, true); + private final @Nullable EXPECTED successfulResult; private final @Nullable FailedReason failedResult; private final boolean nullable; @@ -64,8 +66,9 @@ public static ParseResult success(PARSED parsed) { return new ParseResult<>(parsed, null, false); } + @SuppressWarnings("unchecked") public static ParseResult successNull() { - return new ParseResult<>(null, null, true); + return (ParseResult) NULL_SUCCESS; } public static ParseResult failure(FailedReason failedReason) { diff --git a/litecommands-core/src/dev/rollczi/litecommands/argument/parser/Parser.java b/litecommands-core/src/dev/rollczi/litecommands/argument/parser/Parser.java index 87b5e3997..c37f2ec2c 100644 --- a/litecommands-core/src/dev/rollczi/litecommands/argument/parser/Parser.java +++ b/litecommands-core/src/dev/rollczi/litecommands/argument/parser/Parser.java @@ -1,17 +1,16 @@ package dev.rollczi.litecommands.argument.parser; import dev.rollczi.litecommands.argument.Argument; +import dev.rollczi.litecommands.input.raw.RawInput; import dev.rollczi.litecommands.invocation.Invocation; import dev.rollczi.litecommands.range.Rangeable; -public interface Parser extends Rangeable> { +public interface Parser extends Rangeable> { - ParseResult parse(Invocation invocation, Argument argument, INPUT input); + ParseResult parse(Invocation invocation, Argument argument, RawInput input); - default boolean canParse(Invocation invocation, Argument argument, Class inputType) { + default boolean canParse(Invocation invocation, Argument argument) { return true; } - Class getInputType(); - } diff --git a/litecommands-core/src/dev/rollczi/litecommands/argument/parser/ParserRegistry.java b/litecommands-core/src/dev/rollczi/litecommands/argument/parser/ParserRegistry.java index 329d3cf63..f963676b6 100644 --- a/litecommands-core/src/dev/rollczi/litecommands/argument/parser/ParserRegistry.java +++ b/litecommands-core/src/dev/rollczi/litecommands/argument/parser/ParserRegistry.java @@ -6,11 +6,11 @@ public interface ParserRegistry { @Deprecated - default void registerParser(Class parserType, ArgumentKey key, Parser parser) { + default void registerParser(Class parserType, ArgumentKey key, Parser parser) { registerParser(TypeRange.downwards(parserType), key, parser); } - void registerParser(TypeRange typeRange, ArgumentKey key, Parser parser); + void registerParser(TypeRange typeRange, ArgumentKey key, Parser parser); ParserSet getParserSet(Class parsedClass, ArgumentKey key); diff --git a/litecommands-core/src/dev/rollczi/litecommands/argument/parser/ParserRegistryImpl.java b/litecommands-core/src/dev/rollczi/litecommands/argument/parser/ParserRegistryImpl.java index b852fa7bb..e124436d7 100644 --- a/litecommands-core/src/dev/rollczi/litecommands/argument/parser/ParserRegistryImpl.java +++ b/litecommands-core/src/dev/rollczi/litecommands/argument/parser/ParserRegistryImpl.java @@ -6,6 +6,7 @@ import dev.rollczi.litecommands.shared.BiMap; import dev.rollczi.litecommands.reflect.type.TypeIndex; import dev.rollczi.litecommands.util.StringUtil; +import java.util.ArrayList; import java.util.List; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -16,8 +17,7 @@ public class ParserRegistryImpl implements ParserRegistry { @Override @SuppressWarnings("unchecked") - @NotNull - public void registerParser(TypeRange typeRange, ArgumentKey key, Parser parser) { + public void registerParser(TypeRange typeRange, ArgumentKey key, Parser parser) { List> arguments = buckets.computeIfAbsent(typeRange, () -> new BucketByArgument<>()); for (BucketByArgument argument : arguments) { @@ -27,10 +27,20 @@ public void registerParser(TypeRange typeRange, ArgumentKey key } @Override - @SuppressWarnings("unchecked") @NotNull public ParserSet getParserSet(Class parserType, ArgumentKey key) { - return new MergedParserSetImpl<>(buckets.get(parserType)); + List> parserSets = new ArrayList<>(); + + for (BucketByArgument argument : buckets.get(parserType)) { + BucketByArgument bucket = (BucketByArgument) argument; + ParserSet parserSet = bucket.getParserSet(key); + + if (parserSet != null) { + parserSets.add(parserSet); + } + } + + return new MergedParserSetImpl<>(parserSets); } class BucketByArgument extends BucketByArgumentUniversal { @@ -42,7 +52,7 @@ private BucketByArgument() { } @Override - void registerParser(TypeRange parsedType, ArgumentKey key, Parser parser) { + void registerParser(TypeRange parsedType, ArgumentKey key, Parser parser) { if (key.isUniversal()) { this.universalTypedBucket.registerParser(parsedType, key, parser); return; @@ -80,7 +90,7 @@ private BucketByArgumentUniversal(boolean ignoreNamespace) { this.ignoreNamespace = ignoreNamespace; } - void registerParser(TypeRange parsedType, ArgumentKey key, Parser parser) { + void registerParser(TypeRange parsedType, ArgumentKey key, Parser parser) { ParserSetImpl bucket = buckets.computeIfAbsent(key.getKey(), key.getNamespace(), (k1, k2) -> new ParserSetImpl<>()); bucket.registerParser(parser); diff --git a/litecommands-core/src/dev/rollczi/litecommands/argument/parser/ParserSet.java b/litecommands-core/src/dev/rollczi/litecommands/argument/parser/ParserSet.java index a4dbdffca..b30680474 100644 --- a/litecommands-core/src/dev/rollczi/litecommands/argument/parser/ParserSet.java +++ b/litecommands-core/src/dev/rollczi/litecommands/argument/parser/ParserSet.java @@ -2,18 +2,15 @@ import dev.rollczi.litecommands.argument.Argument; import dev.rollczi.litecommands.invocation.Invocation; -import dev.rollczi.litecommands.reflect.type.TypeRange; -import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.Nullable; public interface ParserSet { - default Parser getValidParserOrThrow( - Class input, + default Parser getValidParserOrThrow( Invocation invocation, Argument argument ) { - Parser parser = this.getValidParser(input, invocation, argument); + Parser parser = this.getValidParser(invocation, argument); if (parser == null) { String simpleName = argument.getWrapperFormat().parsedType().getRawType().getSimpleName(); @@ -24,10 +21,10 @@ default Parser getValidParserOrThrow( } @Nullable - Parser - getValidParser(Class input, Invocation invocation, Argument argument); + Parser + getValidParser(Invocation invocation, Argument argument); - static ParserSet of(Parser parser) { + static ParserSet of(Parser parser) { ParserSetImpl parserSet = new ParserSetImpl<>(); parserSet.registerParser(parser); diff --git a/litecommands-core/src/dev/rollczi/litecommands/argument/parser/ParserSetImpl.java b/litecommands-core/src/dev/rollczi/litecommands/argument/parser/ParserSetImpl.java index b4a125ed5..fc5647fbc 100644 --- a/litecommands-core/src/dev/rollczi/litecommands/argument/parser/ParserSetImpl.java +++ b/litecommands-core/src/dev/rollczi/litecommands/argument/parser/ParserSetImpl.java @@ -2,36 +2,31 @@ import dev.rollczi.litecommands.argument.Argument; import dev.rollczi.litecommands.invocation.Invocation; -import dev.rollczi.litecommands.reflect.type.TypeIndex; -import dev.rollczi.litecommands.reflect.type.TypeRange; +import java.util.LinkedList; import org.jetbrains.annotations.Nullable; class ParserSetImpl implements ParserSet { - private final TypeIndex> parsers = new TypeIndex<>(); + private final LinkedList> parsers = new LinkedList<>(); @Override - @SuppressWarnings("unchecked") @Nullable - public Parser getValidParser( - Class input, + public Parser getValidParser( Invocation invocation, Argument argument ) { - for (Parser parser : this.parsers.get(input)) { - Parser castedParser = (Parser) parser; - - if (castedParser.canParse(invocation, argument, input)) { - return castedParser; + for (Parser parser : parsers) { + if (parser.canParse(invocation, argument)) { + return parser; } } return null; } - void registerParser(Parser parser) { - parsers.put(TypeRange.upwards(parser.getInputType()), parser); + void registerParser(Parser parser) { + parsers.addFirst(parser); } } diff --git a/litecommands-core/src/dev/rollczi/litecommands/argument/parser/RawInputParser.java b/litecommands-core/src/dev/rollczi/litecommands/argument/parser/RawInputParser.java deleted file mode 100644 index e51fad47a..000000000 --- a/litecommands-core/src/dev/rollczi/litecommands/argument/parser/RawInputParser.java +++ /dev/null @@ -1,11 +0,0 @@ -package dev.rollczi.litecommands.argument.parser; - -import dev.rollczi.litecommands.input.raw.RawInput; - -public interface RawInputParser extends Parser { - - default Class getInputType() { - return RawInput.class; - } - -} diff --git a/litecommands-core/src/dev/rollczi/litecommands/argument/parser/TypedParser.java b/litecommands-core/src/dev/rollczi/litecommands/argument/parser/TypedParser.java index 6c0e8c5a7..a1f9fc5de 100644 --- a/litecommands-core/src/dev/rollczi/litecommands/argument/parser/TypedParser.java +++ b/litecommands-core/src/dev/rollczi/litecommands/argument/parser/TypedParser.java @@ -1,13 +1,14 @@ package dev.rollczi.litecommands.argument.parser; import dev.rollczi.litecommands.argument.Argument; +import dev.rollczi.litecommands.input.raw.RawInput; import dev.rollczi.litecommands.invocation.Invocation; import dev.rollczi.litecommands.range.Range; @SuppressWarnings("rawtypes") -public interface TypedParser> extends Parser { +public interface TypedParser> extends Parser { - ParseResult parseTyped(Invocation invocation, ARGUMENT argument, INPUT input); + ParseResult parseTyped(Invocation invocation, ARGUMENT argument, RawInput input); Range getTypedRange(ARGUMENT argument); @@ -15,7 +16,7 @@ public interface TypedParser parse(Invocation invocation, Argument argument, INPUT input) { + default ParseResult parse(Invocation invocation, Argument argument, RawInput input) { return parseTyped(invocation, (ARGUMENT) argument, input); } diff --git a/litecommands-core/src/dev/rollczi/litecommands/argument/parser/input/NamedParseableInput.java b/litecommands-core/src/dev/rollczi/litecommands/argument/parser/input/NamedParseableInput.java index 8185ceaee..1d77c3865 100644 --- a/litecommands-core/src/dev/rollczi/litecommands/argument/parser/input/NamedParseableInput.java +++ b/litecommands-core/src/dev/rollczi/litecommands/argument/parser/input/NamedParseableInput.java @@ -4,6 +4,8 @@ import dev.rollczi.litecommands.argument.parser.ParseResult; import dev.rollczi.litecommands.argument.parser.Parser; import dev.rollczi.litecommands.argument.parser.ParserSet; +import dev.rollczi.litecommands.input.raw.RawCommand; +import dev.rollczi.litecommands.input.raw.RawInput; import dev.rollczi.litecommands.invalidusage.InvalidUsage; import dev.rollczi.litecommands.invocation.Invocation; @@ -61,15 +63,10 @@ public ParseResult nextArgument(Invocation invo } consumedArguments.add(argument.getName()); - return this.parseInput(invocation, argument, parserSet, input); - } - @SuppressWarnings("unchecked") - private ParseResult parseInput(Invocation invocation, Argument argument, ParserSet parserSet, INPUT input) { - Class inputType = (Class) input.getClass(); - Parser parser = parserSet.getValidParserOrThrow(inputType, invocation, argument); + Parser parser = parserSet.getValidParserOrThrow(invocation, argument); - return parser.parse(invocation, argument, input); + return parser.parse(invocation, argument, RawInput.of(input.split(RawCommand.COMMAND_SEPARATOR))); } @Override diff --git a/litecommands-core/src/dev/rollczi/litecommands/argument/parser/input/NamedTypedParseableInput.java b/litecommands-core/src/dev/rollczi/litecommands/argument/parser/input/NamedTypedParseableInput.java index ac062f7bb..484d8f9c0 100644 --- a/litecommands-core/src/dev/rollczi/litecommands/argument/parser/input/NamedTypedParseableInput.java +++ b/litecommands-core/src/dev/rollczi/litecommands/argument/parser/input/NamedTypedParseableInput.java @@ -4,6 +4,8 @@ import dev.rollczi.litecommands.argument.parser.ParseResult; import dev.rollczi.litecommands.argument.parser.Parser; import dev.rollczi.litecommands.argument.parser.ParserSet; +import dev.rollczi.litecommands.input.raw.RawCommand; +import dev.rollczi.litecommands.input.raw.RawInput; import dev.rollczi.litecommands.invalidusage.InvalidUsage; import dev.rollczi.litecommands.invocation.Invocation; @@ -69,15 +71,10 @@ public ParseResult nextArgument(Invocation invo return ParseResult.success((PARSED) input); } - return this.parseInput(invocation, argument, parserSet, input); - } - - @SuppressWarnings("unchecked") - private ParseResult parseInput(Invocation invocation, Argument argument, ParserSet parserSet, INPUT input) { - Class inputType = (Class) input.getClass(); - Parser parser = parserSet.getValidParserOrThrow(inputType, invocation, argument); + Parser parser = parserSet.getValidParserOrThrow(invocation, argument); + RawInput rawInput = RawInput.of(input.toString().split(RawCommand.COMMAND_SEPARATOR)); - return parser.parse(invocation, argument, input); + return parser.parse(invocation, argument, rawInput); } @Override diff --git a/litecommands-core/src/dev/rollczi/litecommands/argument/resolver/ArgumentResolverBase.java b/litecommands-core/src/dev/rollczi/litecommands/argument/resolver/ArgumentResolverBase.java index b547b07c4..776dd75b2 100644 --- a/litecommands-core/src/dev/rollczi/litecommands/argument/resolver/ArgumentResolverBase.java +++ b/litecommands-core/src/dev/rollczi/litecommands/argument/resolver/ArgumentResolverBase.java @@ -3,5 +3,5 @@ import dev.rollczi.litecommands.argument.parser.Parser; import dev.rollczi.litecommands.argument.suggester.Suggester; -public interface ArgumentResolverBase extends Suggester, Parser { +public interface ArgumentResolverBase extends Suggester, Parser { } diff --git a/litecommands-core/src/dev/rollczi/litecommands/argument/resolver/MultipleArgumentResolver.java b/litecommands-core/src/dev/rollczi/litecommands/argument/resolver/MultipleArgumentResolver.java index aa8ee567e..1b4d1dcbf 100644 --- a/litecommands-core/src/dev/rollczi/litecommands/argument/resolver/MultipleArgumentResolver.java +++ b/litecommands-core/src/dev/rollczi/litecommands/argument/resolver/MultipleArgumentResolver.java @@ -1,17 +1,16 @@ package dev.rollczi.litecommands.argument.resolver; import dev.rollczi.litecommands.argument.Argument; -import dev.rollczi.litecommands.argument.parser.RawInputParser; -import dev.rollczi.litecommands.input.raw.RawInput; +import dev.rollczi.litecommands.argument.parser.Parser; import dev.rollczi.litecommands.invocation.Invocation; import dev.rollczi.litecommands.argument.suggester.Suggester; import dev.rollczi.litecommands.suggestion.SuggestionContext; import dev.rollczi.litecommands.suggestion.SuggestionResult; public interface MultipleArgumentResolver extends - ArgumentResolverBase, + ArgumentResolverBase, Suggester, - RawInputParser { + Parser { @Override default SuggestionResult suggest(Invocation invocation, Argument argument, SuggestionContext context) { diff --git a/litecommands-core/src/dev/rollczi/litecommands/argument/resolver/TypedArgumentResolver.java b/litecommands-core/src/dev/rollczi/litecommands/argument/resolver/TypedArgumentResolver.java index a1e35162c..e089e6d26 100644 --- a/litecommands-core/src/dev/rollczi/litecommands/argument/resolver/TypedArgumentResolver.java +++ b/litecommands-core/src/dev/rollczi/litecommands/argument/resolver/TypedArgumentResolver.java @@ -1,14 +1,13 @@ package dev.rollczi.litecommands.argument.resolver; import dev.rollczi.litecommands.argument.Argument; -import dev.rollczi.litecommands.input.raw.RawInput; import dev.rollczi.litecommands.argument.parser.TypedParser; import dev.rollczi.litecommands.argument.suggester.TypedSuggester; @SuppressWarnings("rawtypes") public abstract class TypedArgumentResolver> implements - ArgumentResolverBase, - TypedParser, + ArgumentResolverBase, + TypedParser, TypedSuggester { @@ -23,9 +22,4 @@ public Class getArgumentType() { return argumentType; } - @Override - public Class getInputType() { - return RawInput.class; - } - } diff --git a/litecommands-core/src/dev/rollczi/litecommands/argument/resolver/collector/AbstractCollectorArgumentResolver.java b/litecommands-core/src/dev/rollczi/litecommands/argument/resolver/collector/AbstractCollectorArgumentResolver.java index 6055409a3..512d11edc 100644 --- a/litecommands-core/src/dev/rollczi/litecommands/argument/resolver/collector/AbstractCollectorArgumentResolver.java +++ b/litecommands-core/src/dev/rollczi/litecommands/argument/resolver/collector/AbstractCollectorArgumentResolver.java @@ -42,7 +42,7 @@ private ParseResult parse(Class componentType, RawInput rawInput, Argument argument = new SimpleArgument<>(collectorArgument.getKeyName(), WrapFormat.notWrapped(componentType)); ParserSet parserSet = parserRegistry.getParserSet(componentType, argument.getKey()); - Parser parser = parserSet.getValidParserOrThrow(RawInput.class, invocation, argument); + Parser parser = parserSet.getValidParserOrThrow(invocation, argument); List values = new ArrayList<>(); @@ -85,7 +85,7 @@ private SuggestionResult suggest(Class componentType, SuggestionContext c Argument argument = new SimpleArgument<>(collectorArgument.getKeyName(), WrapFormat.notWrapped(componentType)); ParserSet parserSet = parserRegistry.getParserSet(componentType, argument.getKey()); - Parser parser = parserSet.getValidParserOrThrow(RawInput.class, invocation, argument); + Parser parser = parserSet.getValidParserOrThrow(invocation, argument); Suggester suggester = suggesterRegistry.getSuggester(componentType, argument.getKey()); diff --git a/litecommands-core/src/dev/rollczi/litecommands/argument/resolver/collector/ArrayArgumentResolver.java b/litecommands-core/src/dev/rollczi/litecommands/argument/resolver/collector/ArrayArgumentResolver.java index 59f2022a6..eb6447137 100644 --- a/litecommands-core/src/dev/rollczi/litecommands/argument/resolver/collector/ArrayArgumentResolver.java +++ b/litecommands-core/src/dev/rollczi/litecommands/argument/resolver/collector/ArrayArgumentResolver.java @@ -3,7 +3,6 @@ import dev.rollczi.litecommands.argument.Argument; import dev.rollczi.litecommands.argument.parser.ParserRegistry; import dev.rollczi.litecommands.argument.suggester.SuggesterRegistry; -import dev.rollczi.litecommands.input.raw.RawInput; import dev.rollczi.litecommands.invocation.Invocation; import java.lang.reflect.Array; import java.util.ArrayList; @@ -44,7 +43,7 @@ protected Class getElementType(CollectorArgument context, Invoca } @Override - public boolean canParse(Invocation invocation, Argument argument, Class inputType) { + public boolean canParse(Invocation invocation, Argument argument) { return argument.getWrapperFormat().getParsedType().isArray(); } diff --git a/litecommands-core/src/dev/rollczi/litecommands/command/executor/CommandExecuteService.java b/litecommands-core/src/dev/rollczi/litecommands/command/executor/CommandExecuteService.java index c962771b0..072b1c230 100644 --- a/litecommands-core/src/dev/rollczi/litecommands/command/executor/CommandExecuteService.java +++ b/litecommands-core/src/dev/rollczi/litecommands/command/executor/CommandExecuteService.java @@ -1,21 +1,14 @@ package dev.rollczi.litecommands.command.executor; -import dev.rollczi.litecommands.argument.Argument; -import dev.rollczi.litecommands.argument.parser.ParseResult; import dev.rollczi.litecommands.argument.parser.ParserRegistry; -import dev.rollczi.litecommands.argument.parser.ParserSet; import dev.rollczi.litecommands.argument.parser.input.ParseableInputMatcher; import dev.rollczi.litecommands.bind.BindRegistry; import dev.rollczi.litecommands.command.CommandRoute; import dev.rollczi.litecommands.context.ContextRegistry; -import dev.rollczi.litecommands.requirement.BindRequirement; -import dev.rollczi.litecommands.requirement.ContextRequirement; import dev.rollczi.litecommands.requirement.Requirement; -import dev.rollczi.litecommands.requirement.RequirementResult; import dev.rollczi.litecommands.requirement.RequirementsResult; import dev.rollczi.litecommands.handler.result.ResultHandleService; import dev.rollczi.litecommands.invalidusage.InvalidUsage.Cause; -import dev.rollczi.litecommands.scheduler.ScheduledChainException; import dev.rollczi.litecommands.schematic.Schematic; import dev.rollczi.litecommands.schematic.SchematicGenerator; import dev.rollczi.litecommands.schematic.SchematicInput; @@ -25,8 +18,6 @@ import dev.rollczi.litecommands.invalidusage.InvalidUsage; import dev.rollczi.litecommands.invocation.Invocation; import dev.rollczi.litecommands.meta.Meta; -import dev.rollczi.litecommands.scheduler.ScheduledChain; -import dev.rollczi.litecommands.scheduler.ScheduledChainLink; import dev.rollczi.litecommands.scheduler.Scheduler; import dev.rollczi.litecommands.scheduler.SchedulerPoll; import dev.rollczi.litecommands.validator.ValidatorResult; @@ -36,14 +27,14 @@ import dev.rollczi.litecommands.wrapper.WrapFormat; import dev.rollczi.litecommands.wrapper.Wrapper; import dev.rollczi.litecommands.wrapper.WrapperRegistry; +import java.util.ArrayList; +import java.util.Iterator; import org.jetbrains.annotations.Nullable; -import panda.std.Result; import java.util.List; import java.util.ListIterator; import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletionException; -import java.util.function.Supplier; import static java.util.concurrent.CompletableFuture.completedFuture; @@ -53,20 +44,16 @@ public class CommandExecuteService { private final ResultHandleService resultResolver; private final Scheduler scheduler; private final SchematicGenerator schematicGenerator; - private final ParserRegistry parserRegistry; - private final ContextRegistry contextRegistry; + private final ScheduledRequirementResolver scheduledRequirementResolver; private final WrapperRegistry wrapperRegistry; - private final BindRegistry bindRegistry; public CommandExecuteService(ValidatorService validatorService, ResultHandleService resultResolver, Scheduler scheduler, SchematicGenerator schematicGenerator, ParserRegistry parserRegistry, ContextRegistry contextRegistry, WrapperRegistry wrapperRegistry, BindRegistry bindRegistry) { this.validatorService = validatorService; this.resultResolver = resultResolver; this.scheduler = scheduler; this.schematicGenerator = schematicGenerator; - this.parserRegistry = parserRegistry; - this.contextRegistry = contextRegistry; this.wrapperRegistry = wrapperRegistry; - this.bindRegistry = bindRegistry; + this.scheduledRequirementResolver = new ScheduledRequirementResolver<>(contextRegistry, parserRegistry, bindRegistry, scheduler); } public CompletableFuture execute(Invocation invocation, ParseableInputMatcher matcher, CommandRoute commandRoute) { @@ -203,86 +190,80 @@ private CommandExecuteResult toThrown(CommandExecutor executor, Throwabl return CommandExecuteResult.thrown(executor, throwable); } - // TODO: Refactor this method :/ (and all methods in this class) private > CompletableFuture match( CommandExecutor executor, Invocation invocation, MATCHER matcher ) { - ScheduledChain.Builder, RequirementResult> builder = ScheduledChain.builder(); + List> scheduledRequirements = scheduledRequirementResolver.prepareRequirements(executor, invocation, matcher); + return match(invocation, executor, new ArrayList<>(), scheduledRequirements.listIterator(), matcher); + } - for (Argument argument : executor.getArguments()) { - builder.link(new ScheduledRequirement<>(argument, () -> matchArgument(argument, invocation, matcher))); - } + private CompletableFuture match( + Invocation invocation, + CommandExecutor executor, + List matches, + Iterator> requirementIterator, + ParseableInputMatcher matcher + ) { + if (!requirementIterator.hasNext()) { + ParseableInputMatcher.EndResult endResult = matcher.endMatch(); - for (ContextRequirement contextRequirement : executor.getContextRequirements()) { - builder.link(new ScheduledRequirement<>(contextRequirement, () -> matchContext(contextRequirement, invocation))); - } + if (!endResult.isSuccessful()) { + return completedFuture(CommandExecutorMatchResult.failed(endResult.getFailedReason())); + } + + RequirementsResult.Builder resultBuilder = RequirementsResult.builder(invocation); - for (BindRequirement bindRequirement : executor.getBindRequirements()) { - builder.link(new ScheduledRequirement<>(bindRequirement, () -> matchBind(bindRequirement))); + for (RequirementMatch success : matches) { + resultBuilder.add(success.getRequirement().getName(), success); + } + + return completedFuture(executor.match(resultBuilder.build())); } - return builder.build((scheduledRequirement, requirementResult) -> { - Requirement requirement = scheduledRequirement.requirement; - WrapFormat wrapperFormat = requirement.getWrapperFormat(); + ScheduledRequirement scheduledRequirement = requirementIterator.next(); + + return scheduledRequirement.runMatch().thenCompose((requirementResult) -> { + Requirement requirement = scheduledRequirement.getRequirement(); if (requirementResult.isFailed()) { - return this.handleFailed(requirementResult, wrapperFormat, requirement); + WrapFormat wrapperFormat = requirement.getWrapperFormat(); + Object failedReason = requirementResult.getFailedReason(); + Wrapper wrapper = wrapperRegistry.getWrappedExpectedFactory(wrapperFormat); + + if (failedReason == Cause.MISSING_ARGUMENT && wrapper.canCreateEmpty()) { + Wrap wrap = wrapper.createEmpty(wrapperFormat); + + matches.add(new RequirementMatch(requirement, wrap)); + return match(invocation, executor, matches, requirementIterator, matcher); + } + + return CompletableFuture.completedFuture(CommandExecutorMatchResult.failed(failedReason)); } if (requirementResult.isSuccessfulNull()) { - return toMatch(requirement, null); + matches.add(toMatch(requirement, null)); + return match(invocation, executor, matches, requirementIterator, matcher); } Object success = requirementResult.getSuccess(); + List> validators = requirement.meta().get(Meta.REQUIREMENT_VALIDATORS); for (RequirementValidator validator : validators) { ValidatorResult validatorResult = validateRequirement(invocation, executor, requirement, success, validator); if (validatorResult.isInvalid()) { - throw new ScheduledChainException(validatorResult.getInvalidResult()); + return completedFuture(CommandExecutorMatchResult.failed(validatorResult.getInvalidResult())); } } - return toMatch(requirement, success); - }) - .collectChain(scheduler) - .thenCompose(result -> { - if (result.isFailure()) { - return completedFuture(CommandExecutorMatchResult.failed(result.getFailure())); - } - - ParseableInputMatcher.EndResult endResult = matcher.endMatch(); - - if (!endResult.isSuccessful()) { - return completedFuture(CommandExecutorMatchResult.failed(endResult.getFailedReason())); - } - - RequirementsResult.Builder restulrBuilder = RequirementsResult.builder(invocation); - - for (RequirementMatch, ?> success : result.getSuccess()) { - restulrBuilder.add(success.getRequirement().getName(), success); - } - - return completedFuture(executor.match(restulrBuilder.build())); + matches.add(toMatch(requirement, success)); + return match(invocation, executor, matches, requirementIterator, matcher); }); } - @SuppressWarnings("unchecked") - private , T> RequirementMatch handleFailed(RequirementResult requirementResult, WrapFormat wrapperFormat, R requirement) { - Object failedReason = requirementResult.getFailedReason(); - Wrapper wrapper = wrapperRegistry.getWrappedExpectedFactory(wrapperFormat); - - if (failedReason == Cause.MISSING_ARGUMENT && wrapper.canCreateEmpty()) { - Wrap wrap = (Wrap) wrapper.createEmpty(wrapperFormat); - - return new RequirementMatch<>(requirement, wrap); - } - - throw new ScheduledChainException(failedReason); - } @SuppressWarnings("unchecked") private ValidatorResult validateRequirement( @@ -299,54 +280,12 @@ private ValidatorResult validateRequirement( } @SuppressWarnings("unchecked") - private , T> RequirementMatch toMatch(R requirement, T result) { + private , T> RequirementMatch toMatch(R requirement, T result) { WrapFormat wrapperFormat = (WrapFormat) requirement.getWrapperFormat(); Wrap wrap = wrapperRegistry.wrap(() -> result, wrapperFormat); - return new RequirementMatch<>(requirement, wrap); + return new RequirementMatch(requirement, wrap); } - private static class ScheduledRequirement implements ScheduledChainLink> { - - private final Requirement requirement; - private final Supplier> match; - - public ScheduledRequirement(Requirement requirement, Supplier> match) { - this.requirement = requirement; - this.match = match; - } - - @Override - public RequirementResult call() { - return match.get(); - } - - @Override - public SchedulerPoll type() { - return requirement.meta().get(Meta.POLL_TYPE); - } - } - - private > RequirementResult matchArgument(Argument argument, Invocation invocation, MATCHER matcher) { - WrapFormat wrapFormat = argument.getWrapperFormat(); - ParserSet parserSet = parserRegistry.getParserSet(wrapFormat.getParsedType(), argument.getKey()); - - return matcher.nextArgument(invocation, argument, parserSet); - } - - private RequirementResult matchContext(ContextRequirement contextRequirement, Invocation invocation) { - return contextRegistry.provideContext(contextRequirement.getWrapperFormat().getParsedType(), invocation); - } - - private RequirementResult matchBind(BindRequirement bindRequirement) { - WrapFormat wrapFormat = bindRequirement.getWrapperFormat(); - Result instance = bindRegistry.getInstance(wrapFormat.getParsedType()); - - if (instance.isOk()) { - return ParseResult.success(instance.get()); - } - - return ParseResult.failure(instance.getError()); - } } diff --git a/litecommands-core/src/dev/rollczi/litecommands/command/executor/LiteContext.java b/litecommands-core/src/dev/rollczi/litecommands/command/executor/LiteContext.java index 02d284bed..30e7c3166 100644 --- a/litecommands-core/src/dev/rollczi/litecommands/command/executor/LiteContext.java +++ b/litecommands-core/src/dev/rollczi/litecommands/command/executor/LiteContext.java @@ -59,7 +59,7 @@ public Invocation invocation() { @SuppressWarnings("unchecked") private OUT get(String name, WrapFormat format) { - RequirementMatch match = result.get(name); + RequirementMatch match = result.get(name); if (match == null) { throw new IllegalArgumentException("Argument with name '" + name + "' not found"); diff --git a/litecommands-core/src/dev/rollczi/litecommands/command/executor/ScheduledRequirement.java b/litecommands-core/src/dev/rollczi/litecommands/command/executor/ScheduledRequirement.java new file mode 100644 index 000000000..8b20143de --- /dev/null +++ b/litecommands-core/src/dev/rollczi/litecommands/command/executor/ScheduledRequirement.java @@ -0,0 +1,33 @@ +package dev.rollczi.litecommands.command.executor; + +import dev.rollczi.litecommands.meta.Meta; +import dev.rollczi.litecommands.requirement.Requirement; +import dev.rollczi.litecommands.requirement.RequirementResult; +import dev.rollczi.litecommands.scheduler.SchedulerPoll; +import java.util.concurrent.CompletableFuture; +import java.util.function.Supplier; + +class ScheduledRequirement { + + private final Requirement requirement; + private final Supplier>> match; + + public ScheduledRequirement(Requirement requirement, Supplier>> match) { + this.requirement = requirement; + this.match = match; + } + + public Requirement getRequirement() { + return requirement; + } + + public CompletableFuture> runMatch() { + return match.get(); + } + + public SchedulerPoll type() { + return requirement.meta().get(Meta.POLL_TYPE); + } + + +} diff --git a/litecommands-core/src/dev/rollczi/litecommands/command/executor/ScheduledRequirementResolver.java b/litecommands-core/src/dev/rollczi/litecommands/command/executor/ScheduledRequirementResolver.java new file mode 100644 index 000000000..02d3e2f91 --- /dev/null +++ b/litecommands-core/src/dev/rollczi/litecommands/command/executor/ScheduledRequirementResolver.java @@ -0,0 +1,94 @@ +package dev.rollczi.litecommands.command.executor; + +import dev.rollczi.litecommands.argument.Argument; +import dev.rollczi.litecommands.argument.ArgumentKey; +import dev.rollczi.litecommands.argument.parser.ParseResult; +import dev.rollczi.litecommands.argument.parser.ParserRegistry; +import dev.rollczi.litecommands.argument.parser.ParserSet; +import dev.rollczi.litecommands.argument.parser.input.ParseableInputMatcher; +import dev.rollczi.litecommands.bind.BindRegistry; +import dev.rollczi.litecommands.context.ContextRegistry; +import dev.rollczi.litecommands.invocation.Invocation; +import dev.rollczi.litecommands.meta.Meta; +import dev.rollczi.litecommands.requirement.BindRequirement; +import dev.rollczi.litecommands.requirement.ContextRequirement; +import dev.rollczi.litecommands.requirement.Requirement; +import dev.rollczi.litecommands.requirement.RequirementResult; +import dev.rollczi.litecommands.scheduler.Scheduler; +import dev.rollczi.litecommands.shared.BiHashMap; +import dev.rollczi.litecommands.shared.BiMap; +import dev.rollczi.litecommands.shared.ThrowingSupplier; +import dev.rollczi.litecommands.wrapper.WrapFormat; +import java.util.ArrayList; +import java.util.List; +import org.jetbrains.annotations.NotNull; +import panda.std.Result; + +class ScheduledRequirementResolver { + + private final ContextRegistry contextRegistry; + private final ParserRegistry parserRegistry; + private final BindRegistry bindRegistry; + private final Scheduler scheduler; + + private final BiMap, ArgumentKey, ParserSet> cachedParserSets = new BiHashMap<>(); + + ScheduledRequirementResolver(ContextRegistry contextRegistry, ParserRegistry parserRegistry, BindRegistry bindRegistry, Scheduler scheduler) { + this.contextRegistry = contextRegistry; + this.parserRegistry = parserRegistry; + this.bindRegistry = bindRegistry; + this.scheduler = scheduler; + } + + @NotNull + > List> prepareRequirements(CommandExecutor executor, Invocation invocation, MATCHER matcher) { + List> requirements = new ArrayList<>(); + + for (Argument argument : executor.getArguments()) { + requirements.add(toScheduled(argument, () -> matchArgument(argument, invocation, matcher))); + } + + for (ContextRequirement contextRequirement : executor.getContextRequirements()) { + requirements.add(toScheduled(contextRequirement, () -> matchContext(contextRequirement, invocation))); + } + + for (BindRequirement bindRequirement : executor.getBindRequirements()) { + requirements.add(toScheduled(bindRequirement, () -> matchBind(bindRequirement))); + } + + return requirements; + } + + private ScheduledRequirement toScheduled(Requirement requirement, ThrowingSupplier, Throwable> resultSupplier) { + return new ScheduledRequirement<>(requirement, () -> scheduler.supply(requirement.meta().get(Meta.POLL_TYPE), resultSupplier)); + } + + @SuppressWarnings("unchecked") + private > RequirementResult matchArgument(Argument argument, Invocation invocation, MATCHER matcher) { + WrapFormat wrapFormat = argument.getWrapperFormat(); + ParserSet parserSet = (ParserSet) cachedParserSets.get(wrapFormat.getParsedType(), argument.getKey()); + + if (parserSet == null) { + parserSet = parserRegistry.getParserSet(wrapFormat.getParsedType(), argument.getKey()); + cachedParserSets.put(wrapFormat.getParsedType(), argument.getKey(), parserSet); + } + + return matcher.nextArgument(invocation, argument, parserSet); + } + + private RequirementResult matchContext(ContextRequirement contextRequirement, Invocation invocation) { + return contextRegistry.provideContext(contextRequirement.getWrapperFormat().getParsedType(), invocation); + } + + private RequirementResult matchBind(BindRequirement bindRequirement) { + WrapFormat wrapFormat = bindRequirement.getWrapperFormat(); + Result instance = bindRegistry.getInstance(wrapFormat.getParsedType()); + + if (instance.isOk()) { + return ParseResult.success(instance.get()); + } + + return ParseResult.failure(instance.getError()); + } + +} diff --git a/litecommands-core/src/dev/rollczi/litecommands/input/raw/RawInputAnalyzer.java b/litecommands-core/src/dev/rollczi/litecommands/input/raw/RawInputAnalyzer.java index d13e7822e..0d7c30c1b 100644 --- a/litecommands-core/src/dev/rollczi/litecommands/input/raw/RawInputAnalyzer.java +++ b/litecommands-core/src/dev/rollczi/litecommands/input/raw/RawInputAnalyzer.java @@ -60,7 +60,7 @@ public boolean nextRouteIsLast() { } public boolean isNextOptional(ParserSet parserSet, Invocation invocation, Argument argument) { - Parser validParser = parserSet.getValidParserOrThrow(RawInput.class, null, argument); + Parser validParser = parserSet.getValidParserOrThrow(null, argument); Range range = validParser.getRange(argument); return range.getMin() == 0; @@ -68,7 +68,7 @@ public boolean isNextOptional(ParserSet parserSet, Invoca public class Context { - private final Parser parser; + private final Parser parser; private final Argument argument; private final int argumentMinCount; private final int argumentMaxCount; @@ -81,7 +81,7 @@ public Context( ParserSet parserSet ) { this.argument = argument; - this.parser = parserSet.getValidParserOrThrow(RawInput.class, invocation, argument); + this.parser = parserSet.getValidParserOrThrow(invocation, argument); Range range = parser.getRange(argument); this.argumentMinCount = range.getMin() + pivotPosition; diff --git a/litecommands-core/src/dev/rollczi/litecommands/join/JoinArgumentResolver.java b/litecommands-core/src/dev/rollczi/litecommands/join/JoinArgumentResolver.java index fc65115ef..853660024 100644 --- a/litecommands-core/src/dev/rollczi/litecommands/join/JoinArgumentResolver.java +++ b/litecommands-core/src/dev/rollczi/litecommands/join/JoinArgumentResolver.java @@ -3,10 +3,6 @@ import dev.rollczi.litecommands.argument.Argument; import dev.rollczi.litecommands.argument.parser.ParseResult; import dev.rollczi.litecommands.argument.parser.TypedParser; -import dev.rollczi.litecommands.argument.resolver.TypedArgumentResolver; -import dev.rollczi.litecommands.argument.suggester.TypedSuggester; -import dev.rollczi.litecommands.suggestion.SuggestionContext; -import dev.rollczi.litecommands.suggestion.SuggestionResult; import dev.rollczi.litecommands.input.raw.RawInput; import dev.rollczi.litecommands.invalidusage.InvalidUsage; import dev.rollczi.litecommands.invocation.Invocation; @@ -15,18 +11,13 @@ import java.util.ArrayList; import java.util.List; -public abstract class JoinArgumentResolver implements TypedParser> { +public abstract class JoinArgumentResolver implements TypedParser> { @Override public Class getArgumentType() { return JoinArgument.class; } - @Override - public Class getInputType() { - return RawInput.class; - } - @Override public ParseResult parseTyped(Invocation invocation, JoinArgument argument, RawInput rawInput) { int limit = argument.getLimit(); diff --git a/litecommands-core/src/dev/rollczi/litecommands/meta/Meta.java b/litecommands-core/src/dev/rollczi/litecommands/meta/Meta.java index fa284ee1d..f1bf909cb 100644 --- a/litecommands-core/src/dev/rollczi/litecommands/meta/Meta.java +++ b/litecommands-core/src/dev/rollczi/litecommands/meta/Meta.java @@ -4,6 +4,7 @@ import dev.rollczi.litecommands.validator.Validator; import dev.rollczi.litecommands.validator.requirment.RequirementValidator; import org.jetbrains.annotations.ApiStatus; +import org.jetbrains.annotations.Contract; import org.jetbrains.annotations.NotNull; import java.lang.reflect.Parameter; @@ -34,7 +35,8 @@ public interface Meta { @NotNull T get(MetaKey key); - @NotNull T get(MetaKey key, T defaultValue); + @Contract("_, !null -> !null") + T get(MetaKey key, T defaultValue); Meta put(MetaKey key, T value); diff --git a/litecommands-core/src/dev/rollczi/litecommands/meta/MetaHolderCollectorImpl.java b/litecommands-core/src/dev/rollczi/litecommands/meta/MetaHolderCollectorImpl.java index 3a7888bcc..0e0915ed1 100644 --- a/litecommands-core/src/dev/rollczi/litecommands/meta/MetaHolderCollectorImpl.java +++ b/litecommands-core/src/dev/rollczi/litecommands/meta/MetaHolderCollectorImpl.java @@ -79,8 +79,9 @@ public T next() { private void findNext() { while (current != null) { - if (current.meta().has(key)) { - next = current.meta().get(key); + T t = current.meta().get(key, null); + if (t != null) { + next = t; current = current.parentMeta(); return; } diff --git a/litecommands-core/src/dev/rollczi/litecommands/meta/MetaKey.java b/litecommands-core/src/dev/rollczi/litecommands/meta/MetaKey.java index ee9841197..635e8f50a 100644 --- a/litecommands-core/src/dev/rollczi/litecommands/meta/MetaKey.java +++ b/litecommands-core/src/dev/rollczi/litecommands/meta/MetaKey.java @@ -61,7 +61,7 @@ public boolean equals(Object o) { @Override public int hashCode() { - return Objects.hash(key); + return key.hashCode(); } } diff --git a/litecommands-core/src/dev/rollczi/litecommands/requirement/RequirementMatch.java b/litecommands-core/src/dev/rollczi/litecommands/requirement/RequirementMatch.java index b32d976de..e26c3cb7d 100644 --- a/litecommands-core/src/dev/rollczi/litecommands/requirement/RequirementMatch.java +++ b/litecommands-core/src/dev/rollczi/litecommands/requirement/RequirementMatch.java @@ -2,21 +2,21 @@ import dev.rollczi.litecommands.wrapper.Wrap; -public class RequirementMatch, T> { +public class RequirementMatch { - private final REQUIREMENT requirement; - private final Wrap result; + private final Requirement requirement; + private final Wrap result; - public RequirementMatch(REQUIREMENT requirement, Wrap result) { + public RequirementMatch(Requirement requirement, Wrap result) { this.requirement = requirement; this.result = result; } - public REQUIREMENT getRequirement() { + public Requirement getRequirement() { return requirement; } - public Wrap getResult() { + public Wrap getResult() { return result; } diff --git a/litecommands-core/src/dev/rollczi/litecommands/requirement/RequirementsResult.java b/litecommands-core/src/dev/rollczi/litecommands/requirement/RequirementsResult.java index fe0ae8458..62168d57d 100644 --- a/litecommands-core/src/dev/rollczi/litecommands/requirement/RequirementsResult.java +++ b/litecommands-core/src/dev/rollczi/litecommands/requirement/RequirementsResult.java @@ -8,9 +8,9 @@ public class RequirementsResult { private final Invocation invocation; - private final Map> matches; + private final Map matches; - private RequirementsResult(Invocation invocation, Map> matches) { + private RequirementsResult(Invocation invocation, Map matches) { this.invocation = invocation; this.matches = matches; } @@ -19,7 +19,7 @@ public boolean has(String name) { return matches.containsKey(name); } - public RequirementMatch get(String name) { + public RequirementMatch get(String name) { return matches.get(name); } @@ -34,18 +34,19 @@ public static Builder builder(Invocation invocation) { public static class Builder { private final Invocation invocation; - private final Map> matches = new HashMap<>(); + private final Map matches = new HashMap<>(); public Builder(Invocation invocation) { this.invocation = invocation; } - public Builder add(String name, RequirementMatch match) { - if (matches.containsKey(name)) { - throw new IllegalArgumentException("Duplicate requirements name: " + name); + public Builder add(String name, RequirementMatch match) { + RequirementMatch replacedMatch = matches.put(name, match); + + if (replacedMatch != null) { + throw new IllegalStateException("Requirement match already exists: " + name); } - matches.put(name, match); return this; } diff --git a/litecommands-core/src/dev/rollczi/litecommands/scheduler/ScheduledChain.java b/litecommands-core/src/dev/rollczi/litecommands/scheduler/ScheduledChain.java deleted file mode 100644 index 8787c9570..000000000 --- a/litecommands-core/src/dev/rollczi/litecommands/scheduler/ScheduledChain.java +++ /dev/null @@ -1,99 +0,0 @@ -package dev.rollczi.litecommands.scheduler; - -import java.util.ArrayList; -import java.util.Collection; -import java.util.Iterator; -import java.util.List; -import java.util.concurrent.CompletableFuture; -import java.util.function.BiFunction; -import java.util.function.Function; - -import static java.util.concurrent.CompletableFuture.completedFuture; - -public class ScheduledChain, T, R> { - - private final Collection chain; - private final BiFunction mapper; - - private ScheduledChain(Collection chain, BiFunction mapper) { - this.chain = chain; - this.mapper = mapper; - } - - public CompletableFuture> collectChain(Scheduler scheduler) { - ChainCollector collector = new ChainCollector(scheduler); - - return collector.collect(); - } - - public static , T> Builder builder() { - return new Builder<>(); - } - - public static class Builder, T> { - - private final List chain = new ArrayList<>(); - - public Builder link(CHAIN link) { - chain.add(link); - return this; - } - - public Builder links(Collection links) { - chain.addAll(links); - return this; - } - - public ScheduledChain build(Function mapper) { - return new ScheduledChain<>(chain, (chain1, t) -> mapper.apply(t)); - } - - public ScheduledChain build(BiFunction mapper) { - return new ScheduledChain<>(chain, mapper); - } - - public ScheduledChain build() { - return build(t -> t); - } - - } - - private class ChainCollector { - - private final Iterator chainLinkIterator; - private final Scheduler scheduler; - - ChainCollector(Scheduler scheduler) { - this.scheduler = scheduler; - this.chainLinkIterator = chain.iterator(); - } - - CompletableFuture> collect() { - return collect(new ArrayList<>()); - } - - private CompletableFuture> collect(List results) { - if (!chainLinkIterator.hasNext()) { - return completedFuture(ScheduledChainResult.success(results)); - } - - CHAIN chainLink = chainLinkIterator.next(); - - return scheduler - .supply(chainLink.type(), () -> { - try { - R returnValue = mapper.apply(chainLink, chainLink.call()); - results.add(returnValue); - - return this.collect(results); - } - catch (ScheduledChainException exception) { - return completedFuture(ScheduledChainResult.failure(exception.getReason())); - } - }) - .thenCompose(completableFuture -> completableFuture); - } - - } - -} diff --git a/litecommands-core/src/dev/rollczi/litecommands/scheduler/ScheduledChainException.java b/litecommands-core/src/dev/rollczi/litecommands/scheduler/ScheduledChainException.java deleted file mode 100644 index 4447cc017..000000000 --- a/litecommands-core/src/dev/rollczi/litecommands/scheduler/ScheduledChainException.java +++ /dev/null @@ -1,15 +0,0 @@ -package dev.rollczi.litecommands.scheduler; - -public class ScheduledChainException extends RuntimeException { - - private final Object reason; - - public ScheduledChainException(Object reason) { - this.reason = reason; - } - - public Object getReason() { - return reason; - } - -} diff --git a/litecommands-core/src/dev/rollczi/litecommands/scheduler/ScheduledChainLink.java b/litecommands-core/src/dev/rollczi/litecommands/scheduler/ScheduledChainLink.java deleted file mode 100644 index 193deccc9..000000000 --- a/litecommands-core/src/dev/rollczi/litecommands/scheduler/ScheduledChainLink.java +++ /dev/null @@ -1,20 +0,0 @@ -package dev.rollczi.litecommands.scheduler; - -/** - * Represents the task in the chain - * - * @param the type of the result - */ -public interface ScheduledChainLink { - - /** - * Executes the task and returns the result - * - * @throws ScheduledChainException if the chain is broken - * @return the result of the task - */ - T call(); - - SchedulerPoll type(); - -} diff --git a/litecommands-core/src/dev/rollczi/litecommands/scheduler/ScheduledChainResult.java b/litecommands-core/src/dev/rollczi/litecommands/scheduler/ScheduledChainResult.java deleted file mode 100644 index 73ec8d778..000000000 --- a/litecommands-core/src/dev/rollczi/litecommands/scheduler/ScheduledChainResult.java +++ /dev/null @@ -1,41 +0,0 @@ -package dev.rollczi.litecommands.scheduler; - -import org.jetbrains.annotations.Nullable; - -import java.util.List; - -public class ScheduledChainResult { - - private final List results; - private final @Nullable Object failureReason; - - private ScheduledChainResult(List results, @Nullable Object failureReason) { - this.results = results; - this.failureReason = failureReason; - } - - public List getSuccess() { - return results; - } - - public @Nullable Object getFailure() { - return failureReason; - } - - public boolean isSuccess() { - return failureReason == null; - } - - public boolean isFailure() { - return failureReason != null; - } - - public static ScheduledChainResult success(List results) { - return new ScheduledChainResult<>(results, null); - } - - public static ScheduledChainResult failure(Object failureReason) { - return new ScheduledChainResult<>(null, failureReason); - } - -} diff --git a/litecommands-core/src/dev/rollczi/litecommands/validator/ValidatorService.java b/litecommands-core/src/dev/rollczi/litecommands/validator/ValidatorService.java index 983b2a9db..2ddf498e7 100644 --- a/litecommands-core/src/dev/rollczi/litecommands/validator/ValidatorService.java +++ b/litecommands-core/src/dev/rollczi/litecommands/validator/ValidatorService.java @@ -33,11 +33,11 @@ public void registerValidator(Scope scope, Validator validator) { } /* Kinda shitty, but I don't know how to do it better without losing performance https://github.com/Rollczi/LiteCommands/commit/3ac889d82e3e4d39fea27eee91cf5b01adacb412 */ - public Flow validate(Invocation invocation, Scopeable metaHolder) { + public Flow validate(Invocation invocation, Scopeable scopeable) { Flow lastStopped = null; for (Validator validator : commandGlobalValidators) { - Flow flow = validator.validate(invocation, metaHolder); + Flow flow = validator.validate(invocation, scopeable); switch (flow.status()) { case CONTINUE: continue; @@ -46,7 +46,7 @@ public Flow validate(Invocation invocation, Scopeable metaHolder) { } } - for (List>> validators : metaHolder.metaCollector().iterable(Meta.VALIDATORS)) { + for (List>> validators : scopeable.metaCollector().iterable(Meta.VALIDATORS)) { for (Class> validatorType : validators) { Validator validator = validatorsByClass.get(validatorType); @@ -54,7 +54,7 @@ public Flow validate(Invocation invocation, Scopeable metaHolder) { throw new IllegalStateException("Validator " + validatorType + " not found"); } - Flow flow = validator.validate(invocation, metaHolder); + Flow flow = validator.validate(invocation, scopeable); switch (flow.status()) { case CONTINUE: continue; @@ -65,11 +65,11 @@ public Flow validate(Invocation invocation, Scopeable metaHolder) { } for (Map.Entry> entry : commandValidators.entrySet()) { - if (!entry.getKey().isApplicable(metaHolder)) { + if (!entry.getKey().isApplicable(scopeable)) { continue; } - Flow flow = entry.getValue().validate(invocation, metaHolder); + Flow flow = entry.getValue().validate(invocation, scopeable); switch (flow.status()) { case CONTINUE: continue; diff --git a/litecommands-core/src/dev/rollczi/litecommands/wrapper/WrapFormat.java b/litecommands-core/src/dev/rollczi/litecommands/wrapper/WrapFormat.java index a65814286..facd590e6 100644 --- a/litecommands-core/src/dev/rollczi/litecommands/wrapper/WrapFormat.java +++ b/litecommands-core/src/dev/rollczi/litecommands/wrapper/WrapFormat.java @@ -5,24 +5,20 @@ public interface WrapFormat { - @Deprecated Class getParsedType(); TypeToken parsedType(); boolean hasOutType(); - @Deprecated Class getOutTypeOrParsed(); TypeToken outOrElseParsed(); - @Deprecated Class getOutType(); TypeToken outType(); - @Deprecated static WrapFormat of(Class type, Class toWrapperType) { if (toWrapperType == null) { throw new IllegalArgumentException("Wrapper type cannot be null"); @@ -31,7 +27,6 @@ static WrapFormat of(Class type, Class t return new WrapFormatClass<>(type, toWrapperType); } - @Deprecated static WrapFormat notWrapped(Class type) { return new WrapFormatClass<>(type, null); } diff --git a/litecommands-core/src/dev/rollczi/litecommands/wrapper/WrapFormatClass.java b/litecommands-core/src/dev/rollczi/litecommands/wrapper/WrapFormatClass.java index e59a5857f..8cfe8e70b 100644 --- a/litecommands-core/src/dev/rollczi/litecommands/wrapper/WrapFormatClass.java +++ b/litecommands-core/src/dev/rollczi/litecommands/wrapper/WrapFormatClass.java @@ -2,7 +2,6 @@ import dev.rollczi.litecommands.reflect.type.TypeToken; -@Deprecated class WrapFormatClass implements WrapFormat { private final Class parsedType; diff --git a/litecommands-core/src/dev/rollczi/litecommands/wrapper/std/ValueWrapper.java b/litecommands-core/src/dev/rollczi/litecommands/wrapper/std/ValueWrapper.java index c16c8bfe7..bc85bf9d2 100644 --- a/litecommands-core/src/dev/rollczi/litecommands/wrapper/std/ValueWrapper.java +++ b/litecommands-core/src/dev/rollczi/litecommands/wrapper/std/ValueWrapper.java @@ -14,7 +14,19 @@ public ValueWrapper() { @Override protected Supplier wrapValue(@Nullable EXPECTED valueToWrap, WrapFormat info) { - return () -> valueToWrap; + return new WrapperImpl<>(valueToWrap); } + private static class WrapperImpl implements Supplier { + private final @Nullable EXPECTED valueToWrap; + + public WrapperImpl(@Nullable EXPECTED valueToWrap) { + this.valueToWrap = valueToWrap; + } + + @Override + public Object get() { + return valueToWrap; + } + } } diff --git a/litecommands-core/test/dev/rollczi/litecommands/argument/parser/ParserRegistryImplTest.java b/litecommands-core/test/dev/rollczi/litecommands/argument/parser/ParserRegistryImplTest.java index aafbd7be4..4e4da8a32 100644 --- a/litecommands-core/test/dev/rollczi/litecommands/argument/parser/ParserRegistryImplTest.java +++ b/litecommands-core/test/dev/rollczi/litecommands/argument/parser/ParserRegistryImplTest.java @@ -9,7 +9,6 @@ import dev.rollczi.litecommands.reflect.type.TypeRange; import dev.rollczi.litecommands.unit.TestSender; import dev.rollczi.litecommands.wrapper.WrapFormat; -import java.util.List; import org.junit.jupiter.api.Test; import static org.assertj.core.api.AssertionsForInterfaceTypes.assertThat; @@ -27,7 +26,7 @@ void registerParser() { registry.registerParser(String.class, ArgumentKey.of(), new NamedResolver("universal")); ParserSet universal = registry.getParserSet(String.class, ArgumentKey.of()); - Parser universalParser = universal.getValidParserOrThrow(RawInput.class, null, Argument.of("universal", STRING_FORMAT)); + Parser universalParser = universal.getValidParserOrThrow(null, Argument.of("universal", STRING_FORMAT)); assertThat(universalParser.parse(null, Argument.of("universal", STRING_FORMAT), RawInput.of("in"))) .isEqualTo(ParseResult.success("universal")); @@ -44,9 +43,9 @@ void registerCustomParser() { ParserSet universal = registry.getParserSet(String.class, ArgumentKey.of()); ParserSet missing = registry.getParserSet(String.class, ArgumentKey.of("missing")); - Parser customParser = assertNotNull(custom.getValidParser(RawInput.class, null, Argument.of("custom", STRING_FORMAT))); - Parser universalParser = assertNotNull(universal.getValidParser(RawInput.class, null, Argument.of("universal", STRING_FORMAT))); - Parser missingParser = assertNotNull(missing.getValidParser(RawInput.class, null, Argument.of("missing", STRING_FORMAT))); + Parser customParser = assertNotNull(custom.getValidParser(null, Argument.of("custom", STRING_FORMAT))); + Parser universalParser = assertNotNull(universal.getValidParser(null, Argument.of("universal", STRING_FORMAT))); + Parser missingParser = assertNotNull(missing.getValidParser(null, Argument.of("missing", STRING_FORMAT))); assertThat(customParser.parse(null, Argument.of("custom", STRING_FORMAT), RawInput.of("in"))) .isEqualTo(ParseResult.success("custom")); @@ -66,8 +65,8 @@ void testGenericTypes() { ParserSet number = registry.getParserSet(Number.class, ArgumentKey.of()); ParserSet integer = registry.getParserSet(Integer.class, ArgumentKey.of()); - Parser numberParser = assertNotNull(number.getValidParser(RawInput.class, null, Argument.of("number", NUMBER_FORMAT))); - Parser integerParser = assertNotNull(integer.getValidParser(RawInput.class, null, Argument.of("integer", INTEGER_FORMAT))); + Parser numberParser = assertNotNull(number.getValidParser(null, Argument.of("number", NUMBER_FORMAT))); + Parser integerParser = assertNotNull(integer.getValidParser(null, Argument.of("integer", INTEGER_FORMAT))); assertThat(numberParser.parse(null, Argument.of("number", NUMBER_FORMAT), RawInput.of("1"))) .isEqualTo(ParseResult.success(1)); diff --git a/litecommands-core/test/dev/rollczi/litecommands/scheduler/ScheduledChainTest.java b/litecommands-core/test/dev/rollczi/litecommands/scheduler/ScheduledChainTest.java deleted file mode 100644 index aa2829f3b..000000000 --- a/litecommands-core/test/dev/rollczi/litecommands/scheduler/ScheduledChainTest.java +++ /dev/null @@ -1,58 +0,0 @@ -package dev.rollczi.litecommands.scheduler; - -import org.junit.jupiter.api.Test; - -import java.util.List; - -import static org.junit.jupiter.api.Assertions.assertEquals; - -class ScheduledChainTest { - - @Test - void test() { - Scheduler scheduler = new SchedulerExecutorPoolImpl("test", 4); - - ScheduledChain scheduledChain = ScheduledChain.builder() - .link(new Argument("1", SchedulerPoll.MAIN)) - .link(new Argument("2", SchedulerPoll.MAIN)) - .link(new Argument("3", SchedulerPoll.ASYNCHRONOUS)) - .link(new Argument("4", SchedulerPoll.MAIN)) - .link(new Argument("5", SchedulerPoll.ASYNCHRONOUS)) - .link(new Argument("6", SchedulerPoll.MAIN)) - .build(text -> text + " -> " + Thread.currentThread().getName()); - - List list = scheduledChain.collectChain(scheduler) - .join() - .getSuccess(); - - assertEquals(6, list.size()); - assertEquals("1 -> scheduler-test-main", list.get(0)); - assertEquals("2 -> scheduler-test-main", list.get(1)); - assertEquals("3 -> scheduler-test-async-0", list.get(2)); - assertEquals("4 -> scheduler-test-main", list.get(3)); - assertEquals("5 -> scheduler-test-async-1", list.get(4)); - assertEquals("6 -> scheduler-test-main", list.get(5)); - } - - static class Argument implements ScheduledChainLink { - - private final String value; - private final SchedulerPoll type; - - Argument(String value, SchedulerPoll type) { - this.value = value; - this.type = type; - } - - @Override - public String call() { - return value; - } - - @Override - public SchedulerPoll type() { - return type; - } - } - -} \ No newline at end of file diff --git a/litecommands-framework/src/dev/rollczi/litecommands/LiteCommandsBaseBuilder.java b/litecommands-framework/src/dev/rollczi/litecommands/LiteCommandsBaseBuilder.java index f1dc96b2e..3ac034aa6 100644 --- a/litecommands-framework/src/dev/rollczi/litecommands/LiteCommandsBaseBuilder.java +++ b/litecommands-framework/src/dev/rollczi/litecommands/LiteCommandsBaseBuilder.java @@ -231,18 +231,18 @@ private void preProcessExtensionsOnProvider(LiteCommandsProvider command } @Override - public B argumentParser(Class type, Parser parser) { + public B argumentParser(Class type, Parser parser) { return argumentParser(TypeRange.same(type), ArgumentKey.of(), parser); } @Override public - B argumentParser(Class type, ArgumentKey key, Parser parser) { + B argumentParser(Class type, ArgumentKey key, Parser parser) { return argumentParser(TypeRange.same(type), key, parser); } @Override - public B argumentParser(TypeRange type, ArgumentKey key, Parser parser) { + public B argumentParser(TypeRange type, ArgumentKey key, Parser parser) { this.parserRegistry.registerParser(type, key, parser); return this.self(); } @@ -283,23 +283,23 @@ public B argumentSuggester(TypeRange type, ArgumentKey key, Suggester - B argument(Class type, ArgumentResolverBase resolver) { + B argument(Class type, ArgumentResolverBase resolver) { return argument(TypeRange.same(type), ArgumentKey.of(), resolver); } @Override public - B argument(Class type, ArgumentKey key, ArgumentResolverBase resolver) { + B argument(Class type, ArgumentKey key, ArgumentResolverBase resolver) { return argument(TypeRange.same(type), key, resolver); } @Override - public B argument(TypeRange type, ArgumentResolverBase resolver) { + public B argument(TypeRange type, ArgumentResolverBase resolver) { return argument(type, ArgumentKey.of(), resolver); } @Override - public B argument(TypeRange type, ArgumentKey key, ArgumentResolverBase resolver) { + public B argument(TypeRange type, ArgumentKey key, ArgumentResolverBase resolver) { this.argumentParser(type, key, resolver); this.argumentSuggester(type, key, resolver); return this.self(); diff --git a/litecommands-framework/src/dev/rollczi/litecommands/LiteCommandsBuilder.java b/litecommands-framework/src/dev/rollczi/litecommands/LiteCommandsBuilder.java index 6fa04b903..c0201caed 100644 --- a/litecommands-framework/src/dev/rollczi/litecommands/LiteCommandsBuilder.java +++ b/litecommands-framework/src/dev/rollczi/litecommands/LiteCommandsBuilder.java @@ -89,13 +89,13 @@ public interface LiteCommandsBuilder - B argumentParser(Class type, Parser parser); + B argumentParser(Class type, Parser parser); - B argumentParser(Class type, ArgumentKey key, Parser parser); + B argumentParser(Class type, ArgumentKey key, Parser parser); - B argumentParser(TypeRange type, ArgumentKey key, Parser parser); + B argumentParser(TypeRange type, ArgumentKey key, Parser parser); B argumentSuggestion(Class type, SuggestionResult suggestion); @@ -138,7 +138,7 @@ B argumentSuggester(Class type, ArgumentKey key, SuggestionResult suggestion) * @return this builder */ - B argument(Class type, ArgumentResolverBase resolver); + B argument(Class type, ArgumentResolverBase resolver); /** * [Keyed Argument Parser and Suggester] @@ -152,13 +152,13 @@ B argumentSuggester(Class type, ArgumentKey key, SuggestionResult suggestion) * @return this builder */ - B argument(Class type, ArgumentKey key, ArgumentResolverBase resolver); + B argument(Class type, ArgumentKey key, ArgumentResolverBase resolver); - B argument(TypeRange type, ArgumentResolverBase resolver); + B argument(TypeRange type, ArgumentResolverBase resolver); - B argument(TypeRange type, ArgumentKey key, ArgumentResolverBase resolver); + B argument(TypeRange type, ArgumentKey key, ArgumentResolverBase resolver); B context(Class on, ContextProvider bind); diff --git a/litecommands-jda/src/dev/rollczi/litecommands/jda/JDAParseableInput.java b/litecommands-jda/src/dev/rollczi/litecommands/jda/JDAParseableInput.java index 4fa82cac2..143353e7a 100644 --- a/litecommands-jda/src/dev/rollczi/litecommands/jda/JDAParseableInput.java +++ b/litecommands-jda/src/dev/rollczi/litecommands/jda/JDAParseableInput.java @@ -63,11 +63,14 @@ public ParseResult nextArgument(Invocation invo return ParseResult.success((PARSED) input); } + Parser parser = parserSet.getValidParserOrThrow(invocation, argument); + try { - return this.parseInput(invocation, argument, parserSet, input); + //TODO: implement parse custom Input to PARSED + throw new LiteJDAParseException("Cannot parse input"); } catch (LiteJDAParseException exception) { - return this.parseInput(invocation, argument, parserSet, RawInput.of(optionMapping.getAsString().split(" "))); + return parser.parse(invocation, argument, RawInput.of(optionMapping.getAsString().split(" "))); } } @@ -87,14 +90,6 @@ private JDACommandTranslator.JDARoute toRoute(String argumentName) { throw new IllegalArgumentException("Cannot convert to route"); } - @SuppressWarnings("unchecked") - private ParseResult parseInput(Invocation invocation, Argument argument, ParserSet parserSet, INPUT input) { - Class inputType = (Class) input.getClass(); - Parser parser = parserSet.getValidParserOrThrow(inputType, invocation, argument); - - return parser.parse(invocation, argument, input); - } - @Override public JDAInputMatcher copy() { return new JDAInputMatcher(routePosition); diff --git a/litecommands-unit/src/dev/rollczi/litecommands/unit/AssertExecute.java b/litecommands-unit/src/dev/rollczi/litecommands/unit/AssertExecute.java index 9f6bf7f17..3d970178b 100644 --- a/litecommands-unit/src/dev/rollczi/litecommands/unit/AssertExecute.java +++ b/litecommands-unit/src/dev/rollczi/litecommands/unit/AssertExecute.java @@ -115,7 +115,8 @@ public T assertFailedAs(Class type) { throw new AssertionError("Failed reason is empty"); } - return assertInstanceOf(type, error); + assertThat(error).isInstanceOf(type); + return type.cast(error); } public AssertExecute assertFailure(Object reason) {