https://github.com/tomboddaert/meta_match
A zig module to match types
https://github.com/tomboddaert/meta_match
metaprogramming types zig ziglang
Last synced: 10 months ago
JSON representation
A zig module to match types
- Host: GitHub
- URL: https://github.com/tomboddaert/meta_match
- Owner: tomBoddaert
- Created: 2024-01-01T18:25:12.000Z (over 2 years ago)
- Default Branch: main
- Last Pushed: 2024-05-17T00:37:01.000Z (about 2 years ago)
- Last Synced: 2025-02-28T14:09:01.666Z (over 1 year ago)
- Topics: metaprogramming, types, zig, ziglang
- Language: Zig
- Homepage: https://tomboddaert.com/meta_match/
- Size: 3.9 MB
- Stars: 0
- Watchers: 1
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
Awesome Lists containing this project
README
# meta_match
`meta_match` is a [zig](https://ziglang.org/) module that can match types for you!
It is designed to assist with meta-programming of things like interfaces.
## Adding meta_match to your project
Run
```sh
zig fetch --save https://github.com/tomBoddaert/meta_match/archive/{commit}.tar.gz
```
Where `{commit}` is replaced with the commit (e.g. `4129996211edd30b25c23454520fd78b2a70394b`).
## Example: go-like interfaces
Interfaces in go are implemented implicitly, this means that any type that has the required
functions and fields.
```zig
/// An interface for deinitialising.
///
/// If the type does not have a `deinit` function, the `deinit` function
/// does nothing.
pub fn Deinit(comptime T: type) type {
return struct {
// This matches a compatable 'deinit' function
const DeinitMatch = TypeMatch{
.Fn = &FnMatch{
// Only accept zig and C functions
.calling_convention = .{ .options = &.{ .Unspecified, .C, .Inline } },
// Don't accept C variadic functions
.is_var_args = false,
// It must return void
.return_type = TypeMatch{ .Void = {} },
.params = &.{
// It must have a single pointer parameter
// Note that the 'constness' of this pointer is not specified,
// so functions that take '*const T' will also be accepted.
ParamMatch{
.type = TypeMatch{
.Pointer = &PointerMatch{
// The pointer must point to one value
.size = .{ .options = &.{Type.Pointer.Size.One} },
// It must not be volatile
.is_volatile = false,
// It must be pointing to a 'T'
.child = TypeMatch{ .by_type = T },
// It must not have a sentinel
// Note that if this was just 'null', meta_match would not
// check it.
.sentinel = @as(?*const anyopaque, null),
},
},
},
},
},
};
/// The MetaMatch expression used to determine 'has_deinit'.
pub const MetaMatch = TypeMatch{
.container = &ContainerMatch{
// It must be a container with a 'deinit' declaration matching 'DeinitMatch' above
.decls = &.{DeclarationMatch{ .name = "deinit", .type = DeinitMatch }},
},
};
/// `true` if `T` has a `deinit` function.
pub const has_deinit: bool = MetaMatch.match(T);
/// Deinitialise a value.
pub inline fn deinit(value: *T) void {
if (has_deinit) {
T.deinit(value);
}
}
};
}
test {
try testing.expect(!Deinit(u8).has_deinit);
var n: u8 = 5;
// This will do nothing
Deinit(u8).deinit(&n);
const S = struct {
pub fn deinit(_: *@This()) void {}
};
try testing.expect(Deinit(S).has_deinit);
var s = S{};
// This will run the deinit function
Deinit(S).deinit(&s);
}
```
In this example, if 'deinit' is called with a type that does not have a 'deinit' function, nothing happens but
you could add a compile error, or you could run a default function.
If 'deinit' is run with a type that does have a matching 'deinit' function, then the type's 'deinit' function is called.