// 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); }