209 lines
6.4 KiB
Zig
209 lines
6.4 KiB
Zig
pub const c = @cImport({
|
|
@cInclude("json.h");
|
|
});
|
|
const std = @import("std");
|
|
|
|
const Type = enum(c.json_type) {
|
|
null = c.json_type_null,
|
|
boolean = c.json_type_boolean,
|
|
double = c.json_type_double,
|
|
int = c.json_type_int,
|
|
object = c.json_type_object,
|
|
array = c.json_type_array,
|
|
string = c.json_type_string,
|
|
};
|
|
|
|
pub const Obj = struct {
|
|
// Option because a null value is treated as the C value NULL in json-c
|
|
obj: ?*c.json_object,
|
|
|
|
///////////////////////////////////
|
|
// ** Object creation **
|
|
/////////////////////////////////
|
|
|
|
pub fn newObject() Obj {
|
|
return Obj{ .obj = c.json_object_new_object().? };
|
|
}
|
|
pub fn newArray() Obj {
|
|
return Obj{ .obj = c.json_object_new_array().? };
|
|
}
|
|
pub fn newString(s: [*c]const u8) Obj {
|
|
return Obj{ .obj = c.json_object_new_string(s).? };
|
|
}
|
|
pub fn newInt32(i: i32) Obj {
|
|
return Obj{ .obj = c.json_object_new_int(i).? };
|
|
}
|
|
pub fn newInt64(i: i64) Obj {
|
|
return Obj{ .obj = c.json_object_new_int64(i).? };
|
|
}
|
|
pub fn newFromString(s: [*c]const u8) !Obj {
|
|
const FromStringError = error{
|
|
MalformedString,
|
|
};
|
|
|
|
return Obj{
|
|
.obj = c.json_tokener_parse(s) orelse return FromStringError.MalformedString,
|
|
};
|
|
}
|
|
|
|
pub fn deinit(self: *Obj) void {
|
|
_ = c.json_object_put(self.obj);
|
|
}
|
|
|
|
///////////////////////////////////
|
|
// ** General functions **
|
|
/////////////////////////////////
|
|
|
|
const TypeError = error{
|
|
TypeMismatch, // Tried to use a function on the wrong JSON format
|
|
};
|
|
|
|
pub fn getType(self: Obj) Type {
|
|
//std.debug.print("{}\n", .{c.json_object_get_type(self.obj)});
|
|
return @intToEnum(Type, c.json_object_get_type(self.obj));
|
|
}
|
|
|
|
// Not *const Obj because the json_object retains ownership of the string
|
|
pub fn toString(self: *const Obj) []const u8 {
|
|
// TODO: Allow passing of flags as an enum like the SDL2 binding
|
|
return std.mem.sliceTo(c.json_object_to_json_string(self.obj), 0);
|
|
}
|
|
|
|
///////////////////////////////////
|
|
// ** Getters **
|
|
/////////////////////////////////
|
|
|
|
// Not *const Obj because the json_object retains ownership of the string
|
|
pub fn getString(self: *const Obj) []const u8 {
|
|
// TODO: Check type to not allow other types
|
|
return std.mem.sliceTo(c.json_object_get_string(self.obj), 0);
|
|
}
|
|
pub fn getInt64(self: Obj) i64 {
|
|
// TODO: Check ERRNO to see if there was an error
|
|
return c.json_object_get_int64(self.obj);
|
|
}
|
|
|
|
///////////////////////////////////
|
|
// ** Object functions **
|
|
/////////////////////////////////
|
|
|
|
const GetError = error {
|
|
TypeMismatch, // Not an object/array
|
|
KeyNotFound, // Key or ID not present in the object/array
|
|
};
|
|
|
|
pub fn objectGet(self: *const Obj, key: [*c]const u8) GetError!Obj {
|
|
// TODO: Check type and null return as errors
|
|
var obj: ?*c.json_object = undefined;
|
|
const succ = c.json_object_object_get_ex(self.obj, key, &obj);
|
|
|
|
// Everything went alright
|
|
if (obj) |ret| {
|
|
return Obj{ .obj = c.json_object_get(ret).? };
|
|
} else if (obj == null and succ != 0) {
|
|
// The actual value is just null
|
|
return Obj{ .obj = null };
|
|
} else if (self.getType() != Type.object) {
|
|
return GetError.TypeMismatch;
|
|
} else {
|
|
return GetError.KeyNotFound;
|
|
}
|
|
}
|
|
|
|
pub fn objectAdd(self: *Obj, key: [*c]const u8, value: ?*const Obj) void {
|
|
// TODO: Check type and error return
|
|
|
|
// We need the json-c object or null, not the zig object
|
|
const o = if (value) |i| i.obj else null;
|
|
|
|
_ = c.json_object_object_add(self.obj, key, o);
|
|
}
|
|
|
|
pub fn objectAddString(self: *Obj, key: [*c]const u8, value: [*c]const u8) void {
|
|
_ = c.json_object_object_add(self.obj, key, newString(value).obj);
|
|
}
|
|
|
|
pub fn objectLen(self: *const Obj) c_int {
|
|
return c.json_object_object_length(self.obj);
|
|
}
|
|
|
|
pub fn objectGetIterator(self: *Obj) ObjectIterator {
|
|
// TODO: Check errors and check it is a JSON Object
|
|
return ObjectIterator{
|
|
.it = c.json_object_iter_begin(self.obj),
|
|
.end = c.json_object_iter_end(self.obj),
|
|
};
|
|
}
|
|
|
|
pub const ObjectIterator = struct {
|
|
it: c.json_object_iterator,
|
|
end: c.json_object_iterator,
|
|
|
|
const ReturnType = struct {
|
|
key: []const u8,
|
|
value: ?Obj,
|
|
};
|
|
|
|
// These function's names are way too long ._.
|
|
const step = c.json_object_iter_next;
|
|
const equal = c.json_object_iter_equal;
|
|
const peekName = c.json_object_iter_peek_name;
|
|
const peekValue = c.json_object_iter_peek_value;
|
|
|
|
/// Step the iterator. The owner mustn't call deinit() on the returned value.
|
|
pub fn next(self: *ObjectIterator) ?ReturnType {
|
|
const it = &self.it;
|
|
const end = &self.end;
|
|
|
|
// Reached the end
|
|
if (equal(it, end) != 0) return null;
|
|
|
|
defer step(it);
|
|
|
|
return ReturnType{
|
|
.key = std.mem.sliceTo(peekName(it), 0),
|
|
.value = if (peekValue(it)) |val| Obj{ .obj = val } else null,
|
|
};
|
|
}
|
|
};
|
|
|
|
///////////////////////////////////
|
|
// ** Array functions **
|
|
/////////////////////////////////
|
|
|
|
pub fn arrayAdd(self: *Obj, value: ?*const Obj) void {
|
|
// TODO: Check type and error return
|
|
|
|
// We need the json-c object or null, not the zig object
|
|
const o = if (value) |i| i.obj else null;
|
|
_ = c.json_object_array_add(self.obj, o);
|
|
}
|
|
|
|
pub fn arrayLen(self: Obj) usize {
|
|
return c.json_object_array_length(self.obj);
|
|
}
|
|
|
|
pub fn arrayGet(self: *const Obj, idx: usize) ?Obj {
|
|
// Sould the .? be there?
|
|
if (c.json_object_array_get_idx(self.obj, idx)) |obj| {
|
|
return Obj{ .obj = c.json_object_get(obj).? };
|
|
} else {
|
|
return null;
|
|
}
|
|
}
|
|
|
|
pub fn arrayGetIterator(self: *const Obj) ArrayIterator {
|
|
return ArrayIterator{ .obj = self, .idx = 0 };
|
|
}
|
|
|
|
pub const ArrayIterator = struct {
|
|
obj: *const Obj,
|
|
idx: usize = 0,
|
|
|
|
pub fn next(self: *ArrayIterator) ?Obj {
|
|
defer self.idx += 1;
|
|
return self.obj.arrayGet(self.idx);
|
|
}
|
|
};
|
|
};
|