Ejemplo n.º 1
0
        // TODO: Add tests
        public static bool Skip(ref ReadOnlySpan <byte> remaining, out ReadOnlySpan <byte> skipped)
        {
            skipped = default;

            var stack        = new ResizableMemory <byte>(32);
            var currentToken = JsonTokenType.None;

            int  i       = 0;
            bool success = false;

            for (; i < remaining.Length || currentToken != JsonTokenType.None;)
            {
                // If we skipped an element and returned to the top-most level, stop skipping
                if (success && currentToken == JsonTokenType.None)
                {
                    break;
                }

                byte c = remaining[i];
                switch (c)
                {
                case (byte)' ':     // Whitespace
                case (byte)'\n':
                case (byte)'\r':
                case (byte)'\t':
                    i++;
                    continue;

                case (byte)'{':
                    i++;
                    stack.Push((byte)currentToken);
                    currentToken = JsonTokenType.StartObject;
                    break;

                case (byte)'}':
                    if (currentToken != JsonTokenType.StartObject)
                    {
                        return(false);
                    }
                    i++;
                    currentToken = (JsonTokenType)stack.Pop();
                    success      = true;
                    break;

                case (byte)'[':
                    i++;
                    stack.Push((byte)currentToken);
                    currentToken = JsonTokenType.StartArray;
                    break;

                case (byte)']':
                    if (currentToken != JsonTokenType.StartArray)
                    {
                        return(false);
                    }
                    i++;
                    currentToken = (JsonTokenType)stack.Pop();
                    success      = true;
                    break;

                case (byte)',':
                    if (currentToken != JsonTokenType.StartObject && currentToken != JsonTokenType.StartArray)
                    {
                        return(false);
                    }
                    i++;
                    break;

                case (byte)':':
                    if (currentToken != JsonTokenType.StartObject)
                    {
                        return(false);
                    }
                    i++;
                    break;

                case (byte)'n':
                    i      += 4; // ull
                    success = true;
                    break;

                case (byte)'t':
                    i      += 4; // rue
                    success = true;
                    break;

                case (byte)'f':
                    i      += 5; // alse
                    success = true;
                    break;

                case (byte)'"':
                    i++;
                    bool incomplete = true;
                    while (i < remaining.Length)
                    {
                        switch (remaining[i])
                        {
                        case (byte)'\\':
                            i += 2;         // Skip next char
                            continue;

                        case (byte)'"':
                            i++;
                            incomplete = false;
                            break;

                        default:
                            i++;
                            continue;
                        }
                        break;
                    }
                    if (incomplete)
                    {
                        return(false);
                    }
                    success = true;
                    break;

                case (byte)'-':
                case (byte)'0':
                case (byte)'1':
                case (byte)'2':
                case (byte)'3':
                case (byte)'4':
                case (byte)'5':
                case (byte)'6':
                case (byte)'7':
                case (byte)'8':
                case (byte)'9':
                    i++;
                    while (i < remaining.Length)
                    {
                        switch (remaining[i])
                        {
                        case (byte)'+':
                        case (byte)'-':
                        case (byte)'.':
                        case (byte)'0':
                        case (byte)'1':
                        case (byte)'2':
                        case (byte)'3':
                        case (byte)'4':
                        case (byte)'5':
                        case (byte)'6':
                        case (byte)'7':
                        case (byte)'8':
                        case (byte)'9':
                        case (byte)'e':
                        case (byte)'E':
                            i++;
                            continue;

                        default:         // Crossed into next token
                            break;
                        }
                        break;
                    }
                    success = true;
                    break;

                default:
                    return(false);
                }
            }

            // Incomplete object/array
            if (currentToken != JsonTokenType.None)
            {
                return(false);
            }
            skipped   = remaining.Slice(0, i);
            remaining = remaining.Slice(i);
            return(true);
        }