struct Reader [src]

All next*() methods here handle error.BufferUnderrun from std.json.Scanner, and then read from the reader.

Fields

scanner: Scanner
reader: *std.Io.Reader

Members

Source

pub const Reader = struct { scanner: Scanner, reader: *std.Io.Reader, /// The allocator is only used to track `[]` and `{}` nesting levels. pub fn init(allocator: Allocator, io_reader: *std.Io.Reader) @This() { return .{ .scanner = Scanner.initStreaming(allocator), .reader = io_reader, }; } pub fn deinit(self: *@This()) void { self.scanner.deinit(); self.* = undefined; } /// Calls `std.json.Scanner.enableDiagnostics`. pub fn enableDiagnostics(self: *@This(), diagnostics: *Diagnostics) void { self.scanner.enableDiagnostics(diagnostics); } pub const NextError = std.Io.Reader.Error || Error || Allocator.Error; pub const SkipError = Reader.NextError; pub const AllocError = Reader.NextError || error{ValueTooLong}; pub const PeekError = std.Io.Reader.Error || Error; /// Equivalent to `nextAllocMax(allocator, when, default_max_value_len);` /// See also `std.json.Token` for documentation of `nextAlloc*()` function behavior. pub fn nextAlloc(self: *@This(), allocator: Allocator, when: AllocWhen) Reader.AllocError!Token { return self.nextAllocMax(allocator, when, default_max_value_len); } /// See also `std.json.Token` for documentation of `nextAlloc*()` function behavior. pub fn nextAllocMax(self: *@This(), allocator: Allocator, when: AllocWhen, max_value_len: usize) Reader.AllocError!Token { const token_type = try self.peekNextTokenType(); switch (token_type) { .number, .string => { var value_list = std.array_list.Managed(u8).init(allocator); errdefer { value_list.deinit(); } if (try self.allocNextIntoArrayListMax(&value_list, when, max_value_len)) |slice| { return if (token_type == .number) Token{ .number = slice } else Token{ .string = slice }; } else { return if (token_type == .number) Token{ .allocated_number = try value_list.toOwnedSlice() } else Token{ .allocated_string = try value_list.toOwnedSlice() }; } }, // Simple tokens never alloc. .object_begin, .object_end, .array_begin, .array_end, .true, .false, .null, .end_of_document, => return try self.next(), } } /// Equivalent to `allocNextIntoArrayListMax(value_list, when, default_max_value_len);` pub fn allocNextIntoArrayList(self: *@This(), value_list: *std.array_list.Managed(u8), when: AllocWhen) Reader.AllocError!?[]const u8 { return self.allocNextIntoArrayListMax(value_list, when, default_max_value_len); } /// Calls `std.json.Scanner.allocNextIntoArrayListMax` and handles `error.BufferUnderrun`. pub fn allocNextIntoArrayListMax(self: *@This(), value_list: *std.array_list.Managed(u8), when: AllocWhen, max_value_len: usize) Reader.AllocError!?[]const u8 { while (true) { return self.scanner.allocNextIntoArrayListMax(value_list, when, max_value_len) catch |err| switch (err) { error.BufferUnderrun => { try self.refillBuffer(); continue; }, else => |other_err| return other_err, }; } } /// Like `std.json.Scanner.skipValue`, but handles `error.BufferUnderrun`. pub fn skipValue(self: *@This()) Reader.SkipError!void { switch (try self.peekNextTokenType()) { .object_begin, .array_begin => { try self.skipUntilStackHeight(self.stackHeight()); }, .number, .string => { while (true) { switch (try self.next()) { .partial_number, .partial_string, .partial_string_escaped_1, .partial_string_escaped_2, .partial_string_escaped_3, .partial_string_escaped_4, => continue, .number, .string => break, else => unreachable, } } }, .true, .false, .null => { _ = try self.next(); }, .object_end, .array_end, .end_of_document => unreachable, // Attempt to skip a non-value token. } } /// Like `std.json.Scanner.skipUntilStackHeight()` but handles `error.BufferUnderrun`. pub fn skipUntilStackHeight(self: *@This(), terminal_stack_height: usize) Reader.NextError!void { while (true) { return self.scanner.skipUntilStackHeight(terminal_stack_height) catch |err| switch (err) { error.BufferUnderrun => { try self.refillBuffer(); continue; }, else => |other_err| return other_err, }; } } /// Calls `std.json.Scanner.stackHeight`. pub fn stackHeight(self: *const @This()) usize { return self.scanner.stackHeight(); } /// Calls `std.json.Scanner.ensureTotalStackCapacity`. pub fn ensureTotalStackCapacity(self: *@This(), height: usize) Allocator.Error!void { try self.scanner.ensureTotalStackCapacity(height); } /// See `std.json.Token` for documentation of this function. pub fn next(self: *@This()) Reader.NextError!Token { while (true) { return self.scanner.next() catch |err| switch (err) { error.BufferUnderrun => { try self.refillBuffer(); continue; }, else => |other_err| return other_err, }; } } /// See `std.json.Scanner.peekNextTokenType()`. pub fn peekNextTokenType(self: *@This()) Reader.PeekError!TokenType { while (true) { return self.scanner.peekNextTokenType() catch |err| switch (err) { error.BufferUnderrun => { try self.refillBuffer(); continue; }, else => |other_err| return other_err, }; } } fn refillBuffer(self: *@This()) std.Io.Reader.Error!void { const input = self.reader.peekGreedy(1) catch |err| switch (err) { error.ReadFailed => return error.ReadFailed, error.EndOfStream => return self.scanner.endInput(), }; self.reader.toss(input.len); self.scanner.feedInput(input); } }