Zig utility library
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

fully implement `ResourcePath`

IamPyu 1b39beb3 2e3fbb3a

+126 -14
+119 -9
src/gamedev/ResourcePath.zig
··· 6 6 7 7 const Self = @This(); 8 8 9 + /// namespace delimeter 9 10 pub const namespace_delim = ':'; 11 + 12 + /// path delimeter 10 13 pub const path_delim = '/'; 11 14 12 15 pub fn isValidChar(c: u8) bool { 13 - return std.ascii.isAlphanumeric(c) || c == '_'; 16 + return std.ascii.isAlphanumeric(c) or c == '_' or c == path_delim; 14 17 } 15 18 16 19 pub fn isValidStr(s: []const u8) bool { ··· 29 32 return true; 30 33 } 31 34 32 - namespace: []const u8, 33 - path: []const u8, 35 + allocator: Allocator, 36 + namespace: []u8, 37 + path: []u8, 34 38 35 - pub fn new(id: []const u8) !?Self { 36 - const tuple = mem.splitOnce(u8, id, &.{namespace_delim}) orelse return null; 39 + /// Initialization error 40 + pub const Error = error{ 41 + /// No namespace delimeter found (:) 42 + NoNamespaceDelim, 43 + /// Invalid namespace 44 + InvalidNamespace, 45 + /// Invalid path 46 + InvalidPath, 47 + } || Allocator.Error; 37 48 38 - // TODO: should own its data. 49 + pub const SplitIterator = std.mem.SplitIterator(u8, .scalar); 50 + 51 + /// Initialize a `ResourcePath` 52 + pub fn init(allocator: Allocator, id: []const u8) Error!Self { 53 + const tuple = mem.splitOnceScalar(u8, id, namespace_delim) orelse { 54 + return Error.NoNamespaceDelim; 55 + }; 56 + 39 57 const namespace_ref = tuple.@"0"; 40 58 const path_ref = tuple.@"1"; 41 59 42 - if (!isValidStr(namespace_ref) || !isValidStr(path_ref)) { 43 - return null; 60 + if (!isValidStr(namespace_ref)) { 61 + return Error.InvalidNamespace; 44 62 } 63 + 64 + if (!isValidStr(path_ref)) { 65 + return Error.InvalidPath; 66 + } 67 + 68 + const namespace = try allocator.alloc(u8, namespace_ref.len); 69 + @memcpy(namespace, namespace_ref); 70 + const path = try allocator.alloc(u8, path_ref.len); 71 + @memcpy(path, path_ref); 72 + 73 + return Self{ 74 + .allocator = allocator, 75 + .namespace = namespace, 76 + .path = path, 77 + }; 45 78 } 46 79 47 - // TODO: not ready 80 + /// Deinitialize a `ResourcePath` 81 + pub fn deinit(self: *const Self) void { 82 + self.allocator.free(self.namespace); 83 + self.allocator.free(self.path); 84 + } 85 + 86 + /// Update the namespace to `new_namespace` 87 + pub fn setNamespace(self: *Self, new_namespace: []const u8) Error!void { 88 + if (!isValidStr(new_namespace)) { 89 + return Error.InvalidNamespace; 90 + } 91 + 92 + @memset(self.namespace, 0); 93 + self.namespace = try self.allocator.realloc(self.namespace, new_namespace.len); 94 + @memcpy(self.namespace, new_namespace); 95 + } 96 + 97 + /// Update the path to `new_path` 98 + pub fn setPath(self: *Self, new_path: []const u8) Error!void { 99 + if (!isValidStr(new_path)) { 100 + return Error.InvalidPath; 101 + } 102 + 103 + @memset(self.path, 0); 104 + self.path = try self.allocator.realloc(self.path, new_path.len); 105 + @memcpy(self.path, new_path); 106 + } 107 + 108 + /// Split the namespace by `path_delim` 109 + pub fn splitNamespace(self: *Self) SplitIterator { 110 + return std.mem.splitScalar(u8, self.namespace, path_delim); 111 + } 112 + 113 + /// Split the path by `path_delim` 114 + pub fn splitPath(self: *Self) SplitIterator { 115 + return std.mem.splitScalar(u8, self.path, path_delim); 116 + } 117 + 118 + pub fn format(self: *Self, writer: *std.Io.Writer) !void { 119 + try writer.print("{s}{s}{s}", .{ self.namespace, &.{namespace_delim}, self.path }); 120 + } 121 + 122 + test "namespace" { 123 + var id = try Self.init(std.testing.allocator, "namespace:path"); 124 + defer id.deinit(); 125 + 126 + try id.setPath("different_path"); 127 + 128 + try std.testing.expectEqualStrings("namespace", id.namespace); 129 + try std.testing.expectEqualStrings("different_path", id.path); 130 + } 131 + 132 + test "invalid_parse" { 133 + try std.testing.expectError( 134 + error.InvalidNamespace, 135 + Self.init(std.testing.allocator, ":no_namespace"), 136 + ); 137 + 138 + try std.testing.expectError( 139 + error.InvalidPath, 140 + Self.init(std.testing.allocator, "no_path:"), 141 + ); 142 + 143 + try std.testing.expectError( 144 + error.InvalidPath, 145 + Self.init(std.testing.allocator, "ns:invalid-path"), 146 + ); 147 + } 148 + 149 + test "split" { 150 + var id = try Self.init(std.testing.allocator, "ns:rather/long/path"); 151 + defer id.deinit(); 152 + 153 + var split = id.splitPath(); 154 + while (split.next()) |s| { 155 + std.debug.print("{s}\n", .{s}); 156 + } 157 + }
+2
src/gamedev/root.zig
··· 1 1 pub const tick = @import("./tick.zig"); 2 + pub const ResourcePath = @import("./ResourcePath.zig"); 2 3 3 4 test { 4 5 _ = tick; 6 + _ = ResourcePath; 5 7 }
+5 -5
src/gamedev/tick.zig
··· 16 16 const Self = @This(); 17 17 18 18 /// Unit tick, equivelant to `1t` 19 - pub const single_tick = Self.new(1); 19 + pub const single_tick = Self.init(1); 20 20 21 21 /// Create a `Tick` of `n` ticks 22 - pub fn new(n: usize) Self { 22 + pub fn init(n: usize) Self { 23 23 return .{ ._inner = n }; 24 24 } 25 25 26 26 /// Create a `Tick` from milliseconds 27 27 pub fn fromMillis(ms: u64) Self { 28 - return Self.new(ms / MS); 28 + return Self.init(ms / MS); 29 29 } 30 30 31 31 /// Convert `self` to milliseconds ··· 52 52 pub const Tick25 = Tick(25); 53 53 54 54 test "millis" { 55 - const t = Tick50.new(5); 55 + const t = Tick50.init(5); 56 56 try std.testing.expectEqual(t.asMillis(), 250); 57 57 } 58 58 59 59 test "sleep" { 60 - const t = Tick25.new(5); 60 + const t = Tick25.init(5); 61 61 t.sleep(); 62 62 }