union Value [src]
Alias for std.json.dynamic.Value
Represents any JSON value, potentially containing other JSON values.
A .float value may be an approximation of the original value.
Arbitrary precision numbers can be represented by .number_string values.
See also std.json.ParseOptions.parse_numbers.
Fields
null
bool: bool
integer: i64
float: f64
number_string: []const u8
string: []const u8
array: Array
object: ObjectMap
Members
- dump (Function)
- jsonParse (Function)
- jsonParseFromValue (Function)
- jsonStringify (Function)
- parseFromNumberSlice (Function)
Source
pub const Value = union(enum) {
null,
bool: bool,
integer: i64,
float: f64,
number_string: []const u8,
string: []const u8,
array: Array,
object: ObjectMap,
pub fn parseFromNumberSlice(s: []const u8) Value {
if (!isNumberFormattedLikeAnInteger(s)) {
const f = std.fmt.parseFloat(f64, s) catch unreachable;
if (std.math.isFinite(f)) {
return Value{ .float = f };
} else {
return Value{ .number_string = s };
}
}
if (std.fmt.parseInt(i64, s, 10)) |i| {
return Value{ .integer = i };
} else |e| {
switch (e) {
error.Overflow => return Value{ .number_string = s },
error.InvalidCharacter => unreachable,
}
}
}
pub fn dump(self: Value) void {
std.debug.lockStdErr();
defer std.debug.unlockStdErr();
const stderr = std.io.getStdErr().writer();
stringify(self, .{}, stderr) catch return;
}
pub fn jsonStringify(value: @This(), jws: anytype) !void {
switch (value) {
.null => try jws.write(null),
.bool => |inner| try jws.write(inner),
.integer => |inner| try jws.write(inner),
.float => |inner| try jws.write(inner),
.number_string => |inner| try jws.print("{s}", .{inner}),
.string => |inner| try jws.write(inner),
.array => |inner| try jws.write(inner.items),
.object => |inner| {
try jws.beginObject();
var it = inner.iterator();
while (it.next()) |entry| {
try jws.objectField(entry.key_ptr.*);
try jws.write(entry.value_ptr.*);
}
try jws.endObject();
},
}
}
pub fn jsonParse(allocator: Allocator, source: anytype, options: ParseOptions) ParseError(@TypeOf(source.*))!@This() {
// The grammar of the stack is:
// (.array | .object .string)*
var stack = Array.init(allocator);
defer stack.deinit();
while (true) {
// Assert the stack grammar at the top of the stack.
debug.assert(stack.items.len == 0 or
stack.items[stack.items.len - 1] == .array or
(stack.items[stack.items.len - 2] == .object and stack.items[stack.items.len - 1] == .string));
switch (try source.nextAllocMax(allocator, .alloc_always, options.max_value_len.?)) {
.allocated_string => |s| {
return try handleCompleteValue(&stack, allocator, source, Value{ .string = s }, options) orelse continue;
},
.allocated_number => |slice| {
if (options.parse_numbers) {
return try handleCompleteValue(&stack, allocator, source, Value.parseFromNumberSlice(slice), options) orelse continue;
} else {
return try handleCompleteValue(&stack, allocator, source, Value{ .number_string = slice }, options) orelse continue;
}
},
.null => return try handleCompleteValue(&stack, allocator, source, .null, options) orelse continue,
.true => return try handleCompleteValue(&stack, allocator, source, Value{ .bool = true }, options) orelse continue,
.false => return try handleCompleteValue(&stack, allocator, source, Value{ .bool = false }, options) orelse continue,
.object_begin => {
switch (try source.nextAllocMax(allocator, .alloc_always, options.max_value_len.?)) {
.object_end => return try handleCompleteValue(&stack, allocator, source, Value{ .object = ObjectMap.init(allocator) }, options) orelse continue,
.allocated_string => |key| {
try stack.appendSlice(&[_]Value{
Value{ .object = ObjectMap.init(allocator) },
Value{ .string = key },
});
},
else => unreachable,
}
},
.array_begin => {
try stack.append(Value{ .array = Array.init(allocator) });
},
.array_end => return try handleCompleteValue(&stack, allocator, source, stack.pop().?, options) orelse continue,
else => unreachable,
}
}
}
pub fn jsonParseFromValue(allocator: Allocator, source: Value, options: ParseOptions) !@This() {
_ = allocator;
_ = options;
return source;
}
}