diff --git a/src/LDtk.zig b/src/LDtk.zig index d125347..61c8938 100644 --- a/src/LDtk.zig +++ b/src/LDtk.zig @@ -10,87 +10,6 @@ pub fn parse(alloc: std.mem.Allocator, ldtk_file: []const u8) !Root { return Root.fromJSON(alloc, value_tree.root); } -// Utility functions -pub fn object(value_opt: ?std.json.Value) ?std.json.ObjectMap { - const value = value_opt orelse return null; - return switch (value) { - .Object => |obj| obj, - else => null, - }; -} - -pub fn array(value_opt: ?std.json.Value) ?std.json.Array { - const value = value_opt orelse return null; - return switch (value) { - .Array => |arr| arr, - else => null, - }; -} - -pub fn string(value_opt: ?std.json.Value) ?[]const u8 { - const value = value_opt orelse return null; - return switch (value) { - .String => |str| str, - else => null, - }; -} - -pub fn string_list(alloc: std.mem.Allocator, array_opt: ?std.json.Value) ![][]const u8 { - const arr = array(array_opt) orelse return &[_][]const u8{}; - var list = try std.ArrayList([]const u8).initCapacity(alloc, arr.items.len); - defer list.deinit(); - for (arr.items) |value| { - list.appendAssumeCapacity(string(value) orelse return error.InvalidString); - } - return list.toOwnedSlice(); -} - -pub fn boolean(value_opt: ?std.json.Value) ?bool { - const value = value_opt orelse return null; - return switch (value) { - .Bool => |b| b, - else => null, - }; -} - -pub fn integer(value_opt: ?std.json.Value) ?i64 { - const value = value_opt orelse return null; - return switch (value) { - .Integer => |int| int, - else => null, - }; -} - -fn float(value_opt: ?std.json.Value) ?f64 { - const value = value_opt orelse return null; - return switch (value) { - .Float => |float| float, - else => null, - }; -} - -pub fn enum_from_value(comptime T: type, value_opt: ?std.json.Value) ?T { - const value = value_opt orelse return null; - return switch (value) { - .String => |str| std.meta.stringToEnum(T, str), - else => null, - }; -} - -pub fn pos_from_value(value_opt: ?std.json.Value) ?[2]i64 { - const value = array(value_opt) orelse return null; - const x = integer(value.items[0]) orelse return null; - const y = integer(value.items[1]) orelse return null; - return [2]i64{ x, y }; -} - -pub fn posf_from_value(value_opt: ?std.json.Value) ?[2]f64 { - const value = array(value_opt) orelse return null; - const x = float(value.items[0]) orelse return null; - const y = float(value.items[1]) orelse return null; - return [2]f64{ x, y }; -} - /// 1. LDtk Json root pub const Root = struct { bgColor: []const u8, @@ -121,6 +40,16 @@ pub const Root = struct { } return ldtk_root; } + + pub fn deinit(root: Root, alloc: std.mem.Allocator) void { + if (root.defs) |defs| defs.deinit(alloc); + if (root.worlds) |worlds| { + for (worlds) |world| world.deinit(alloc); + alloc.free(worlds); + } + for (root.levels) |level| level.deinit(alloc); + alloc.free(root.levels); + } }; /// 1.1. World @@ -153,6 +82,11 @@ pub const World = struct { } return ldtk_worlds.toOwnedSlice(); } + + pub fn deinit(world: World, alloc: std.mem.Allocator) void { + for (world.levels) |level| level.deinit(alloc); + alloc.free(world.levels); + } }; pub const WorldLayout = enum { @@ -219,6 +153,15 @@ pub const Level = struct { } return ldtk_levels.toOwnedSlice(); } + + pub fn deinit(level: Level, alloc: std.mem.Allocator) void { + alloc.free(level.__neighbours); + alloc.free(level.fieldInstances); + if (level.layerInstances) |layerInstances| { + for (layerInstances) |layerInstance| layerInstance.deinit(alloc); + alloc.free(layerInstances); + } + } }; pub const Neighbour = struct { @@ -318,6 +261,15 @@ pub const LayerInstance = struct { } return ldtk_layers.toOwnedSlice(); } + + pub fn deinit(layerInstance: LayerInstance, alloc: std.mem.Allocator) void { + alloc.free(layerInstance.autoLayerTiles); + alloc.free(layerInstance.gridTiles); + for (layerInstance.entityInstances) |entityInstance| { + entityInstance.deinit(alloc); + } + alloc.free(layerInstance.entityInstances); + } }; const LayerType = enum { @@ -427,6 +379,11 @@ const EntityInstance = struct { } return ldtk_entities.toOwnedSlice(); } + + pub fn deinit(entityInstance: EntityInstance, alloc: std.mem.Allocator) void { + alloc.free(entityInstance.fieldInstances); + alloc.free(entityInstance.__tags); + } }; /// 2.4. Field Instance @@ -503,6 +460,12 @@ const Definitions = struct { levelFields: []FieldDefinition, /// All tilesets tilesets: []TilesetDefinition, + + pub fn deinit(defs: Definitions, alloc: std.mem.Allocator) void { + _ = defs; + _ = alloc; + // TODO + } }; /// 3.1. Layer definition @@ -620,3 +583,98 @@ const EnumValueDefinition = struct { id: []const u8, tileId: ?i64, }; + +// Utility functions +/// Takes std.json.Value and returns std.json.ObjectMap or null +pub fn object(value_opt: ?std.json.Value) ?std.json.ObjectMap { + const value = value_opt orelse return null; + return switch (value) { + .Object => |obj| obj, + else => null, + }; +} + +/// Takes std.json.Value and returns std.json.Array or null +pub fn array(value_opt: ?std.json.Value) ?std.json.Array { + const value = value_opt orelse return null; + return switch (value) { + .Array => |arr| arr, + else => null, + }; +} + +/// Takes std.json.Value and returns []const u8 or null +pub fn string(value_opt: ?std.json.Value) ?[]const u8 { + const value = value_opt orelse return null; + return switch (value) { + .String => |str| str, + else => null, + }; +} + +/// Takes std.json.Value and returns an error, [][]const u8, or null +pub fn string_list(alloc: std.mem.Allocator, array_opt: ?std.json.Value) ![][]const u8 { + const arr = array(array_opt) orelse return &[_][]const u8{}; + var list = try std.ArrayList([]const u8).initCapacity(alloc, arr.items.len); + defer list.deinit(); + for (arr.items) |value| { + list.appendAssumeCapacity(string(value) orelse return error.InvalidString); + } + return list.toOwnedSlice(); +} + +/// Takes std.json.Value and returns bool or null +pub fn boolean(value_opt: ?std.json.Value) ?bool { + const value = value_opt orelse return null; + return switch (value) { + .Bool => |b| b, + else => null, + }; +} + +/// Takes std.json.Value and returns i64 or null +pub fn integer(value_opt: ?std.json.Value) ?i64 { + const value = value_opt orelse return null; + return switch (value) { + .Integer => |int| int, + else => null, + }; +} + +/// Takes std.json.Value and returns f64 or null +fn float(value_opt: ?std.json.Value) ?f64 { + const value = value_opt orelse return null; + return switch (value) { + .Float => |float| float, + else => null, + }; +} + +/// Takes an enum and std.json.Value. +/// Return values: +/// - If the Value is a String it will attempt to convert it into an enum +/// - If the String is not in the enum, null is returned +/// - If the Value is not a String, null is returned +pub fn enum_from_value(comptime T: type, value_opt: ?std.json.Value) ?T { + const value = value_opt orelse return null; + return switch (value) { + .String => |str| std.meta.stringToEnum(T, str), + else => null, + }; +} + +/// Takes std.json.Value and returns [2]i64 or null +pub fn pos_from_value(value_opt: ?std.json.Value) ?[2]i64 { + const value = array(value_opt) orelse return null; + const x = integer(value.items[0]) orelse return null; + const y = integer(value.items[1]) orelse return null; + return [2]i64{ x, y }; +} + +/// Takes std.json.Value and returns [2]f64 or null +pub fn posf_from_value(value_opt: ?std.json.Value) ?[2]f64 { + const value = array(value_opt) orelse return null; + const x = float(value.items[0]) orelse return null; + const y = float(value.items[1]) orelse return null; + return [2]f64{ x, y }; +} diff --git a/src/main.zig b/src/main.zig index f3a512f..cb729d9 100644 --- a/src/main.zig +++ b/src/main.zig @@ -6,6 +6,7 @@ test "load default/empty ldtk file" { const empty_ldtk = @embedFile("test.ldtk"); const ldtk_root = try LDtk.parse(testing.allocator, empty_ldtk); + defer ldtk_root.deinit(testing.allocator); try testing.expectEqualStrings("1.1.3", ldtk_root.jsonVersion); try testing.expectEqualStrings("#40465B", ldtk_root.bgColor);