|
|
@ -54,6 +54,31 @@ pub const Path = struct { |
|
|
|
pub var default = flecs_c; |
|
|
|
pub var default = flecs_c; |
|
|
|
}; |
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// Creates an array of `EntityPath`s with known size equal to the number of |
|
|
|
|
|
|
|
/// elements in the specified tuple argument. Each element of the tuple is |
|
|
|
|
|
|
|
/// either converted to a `.name` part, or an `.id` part. |
|
|
|
|
|
|
|
/// |
|
|
|
|
|
|
|
/// Keep in mind the mutability and lifetime of the string elements passed |
|
|
|
|
|
|
|
/// 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 |
|
|
|
|
|
|
|
/// is not the case, it's recommended to `.clone()` the path after creation. |
|
|
|
|
|
|
|
pub fn buildParts(parts: anytype) t: { |
|
|
|
|
|
|
|
if (!std.meta.trait.isTuple(@TypeOf(parts))) |
|
|
|
|
|
|
|
@compileError("Expected tuple, got '" ++ @typeName(@TypeOf(parts)) ++ "'"); |
|
|
|
|
|
|
|
const len = @typeInfo(@TypeOf(parts)).Struct.fields.len; |
|
|
|
|
|
|
|
break :t [len]EntityPart; |
|
|
|
|
|
|
|
} { |
|
|
|
|
|
|
|
const len = @typeInfo(@TypeOf(parts)).Struct.fields.len; |
|
|
|
|
|
|
|
var result: [len]EntityPart = undefined; |
|
|
|
|
|
|
|
inline for (&result, parts) |*res, part| |
|
|
|
|
|
|
|
res.* = switch (@TypeOf(part)) { |
|
|
|
|
|
|
|
[]u8, []const u8 => |name| .{ .name = name }, |
|
|
|
|
|
|
|
u32, comptime_int => |id| .{ .id = id }, |
|
|
|
|
|
|
|
else => @compileError("Expected []u8, []const u8, u32 or comptime_int, got '" ++ @typeName(@TypeOf(part)) ++ "'"), |
|
|
|
|
|
|
|
}; |
|
|
|
|
|
|
|
return result; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/// Creates a new `Path` from the specified string parts. |
|
|
|
/// Creates a new `Path` from the specified string parts. |
|
|
|
/// |
|
|
|
/// |
|
|
|
/// The resulting path does not own any of the given slices. |
|
|
|
/// The resulting path does not own any of the given slices. |
|
|
@ -287,8 +312,22 @@ test Path { |
|
|
|
// Alternatively they can be made by specifying the individual component |
|
|
|
// Alternatively they can be made by specifying the individual component |
|
|
|
// parts they're made of, as well as an argument specifying whether it's |
|
|
|
// parts they're made of, as well as an argument specifying whether it's |
|
|
|
// an absolute path. |
|
|
|
// an absolute path. |
|
|
|
const absolute1 = try Path.fromParts(true, &.{ .{ .name = "I'm" }, .{ .name = "absolute!" } }); |
|
|
|
// To do this you can use the `buildParts` helper function, which is less |
|
|
|
// No need for `deinit()`, does not own outer array nor inner string parts. |
|
|
|
// wordy than building `EntityPart` structs manually. |
|
|
|
|
|
|
|
const absolute1_parts = Path.buildParts(.{ "I'm", "absolute!" }); |
|
|
|
|
|
|
|
const absolute1 = try Path.fromParts(true, &absolute1_parts); |
|
|
|
|
|
|
|
// No need to call `deinit()`. The path does not own the `absolute1_parts` |
|
|
|
|
|
|
|
// array nor the string parts, which in this case are comptime constants. |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// When handling paths, always be aware of the lifetime of its array and |
|
|
|
|
|
|
|
// any string parts contained within it. This API allows you to completely |
|
|
|
|
|
|
|
// avoid allocation if you know what you are doing. |
|
|
|
|
|
|
|
// In the above example, `absolute_parts` is an array allocated onto the |
|
|
|
|
|
|
|
// stack, and as such will only be valid until the end of the scope. This |
|
|
|
|
|
|
|
// means no allocation is necessary, but it also means `absolute1` is only |
|
|
|
|
|
|
|
// valid for as long as its parts. |
|
|
|
|
|
|
|
// If a path instance is not immediately consumed and you're uncertain |
|
|
|
|
|
|
|
// about the lifetime of its parts, consider using `.clone(alloc)`. |
|
|
|
|
|
|
|
|
|
|
|
// With `options` unspecified, it's not possible to represent an absolute |
|
|
|
// With `options` unspecified, it's not possible to represent an absolute |
|
|
|
// path using a string. Pass your own `FormatOptions` to be able to. |
|
|
|
// path using a string. Pass your own `FormatOptions` to be able to. |
|
|
@ -309,12 +348,19 @@ test Path { |
|
|
|
try expectEqualStrings("path", relative.parts[2].name); |
|
|
|
try expectEqualStrings("path", relative.parts[2].name); |
|
|
|
|
|
|
|
|
|
|
|
// Parts can also be numeric ids, used for entities that don't have a name. |
|
|
|
// Parts can also be numeric ids, used for entities that don't have a name. |
|
|
|
const numeric = try Path.fromString("100.101.bar", null, alloc); |
|
|
|
const numeric1 = try Path.fromString("100.101.bar", null, alloc); |
|
|
|
defer numeric.deinit(); |
|
|
|
defer numeric1.deinit(); |
|
|
|
try expectEqual(@as(usize, 3), numeric.parts.len); |
|
|
|
try expectEqual(@as(usize, 3), numeric1.parts.len); |
|
|
|
try expectEqual(@as(u32, 100), numeric.parts[0].id); |
|
|
|
try expectEqual(@as(u32, 100), numeric1.parts[0].id); |
|
|
|
try expectEqual(@as(u32, 101), numeric.parts[1].id); |
|
|
|
try expectEqual(@as(u32, 101), numeric1.parts[1].id); |
|
|
|
try expectEqualStrings("bar", numeric.parts[2].name); |
|
|
|
try expectEqualStrings("bar", numeric1.parts[2].name); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Numeric ids can also be passed to `buildParts`. |
|
|
|
|
|
|
|
const numeric2_parts = Path.buildParts(.{ 100, 101, "bar" }); |
|
|
|
|
|
|
|
const numeric2 = try Path.fromParts(false, &numeric2_parts); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// TODO: Let's check numeric1 and numeric2 for equality here. |
|
|
|
|
|
|
|
_ = numeric2; |
|
|
|
|
|
|
|
|
|
|
|
// Paths are formattable. As format specifier you can use options defined |
|
|
|
// Paths are formattable. As format specifier you can use options defined |
|
|
|
// on the `FormatOptions` type, or an empty string to use the default. |
|
|
|
// on the `FormatOptions` type, or an empty string to use the default. |
|
|
|