Type Function Reader [src]

Alias for std.json.scanner.Reader

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

Prototype

pub fn Reader(comptime buffer_size: usize, comptime ReaderType: type) type

Parameters

buffer_size: usizeReaderType: type

Source

pub fn Reader(comptime buffer_size: usize, comptime ReaderType: type) type { return struct { scanner: Scanner, reader: ReaderType, buffer: [buffer_size]u8 = undefined, /// The allocator is only used to track `[]` and `{}` nesting levels. pub fn init(allocator: Allocator, io_reader: ReaderType) @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 = ReaderType.Error || Error || Allocator.Error; pub const SkipError = NextError; pub const AllocError = NextError || error{ValueTooLong}; pub const PeekError = ReaderType.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) 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) AllocError!Token { const token_type = try self.peekNextTokenType(); switch (token_type) { .number, .string => { var value_list = ArrayList(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: *ArrayList(u8), when: AllocWhen) 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: *ArrayList(u8), when: AllocWhen, max_value_len: usize) 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()) 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) 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()) 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()) 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()) ReaderType.Error!void { const input = self.buffer[0..try self.reader.read(self.buffer[0..])]; if (input.len > 0) { self.scanner.feedInput(input); } else { self.scanner.endInput(); } } }; }