Skip to content

A reflection library in Zig with utilities covering change detection and interface validation and vtable generation using real structs.

License

Notifications You must be signed in to change notification settings

captkirk88/zevy-reflect

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

77 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

zevy-reflect

A lightweight reflection and change detection library for Zig.

Zig Version

Features

  • Runtime Type Information: Get detailed type information at runtime including fields, functions, and nested types
  • Interface Validation: Compile-time validation of interface implementations with clear error messages
    • VTable Generation: Create vtables for dynamic dispatch based on interfaces, with support for interface extension. Tested using std.mem.Allocation.VTable interface.
  • Change Detection: Track changes to struct fields with minimal memory overhead (8 bytes)
  • Zero Dependencies: Pure Zig implementation with no external dependencies

Installation

Add to your build.zig.zon:

zig fetch --save git+https://github.com/captkirk88/zevy-reflect

Then in your build.zig:

const zevy_reflect = b.dependency("zevy_reflect", .{
    .branch_quota = 20000, // Optional: increase eval branch quota for complex reflection (default: 10000)
});
exe.root_module.addImport("zevy_reflect", zevy_reflect.module("zevy_reflect"));

Quick Start

Reflection

This library provides both lightweight (shallow) runtime TypeInfo and a small set of helpers to query type structure without blowing up comptime.

const reflect = @import("zevy_reflect");
const std = @import("std");

const MyStruct = struct {
    id: u32,
    name: []const u8,
    active: bool,

    pub fn getId(self: @This()) u32 { return self.id; }
};

comptime {
    const info = reflect.getTypeInfo(MyStruct);
    std.debug.print("Name: {s}, Size: {d}\n", .{ info.name, info.size });

    // Field checks (comptime-safe helpers):
    try std.testing.expect(comptime reflect.hasField(MyStruct, "id"));
    try std.testing.expect(comptime reflect.hasFunc(MyStruct, "getId"));

    // List field names at comptime
    const fields = reflect.getFields(MyStruct);
    inline for (fields) |f| std.debug.print("field: {s}\n", .{ f });
}

// Runtime: use TypeInfo to introspect dynamic metadata (shallow info avoids recursion)
const ti = reflect.getTypeInfo(MyStruct);
std.debug.print("Runtime fields: {d}\n", .{ ti.fields.len });

// Construct a value using `TypeInfo.new` from a tuple literal (comptime API)
comptime {
    const ti_comp = reflect.getTypeInfo(MyStruct);
    const instance_default = ti_comp.new(.{});
    const instance_override = ti_comp.new(.{ .id = 10, .name = "bob" });
    try std.testing.expectEqual(@as(u32, 10), instance_override.id);
}

Notes:

  • getTypeInfo returns shallow field and function metadata suitable for runtime use.
  • TypeInfo.new is a comptime helper that constructs values from tuple literals; useful for code generation and tests.

Interface Validation and VTable

Template(...) provides a compile-time validator and a typed vtable generator. Useful when you want an explicit interface and a vtable for dynamic dispatch. You can also obtain a convenience bound interface instance with Template.interface(ImplType, &instance).

This is a different approach to interfaces in Zig. Hopefully more useful and generally easier to integrate.

See common_interfaces.zig for a examples.

Change Detection

Change(T) is a tiny tracker that hashes trackable fields and detects modifications. Fields beginning with _ are ignored.

const reflect = @import("zevy_reflect");
const std = @import("std");

const Player = struct {
    health: i32,
    score: u32,
    _internal_id: u64, // ignored by Change
};

var player = Player{ .health = 100, .score = 0, ._internal_id = 123 };
var tracker = reflect.Change(Player).init(player);

// Mutate through `get()` (mutable) and finish when processed
var data = tracker.get();
data.health = 80;
data.score = 100;

if (tracker.isChanged()) {
    std.debug.print("Player changed: {d}\n", .{ tracker.getConst().score });
    tracker.finish();
}

Warning

The tracker compares raw bytes for tracked fields; pointer/slice/array contents are hashed as their pointer/length/contents as appropriate. Be cautious with non-stable data (e.g., transient pointers).

Contributing

  1. Fork the repository
  2. Create a feature branch
  3. Add tests for any new functionality
  4. Ensure all tests pass: zig build test
  5. Submit a pull request

Related Projects

  • zevy-ecs - Entity Component System framework that uses zevy-reflect.

About

A reflection library in Zig with utilities covering change detection and interface validation and vtable generation using real structs.

Topics

Resources

License

Stars

Watchers

Forks

Languages