diff --git a/src/main/java/dev/qixils/quasicord/converter/Converter.java b/src/main/java/dev/qixils/quasicord/converter/Converter.java index 15d883b..8cd235c 100644 --- a/src/main/java/dev/qixils/quasicord/converter/Converter.java +++ b/src/main/java/dev/qixils/quasicord/converter/Converter.java @@ -8,6 +8,7 @@ import net.dv8tion.jda.api.interactions.Interaction; import org.checkerframework.checker.nullness.qual.NonNull; +import org.jetbrains.annotations.ApiStatus; /** * An interface for converting a user-provided value to a different type. @@ -38,10 +39,24 @@ public interface Converter { * * @param interaction the interaction being invoked * @param input the user input + * @param targetClass the class to convert to * @return converted value */ @NonNull - O convert(@NonNull Interaction interaction, @NonNull I input); + O convert(@NonNull Interaction interaction, @NonNull I input, @NonNull Class targetClass); + + /** + * Converts an input to the output type. + * + * @param interaction the interaction being invoked + * @param input the user input + * @return converted value + */ + @NonNull + @ApiStatus.NonExtendable + default O convert(@NonNull Interaction interaction, @NonNull I input) { + return convert(interaction, input, getOutputClass()); + } /** * Determines whether this converter can be converted to in a converter chain. diff --git a/src/main/java/dev/qixils/quasicord/converter/ConverterImpl.java b/src/main/java/dev/qixils/quasicord/converter/ConverterImpl.java index 3eefc28..392b0aa 100644 --- a/src/main/java/dev/qixils/quasicord/converter/ConverterImpl.java +++ b/src/main/java/dev/qixils/quasicord/converter/ConverterImpl.java @@ -15,20 +15,42 @@ public class ConverterImpl extends AbstractConverter { - private final @NonNull BiFunction converter; + @FunctionalInterface + public interface ConverterImplStep { + /** + * Converts an input to the output type. + * + * @param interaction the interaction being invoked + * @param input the user input + * @param targetClass the class to convert to + * @return converted value + */ + @NonNull + O convert(@NonNull Interaction interaction, @NonNull I input, @NonNull Class targetClass); + } + + private final @NonNull ConverterImplStep converter; + + public ConverterImpl( + @NonNull Class inputClass, + @NonNull Class outputClass, + @NonNull ConverterImplStep converter + ) { + super(inputClass, outputClass); + this.converter = converter; + } public ConverterImpl( @NonNull Class inputClass, @NonNull Class outputClass, @NonNull BiFunction converter ) { - super(inputClass, outputClass); - this.converter = converter; + this(inputClass, outputClass, (ctx, i, t) -> converter.apply(ctx, i)); } @Override - public @NonNull O convert(@NonNull Interaction interaction, @NonNull I input) { - return converter.apply(interaction, input); + public @NonNull O convert(@NonNull Interaction interaction, @NonNull I input, @NonNull Class targetClass) { + return converter.convert(interaction, input, targetClass); } @NonNull diff --git a/src/main/java/dev/qixils/quasicord/converter/ConverterRegistry.java b/src/main/java/dev/qixils/quasicord/converter/ConverterRegistry.java index ffe3bc8..85e20fc 100644 --- a/src/main/java/dev/qixils/quasicord/converter/ConverterRegistry.java +++ b/src/main/java/dev/qixils/quasicord/converter/ConverterRegistry.java @@ -25,10 +25,7 @@ import org.checkerframework.checker.nullness.qual.Nullable; import java.time.*; -import java.util.ArrayList; -import java.util.List; -import java.util.Locale; -import java.util.Objects; +import java.util.*; import static dev.qixils.quasicord.converter.ConverterImpl.identity; @@ -76,6 +73,8 @@ public ConverterRegistry(@NonNull Quasicord library) { register(new ConverterImpl<>(Number.class, Byte.class, (it, b) -> b.byteValue())); // misc register(new ConverterImpl<>(User.class, Member.class, (it, u) -> Objects.requireNonNull(Objects.requireNonNull(it.getGuild()).getMember(u)))); + register(new ConverterImpl<>(Integer.class, Enum.class, (ctx, i, tc) -> tc.getEnumConstants()[i])); + register(new ConverterImpl<>(String.class, Enum.class, (ctx, i, tc) -> Arrays.stream(tc.getEnumConstants()).filter(e -> e.name().equals(i)).findFirst().orElseThrow())); } @NonNull @@ -180,10 +179,10 @@ private ChainConverter(@NonNull Class inputClass, @NonNull Class outputCla @SuppressWarnings({"unchecked", "rawtypes"}) // i'm sorry JVM @Override - public @NonNull O convert(@NonNull Interaction interaction, @NonNull I input) { + public @NonNull O convert(@NonNull Interaction interaction, @NonNull I input, @NonNull Class targetClass) { Object result = input; for (Converter converter : converters) - result = converter.convert(interaction, result); + result = converter.convert(interaction, result, targetClass); // TODO: does passing targetClass unconditionally make sense here? return (O) result; } } diff --git a/src/main/java/dev/qixils/quasicord/converter/VoidConverter.java b/src/main/java/dev/qixils/quasicord/converter/VoidConverter.java index 5a27f63..d2ebe32 100644 --- a/src/main/java/dev/qixils/quasicord/converter/VoidConverter.java +++ b/src/main/java/dev/qixils/quasicord/converter/VoidConverter.java @@ -16,7 +16,7 @@ public interface VoidConverter extends Converter { @Override - default @NonNull O convert(@NonNull Interaction interaction, @Nullable Void input) { + default @NonNull O convert(@NonNull Interaction interaction, @Nullable Void input, @NonNull Class targetClass) { return convert(interaction); } diff --git a/src/main/java/dev/qixils/quasicord/converter/impl/DurationConverter.java b/src/main/java/dev/qixils/quasicord/converter/impl/DurationConverter.java index b4410cf..be5b62c 100644 --- a/src/main/java/dev/qixils/quasicord/converter/impl/DurationConverter.java +++ b/src/main/java/dev/qixils/quasicord/converter/impl/DurationConverter.java @@ -32,7 +32,7 @@ public class DurationConverter implements Converter { private static final @NonNull Pattern RELATIVE_TIME_PATTERN = Pattern.compile("^\\d+[A-Za-z]+"); @Override - public @NonNull Duration convert(@NonNull Interaction interaction, @NonNull String input) { + public @NonNull Duration convert(@NonNull Interaction interaction, @NonNull String input, @NonNull Class targetClass) { List arguments = new ArrayList<>(Arrays.asList(input.split(" "))); arguments.removeIf(s -> RELATIVE_TIME_IGNORED_TOKENS.contains(s.toLowerCase(Locale.ENGLISH))); String strippedInput = String.join("", arguments); diff --git a/src/main/java/dev/qixils/quasicord/converter/impl/LocaleConverter.java b/src/main/java/dev/qixils/quasicord/converter/impl/LocaleConverter.java index 9a869be..a65f319 100644 --- a/src/main/java/dev/qixils/quasicord/converter/impl/LocaleConverter.java +++ b/src/main/java/dev/qixils/quasicord/converter/impl/LocaleConverter.java @@ -35,7 +35,7 @@ public LocaleConverter(@NonNull Quasicord library) { } @Override - public @NonNull Locale convert(@NonNull Interaction it, @NonNull String input) { + public @NonNull Locale convert(@NonNull Interaction it, @NonNull String input, @org.checkerframework.checker.nullness.qual.NonNull Class targetClass) { try { return new Locale.Builder().setLanguageTag(input).build(); } catch (IllformedLocaleException ignored) { diff --git a/src/main/java/dev/qixils/quasicord/converter/impl/ZoneIdConverter.java b/src/main/java/dev/qixils/quasicord/converter/impl/ZoneIdConverter.java index 84fdc6e..81edc95 100644 --- a/src/main/java/dev/qixils/quasicord/converter/impl/ZoneIdConverter.java +++ b/src/main/java/dev/qixils/quasicord/converter/impl/ZoneIdConverter.java @@ -28,7 +28,7 @@ public class ZoneIdConverter implements Converter { private final @NonNull Class outputClass = ZoneId.class; @Override - public @NonNull ZoneId convert(@NonNull Interaction it, @NonNull String input) { + public @NonNull ZoneId convert(@NonNull Interaction it, @NonNull String input, @org.checkerframework.checker.nullness.qual.NonNull Class targetClass) { try { return ZoneId.of(input); } catch (Exception ignored) { diff --git a/src/main/java/dev/qixils/quasicord/converter/impl/ZonedDateTimeConverter.java b/src/main/java/dev/qixils/quasicord/converter/impl/ZonedDateTimeConverter.java index fffd45b..1bcde48 100644 --- a/src/main/java/dev/qixils/quasicord/converter/impl/ZonedDateTimeConverter.java +++ b/src/main/java/dev/qixils/quasicord/converter/impl/ZonedDateTimeConverter.java @@ -46,7 +46,7 @@ public ZonedDateTimeConverter(@NonNull Quasicord library) { } @Override - public @NonNull ZonedDateTime convert(@NonNull Interaction interaction, @NonNull String input) { + public @NonNull ZonedDateTime convert(@NonNull Interaction interaction, @NonNull String input, @NonNull Class targetClass) { TimeZoneConfig config = library.getDatabaseManager().getById(interaction.getUser().getIdLong(), TimeZoneConfig.class).block(); ZoneId zone = config == null ? ZoneOffset.UTC : config.getTimeZone(); ZonedDateTime now = ZonedDateTime.now(zone); diff --git a/src/main/java/dev/qixils/quasicord/decorators/ConverterData.java b/src/main/java/dev/qixils/quasicord/decorators/ConverterData.java index 707391c..c1f1f0d 100644 --- a/src/main/java/dev/qixils/quasicord/decorators/ConverterData.java +++ b/src/main/java/dev/qixils/quasicord/decorators/ConverterData.java @@ -12,5 +12,5 @@ import org.jetbrains.annotations.ApiStatus; @ApiStatus.Internal -public record ConverterData(@NonNull Converter converter, @Nullable String optName) { +public record ConverterData(@NonNull Converter converter, @Nullable String optName, @NonNull Class targetClass) { } diff --git a/src/main/java/dev/qixils/quasicord/decorators/ParserSlashCommand.java b/src/main/java/dev/qixils/quasicord/decorators/ParserSlashCommand.java index 0dff887..c0f4868 100644 --- a/src/main/java/dev/qixils/quasicord/decorators/ParserSlashCommand.java +++ b/src/main/java/dev/qixils/quasicord/decorators/ParserSlashCommand.java @@ -160,7 +160,7 @@ else if (option.type() == OptionType.STRING) branch.root().addOptions(opt); } - converters[i] = new ConverterData(converter, optNameStr); + converters[i] = new ConverterData(converter, optNameStr, parameter.getType()); } } @@ -224,7 +224,7 @@ else if (inputClass == Member.class) { } else throw new IllegalArgumentException("Could not accept interaction option of type " + option.getType() + " for a converter from " + inputClass.getName()); - args[i] = converter.convert(interaction, input); + args[i] = converter.convert(interaction, input, converterData.targetClass()); } // invoke and handle