public ReadResults ReadString(out JsonString result)
        {
            result = default;
            string actualString = "";

            if (!StringReader.CanRead() || StringReader.Peek() != STRING_CHARACTER)
            {
                return(ReadResults.Failure(JsonCommandError.MalformedJson().WithContext(StringReader)));
            }
            StringReader.Skip();

            bool escaped = false;

            while (StringReader.CanRead())
            {
                char c = StringReader.Read();
                if (escaped)
                {
                    if (c == UNICODE_CHARACTER)
                    {
                        if (!StringReader.CanRead(4))
                        {
                            return(ReadResults.Failure(JsonCommandError.UnterminatedEscapeSequence().WithContext(StringReader)));
                        }
                        string unicode = StringReader.Read(4);
                        if (!short.TryParse(unicode, NumberStyles.HexNumber, NumberFormatInfo.InvariantInfo, out _))
                        {
                            return(ReadResults.Failure(JsonCommandError.InvalidUnicodeCharacter(unicode).WithContext(StringReader)));
                        }
                        escaped       = false;
                        actualString += c + unicode;
                    }
                    else if (ESCAPABLE_CHARACTERS.Contains(c))
                    {
                        escaped       = false;
                        actualString += c;
                    }
                    else
                    {
                        return(ReadResults.Failure(JsonCommandError.InvalidEscapeSequence().WithContext(StringReader)));
                    }
                }
                else if (c == ESCAPE_CHARACTER)
                {
                    escaped       = true;
                    actualString += c;
                }
                else if (c == STRING_CHARACTER)
                {
                    result = new JsonString(actualString);
                    return(ReadResults.Success());
                }
                else
                {
                    actualString += c;
                }
            }

            return(ReadResults.Failure(JsonCommandError.UnterminatedString().WithContext(StringReader)));
        }
        public ReadResults ReadObject(out JsonObject result)
        {
            result = new JsonObject();

            if (!StringReader.CanRead() || StringReader.Peek() != OBJECT_OPEN_CHARACTER)
            {
                return(ReadResults.Failure(JsonCommandError.MalformedJson()));
            }
            StringReader.Skip();

            SkipWhitespace();
            ReadResults readResults;

            while (StringReader.CanRead() && StringReader.Peek() != OBJECT_CLOSE_CHARACTER)
            {
                SkipWhitespace();
                readResults = ReadString(out JsonString name);
                if (!readResults.Successful)
                {
                    return(readResults);
                }

                SkipWhitespace();
                if (!StringReader.CanRead() || StringReader.Peek() != NAME_VALUE_SEPARATOR)
                {
                    return(ReadResults.Failure(JsonCommandError.ExpectedNameValueSeparator().WithContext(StringReader)));
                }
                StringReader.Skip();

                SkipWhitespace();
                readResults = ReadAny(out IJsonArgument argument);
                if (!readResults.Successful)
                {
                    return(readResults);
                }
                result.Add(name, argument);

                SkipWhitespace();
                if (!StringReader.CanRead() || StringReader.Peek() != ARGUMENT_SEPARATOR)
                {
                    break;
                }
                StringReader.Skip();
            }
            if (!StringReader.CanRead() || StringReader.Peek() != OBJECT_CLOSE_CHARACTER)
            {
                return(ReadResults.Failure(JsonCommandError.EndOfInput().WithContext(StringReader)));
            }
            StringReader.Skip();
            return(ReadResults.Success());
        }
        public ReadResults ReadArray(out JsonArray result)
        {
            result = new JsonArray();

            if (!StringReader.CanRead() || StringReader.Peek() != ARRAY_OPEN_CHARACTER)
            {
                return(ReadResults.Failure(JsonCommandError.MalformedJson()));
            }
            StringReader.Skip();

            SkipWhitespace();
            ReadResults readResults;

            while (StringReader.CanRead() && StringReader.Peek() != ARRAY_CLOSE_CHARACTER)
            {
                SkipWhitespace();
                readResults = ReadAny(out IJsonArgument argument);
                if (!readResults.Successful)
                {
                    return(readResults);
                }
                result.Add(argument);

                SkipWhitespace();
                if (!StringReader.CanRead() || StringReader.Peek() != ARGUMENT_SEPARATOR)
                {
                    break;
                }
                StringReader.Skip();
            }
            if (!StringReader.CanRead() || StringReader.Peek() != ARRAY_CLOSE_CHARACTER)
            {
                return(ReadResults.Failure(JsonCommandError.EndOfInput().WithContext(StringReader)));
            }
            StringReader.Skip();
            return(ReadResults.Success());
        }