|
|
@ -24,7 +24,7 @@ pub const Path = struct { |
|
|
|
/// Represents an `Entity` in a `Path`, either by name or its numeric id. |
|
|
|
/// Represents an `Entity` in a `Path`, either by name or its numeric id. |
|
|
|
pub const EntityPart = union(enum) { |
|
|
|
pub const EntityPart = union(enum) { |
|
|
|
id: u32, |
|
|
|
id: u32, |
|
|
|
name: []const u8, |
|
|
|
name: [:0]const u8, |
|
|
|
}; |
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
/// Format used to parse and stringify `Path`s. |
|
|
|
/// Format used to parse and stringify `Path`s. |
|
|
@ -62,32 +62,29 @@ pub const Path = struct { |
|
|
|
/// to this function, as they aren't cloned and ownership stays the same. |
|
|
|
/// to this function, as they aren't cloned and ownership stays the same. |
|
|
|
/// In many cases, the lifetime of `Path`s is relatively short. When this |
|
|
|
/// In many cases, the lifetime of `Path`s is relatively short. When this |
|
|
|
/// is not the case, it's recommended to `.clone()` the path after creation. |
|
|
|
/// is not the case, it's recommended to `.clone()` the path after creation. |
|
|
|
pub fn buildParts(parts: anytype) t: { |
|
|
|
pub fn buildParts(parts: anytype) [numElements(parts)]EntityPart { |
|
|
|
if (!std.meta.trait.isTuple(@TypeOf(parts))) |
|
|
|
if (comptime !std.meta.trait.isTuple(@TypeOf(parts))) |
|
|
|
@compileError("Expected tuple, got '" ++ @typeName(@TypeOf(parts)) ++ "'"); |
|
|
|
@compileError("Expected tuple, got '" ++ @typeName(@TypeOf(parts)) ++ "'"); |
|
|
|
const len = @typeInfo(@TypeOf(parts)).Struct.fields.len; |
|
|
|
var result: [numElements(parts)]EntityPart = undefined; |
|
|
|
break :t [len]EntityPart; |
|
|
|
|
|
|
|
} { |
|
|
|
|
|
|
|
const len = @typeInfo(@TypeOf(parts)).Struct.fields.len; |
|
|
|
|
|
|
|
var result: [len]EntityPart = undefined; |
|
|
|
|
|
|
|
inline for (&result, parts) |*res, part| { |
|
|
|
inline for (&result, parts) |*res, part| { |
|
|
|
const msg = "Expected '[]const u8' or 'u32', got '" ++ @typeName(@TypeOf(part)) ++ "'"; |
|
|
|
res.* = if (comptime std.meta.trait.isZigString(@TypeOf(part))) |
|
|
|
res.* = switch (@typeInfo(@TypeOf(part))) { |
|
|
|
.{ .name = part } |
|
|
|
.Pointer => |p| switch (p.size) { |
|
|
|
else switch (@typeInfo(@TypeOf(part))) { |
|
|
|
.One => switch (@typeInfo(p.child)) { |
|
|
|
|
|
|
|
.Array => |a| if (a.child == u8) .{ .name = part } else @compileError(msg), |
|
|
|
|
|
|
|
else => @compileError(msg), |
|
|
|
|
|
|
|
}, |
|
|
|
|
|
|
|
.Slice => if (p.child == u8) .{ .name = part } else @compileError(msg), |
|
|
|
|
|
|
|
else => @compileError(msg), |
|
|
|
|
|
|
|
}, |
|
|
|
|
|
|
|
.Int, .ComptimeInt => .{ .id = part }, |
|
|
|
.Int, .ComptimeInt => .{ .id = part }, |
|
|
|
else => @compileError(msg), |
|
|
|
else => @compileError("Expected '[:0]const u8' or 'u32', got '" ++ @typeName(@TypeOf(part)) ++ "'"), |
|
|
|
}; |
|
|
|
}; |
|
|
|
} |
|
|
|
} |
|
|
|
return result; |
|
|
|
return result; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// Returns the number of elements of the specified tuple type. |
|
|
|
|
|
|
|
fn numElements(parts: anytype) usize { |
|
|
|
|
|
|
|
return if (comptime std.meta.trait.isTuple(@TypeOf(parts))) |
|
|
|
|
|
|
|
@typeInfo(@TypeOf(parts)).Struct.fields.len |
|
|
|
|
|
|
|
else |
|
|
|
|
|
|
|
0; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/// Creates a new `Path` from the specified parts. |
|
|
|
/// Creates a new `Path` from the specified parts. |
|
|
|
/// |
|
|
|
/// |
|
|
|
/// The resulting path does not own any of the given slices. |
|
|
|
/// The resulting path does not own any of the given slices. |
|
|
@ -103,8 +100,9 @@ pub const Path = struct { |
|
|
|
/// resulting path will be absolute. The rest of the string will be split |
|
|
|
/// resulting path will be absolute. The rest of the string will be split |
|
|
|
/// by the specified seperator, becoming its parts. |
|
|
|
/// by the specified seperator, becoming its parts. |
|
|
|
/// |
|
|
|
/// |
|
|
|
/// The parts array will be allocated with the specified `Allocator` and is |
|
|
|
/// This function will allocate duplicate strings taken from the specified |
|
|
|
/// owned by the resulting path. `deinit()` must be called to free it. |
|
|
|
/// source `path`, to ensure they are sentinel-terminated. The resulting |
|
|
|
|
|
|
|
/// `Path` takes ownership of these. |
|
|
|
pub fn fromString(path: []const u8, options: ?FormatOptions, alloc: Allocator) !Path { |
|
|
|
pub fn fromString(path: []const u8, options: ?FormatOptions, alloc: Allocator) !Path { |
|
|
|
if (path.len == 0) return error.MustNotBeEmpty; |
|
|
|
if (path.len == 0) return error.MustNotBeEmpty; |
|
|
|
const opt = options orelse FormatOptions.default; |
|
|
|
const opt = options orelse FormatOptions.default; |
|
|
@ -129,13 +127,14 @@ pub const Path = struct { |
|
|
|
parts[i] = if (parseNumericId(str)) |id| |
|
|
|
parts[i] = if (parseNumericId(str)) |id| |
|
|
|
.{ .id = id } |
|
|
|
.{ .id = id } |
|
|
|
else |
|
|
|
else |
|
|
|
.{ .name = str }; |
|
|
|
.{ .name = try alloc.dupeZ(u8, str) }; |
|
|
|
|
|
|
|
|
|
|
|
return .{ |
|
|
|
return .{ |
|
|
|
.absolute = absolute, |
|
|
|
.absolute = absolute, |
|
|
|
.parts = parts, |
|
|
|
.parts = parts, |
|
|
|
.alloc = alloc, |
|
|
|
.alloc = alloc, |
|
|
|
.owns_array = true, |
|
|
|
.owns_array = true, |
|
|
|
|
|
|
|
.owns_parts = true, |
|
|
|
}; |
|
|
|
}; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
@ -202,7 +201,7 @@ pub const Path = struct { |
|
|
|
|
|
|
|
|
|
|
|
for (parts) |*part| { |
|
|
|
for (parts) |*part| { |
|
|
|
if (part.* == .name) |
|
|
|
if (part.* == .name) |
|
|
|
part.* = .{ .name = try alloc.dupe(u8, part.name) }; |
|
|
|
part.* = .{ .name = try alloc.dupeZ(u8, part.name) }; |
|
|
|
num_allocated += 1; |
|
|
|
num_allocated += 1; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|