diff --git a/src/Disqord.Bot/Commands/Implementation/Application/ExecutionSteps/Slash/BindOptions.cs b/src/Disqord.Bot/Commands/Implementation/Application/ExecutionSteps/Slash/BindOptions.cs index 27a3e820d..8f80cc2f2 100644 --- a/src/Disqord.Bot/Commands/Implementation/Application/ExecutionSteps/Slash/BindOptions.cs +++ b/src/Disqord.Bot/Commands/Implementation/Application/ExecutionSteps/Slash/BindOptions.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Threading.Tasks; +using Disqord.Serialization.Json; using Qmmands; using Qommon; @@ -84,15 +85,17 @@ static IReadOnlyDictionary GetArguments( continue; } - if (option.Value is not string stringValue) + if (option.Value.Type != JsonValueType.String) { + var value = GetOptionValue(option); arguments[parameter] = actualType.IsEnum - ? Enum.ToObject(actualType, option.Value) - : Convert.ChangeType(option.Value, actualType, context.Locale); + ? Enum.ToObject(actualType, value) + : Convert.ChangeType(value, actualType, context.Locale); continue; } + var stringValue = option.Value.ToType()!; if (interaction is IAutoCompleteInteraction) { // Treat string values as arguments for auto-complete. @@ -105,7 +108,7 @@ static IReadOnlyDictionary GetArguments( { // If the option is just a string, pass it through to type parsing. var rawArguments = context.RawArguments ??= new Dictionary(); - rawArguments[parameter] = option.Value as string; + rawArguments[parameter] = stringValue; continue; } @@ -134,5 +137,30 @@ static IReadOnlyDictionary GetArguments( return Next.ExecuteAsync(context); } + + private static object GetOptionValue(ISlashCommandInteractionOption option) + { + var value = option.Value!; + switch (option.Type) + { + case SlashCommandOptionType.Integer: + { + return value.ToType(); + } + case SlashCommandOptionType.Boolean: + { + return value.ToType(); + } + case SlashCommandOptionType.Number: + { + return value.ToType(); + } + default: + { + Throw.ArgumentOutOfRangeException(nameof(option)); + return default; + } + } + } } } diff --git a/src/Disqord.Core/Entities/Core/Interactions/Commands/Slash/ISlashCommandInteractionOption.cs b/src/Disqord.Core/Entities/Core/Interactions/Commands/Slash/ISlashCommandInteractionOption.cs index f47e91144..1fa3d699c 100644 --- a/src/Disqord.Core/Entities/Core/Interactions/Commands/Slash/ISlashCommandInteractionOption.cs +++ b/src/Disqord.Core/Entities/Core/Interactions/Commands/Slash/ISlashCommandInteractionOption.cs @@ -1,4 +1,5 @@ using System.Collections.Generic; +using Disqord.Serialization.Json; namespace Disqord; @@ -23,7 +24,7 @@ public interface ISlashCommandInteractionOption /// /// and are mutually exclusive. /// - object? Value { get; } + IJsonValue? Value { get; } /// /// Gets the nested options of this option. diff --git a/src/Disqord.Core/Entities/Transient/Interactions/Commands/Slash/TransientSlashCommandInteractionOption.cs b/src/Disqord.Core/Entities/Transient/Interactions/Commands/Slash/TransientSlashCommandInteractionOption.cs index b9ea32e4b..5417f8f9d 100644 --- a/src/Disqord.Core/Entities/Transient/Interactions/Commands/Slash/TransientSlashCommandInteractionOption.cs +++ b/src/Disqord.Core/Entities/Transient/Interactions/Commands/Slash/TransientSlashCommandInteractionOption.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using Disqord.Models; +using Disqord.Serialization.Json; using Qommon; using Qommon.Collections.ReadOnly; @@ -15,7 +16,7 @@ public class TransientSlashCommandInteractionOption : TransientClientEntity Model.Type; /// - public object? Value => Model.Value.GetValueOrDefault()?.ToType(); + public IJsonValue? Value => Model.Value.GetValueOrDefault(); /// public IReadOnlyDictionary Options diff --git a/src/Disqord.Core/Serialization/Json/Default/Nodes/DefaultJsonValue.cs b/src/Disqord.Core/Serialization/Json/Default/Nodes/DefaultJsonValue.cs index fd5d6cae9..d4a4174f5 100644 --- a/src/Disqord.Core/Serialization/Json/Default/Nodes/DefaultJsonValue.cs +++ b/src/Disqord.Core/Serialization/Json/Default/Nodes/DefaultJsonValue.cs @@ -15,16 +15,21 @@ public class DefaultJsonValue : DefaultJsonNode, IJsonValue /// public new JValue Token => (base.Token as JValue)!; + public JsonValueType Type => Token.Type switch + { + JTokenType.Object => JsonValueType.Object, + JTokenType.Array => JsonValueType.Array, + JTokenType.Integer or JTokenType.Float => JsonValueType.Number, + JTokenType.String or JTokenType.Date or JTokenType.Raw or JTokenType.Bytes or JTokenType.Guid or JTokenType.Uri or JTokenType.TimeSpan => JsonValueType.String, + JTokenType.Boolean when Token.Value() => JsonValueType.True, + JTokenType.Boolean when !Token.Value() => JsonValueType.False, + _ => JsonValueType.Null + }; + public DefaultJsonValue(JValue token, JsonSerializer serializer) : base(token, serializer) { } - /// - public T? GetValue() - { - return Token.Value(); - } - /// public override string ToString() { diff --git a/src/Disqord.Core/Serialization/Json/Nodes/IJsonValue.cs b/src/Disqord.Core/Serialization/Json/Nodes/IJsonValue.cs index 4519d2d6f..66ff983a5 100644 --- a/src/Disqord.Core/Serialization/Json/Nodes/IJsonValue.cs +++ b/src/Disqord.Core/Serialization/Json/Nodes/IJsonValue.cs @@ -4,4 +4,9 @@ /// Represents a JSON value node, i.e. a single JSON value. /// public interface IJsonValue : IJsonNode -{ } +{ + /// + /// Gets the type of this JSON value. + /// + JsonValueType Type { get; } +} diff --git a/src/Disqord.Core/Serialization/Json/Nodes/JsonValueType.cs b/src/Disqord.Core/Serialization/Json/Nodes/JsonValueType.cs new file mode 100644 index 000000000..ad0a614fc --- /dev/null +++ b/src/Disqord.Core/Serialization/Json/Nodes/JsonValueType.cs @@ -0,0 +1,12 @@ +namespace Disqord.Serialization.Json; + +public enum JsonValueType +{ + Null, + True, + False, + Number, + String, + Array, + Object +} diff --git a/src/Disqord.Core/Serialization/Json/STJ/Nodes/SystemJsonNode.cs b/src/Disqord.Core/Serialization/Json/STJ/Nodes/SystemJsonNode.cs index da1e99f01..4f173d4c8 100644 --- a/src/Disqord.Core/Serialization/Json/STJ/Nodes/SystemJsonNode.cs +++ b/src/Disqord.Core/Serialization/Json/STJ/Nodes/SystemJsonNode.cs @@ -33,18 +33,13 @@ private protected SystemJsonNode(JsonNode node, JsonSerializerOptions options) { try { - if (Node is JsonValue jsonValue) + var value = Node.Deserialize(Options); + if (typeof(T) != typeof(JsonElement) && value is JsonElement) { - if (jsonValue.TryGetValue(out T? value)) - { - return value; - } - - // TODO: not sure if this helps - return jsonValue.Deserialize().Deserialize(); + Throw.ArgumentException($"Cannot convert the value to type {typeof(T)}."); } - return Node.Deserialize(Options); + return value; } catch (JsonException ex) { diff --git a/src/Disqord.Core/Serialization/Json/STJ/Nodes/SystemJsonValue.cs b/src/Disqord.Core/Serialization/Json/STJ/Nodes/SystemJsonValue.cs index 3144b0385..f2fe5964e 100644 --- a/src/Disqord.Core/Serialization/Json/STJ/Nodes/SystemJsonValue.cs +++ b/src/Disqord.Core/Serialization/Json/STJ/Nodes/SystemJsonValue.cs @@ -8,21 +8,32 @@ namespace Disqord.Serialization.Json.System; /// Represents a default JSON value node. /// Wraps a . /// -[DebuggerDisplay($"{nameof(Value)}")] +[DebuggerDisplay($"{nameof(DebuggerDisplay)}")] internal sealed class SystemJsonValue : SystemJsonNode, IJsonValue { /// public new JsonValue Node => (base.Node as JsonValue)!; - private object? Value => ToType(); + public JsonValueType Type => Node.GetValueKind() switch + { + JsonValueKind.Object => JsonValueType.Object, + JsonValueKind.Array => JsonValueType.Array, + JsonValueKind.String => JsonValueType.String, + JsonValueKind.Number => JsonValueType.Number, + JsonValueKind.True => JsonValueType.True, + JsonValueKind.False => JsonValueType.False, + _ => JsonValueType.Null + }; internal SystemJsonValue(JsonValue value, JsonSerializerOptions options) : base(value, options) { } + private string DebuggerDisplay => Node.ToJsonString(Options); + /// public override string? ToString() { - return Value?.ToString(); + return Node.ToJsonString(Options); } } diff --git a/src/Disqord.Core/Serialization/Json/STJ/SystemJsonSerializer.cs b/src/Disqord.Core/Serialization/Json/STJ/SystemJsonSerializer.cs index dbd65247a..757d194cf 100644 --- a/src/Disqord.Core/Serialization/Json/STJ/SystemJsonSerializer.cs +++ b/src/Disqord.Core/Serialization/Json/STJ/SystemJsonSerializer.cs @@ -26,6 +26,7 @@ public SystemJsonSerializer() IgnoreReadOnlyProperties = true, RespectNullableAnnotations = true, NewLine = "\n", + UnknownTypeHandling = JsonUnknownTypeHandling.JsonNode, TypeInfoResolver = new JsonTypeInfoResolver(), Converters = { @@ -35,7 +36,7 @@ public SystemJsonSerializer() new OptionalConverter(), new StringConverter(), new SnowflakeConverter(), - new StreamConverter() + new StreamConverter(), } };