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