Skip to content

Commit 380a14d

Browse files
committed
Upgrade to Zig 0.16
1 parent d4438aa commit 380a14d

4 files changed

Lines changed: 56 additions & 57 deletions

File tree

README.md

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
11
<img align="right" width="160" height="160" src="https://user-images.githubusercontent.com/34946442/152222895-9c8adb22-a22d-4bce-a513-3486ca28bdd5.png"> zig**fsm** is a [finite state machine](https://en.wikipedia.org/wiki/Finite-state_machine) library for Zig.
22

3-
This library supports Zig 0.12.x, 0.13, 0.14.x, and 0.15.1.
4-
5-
Use the zigfsm main branch to compile with Zig master. Use the appropriate zig-*version* tag to target a specific Zig version.
3+
This library supports Zig 0.16 all the way down to Zig 0.12.x. Use the appropriate tag for older version.
64

75
Tested on Linux, macOS, FreeBSD and Windows.
86

src/benchmark.zig

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ const zigfsm = @import("zigfsm");
33

44
// Run with `zig build benchmark`
55
pub fn main() !void {
6+
const io = std.Io.Threaded.global_single_threaded.io();
67
const State = zigfsm.GenerateConsecutiveEnum("S", 20);
78
const Event = zigfsm.GenerateConsecutiveEnum("T", 20);
89
const defs = [_]zigfsm.Transition(State, Event){
@@ -15,8 +16,7 @@ pub fn main() !void {
1516
const FSM = zigfsm.StateMachineFromTable(State, Event, &defs, .S0, &.{});
1617
var fsm = FSM.init();
1718

18-
var timer = try std.time.Timer.start();
19-
const start = timer.lap();
19+
const start = std.Io.Timestamp.now(io, .awake);
2020

2121
var iterations: usize = 0;
2222
const changes_per_iteration = 120;
@@ -37,9 +37,9 @@ pub fn main() !void {
3737
}
3838

3939
std.mem.doNotOptimizeAway(&iterations);
40-
const end = timer.read();
40+
const end = std.Io.Timestamp.now(io, .awake);
4141

42-
const elapsed_microsec = @as(f64, @floatFromInt(end - start)) / 1000;
42+
const elapsed_microsec = @as(f64, @floatFromInt(start.durationTo(end).toNanoseconds())) / 1000;
4343
const rate = @as(f64, changes_per_iteration) * @as(f64, @floatFromInt(iterations)) / elapsed_microsec;
4444

4545
std.debug.print("{d:.2} transitions per µs ({d:.2} nanoseconds on avg. per transition)\n", .{ rate, 1000 / rate });

src/main.zig

Lines changed: 35 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -398,21 +398,21 @@ pub fn StateMachineFromTable(
398398
if (options.show_events) {
399399
const events_start_offset = @as(usize, @intCast(@intFromEnum(from))) * event_type_count;
400400
var transition_name_buf: [4096]u8 = undefined;
401-
var transition_name = std.io.fixedBufferStream(&transition_name_buf);
401+
var transition_name = std.Io.Writer.fixed(&transition_name_buf);
402402
for (0..event_type_count) |event_index| {
403403
const slot_val = std.mem.readPackedIntNative(CellType, &self.internal.events, (events_start_offset + event_index) * bits_per_cell);
404404
if (slot_val > 0 and (slot_val - 1) == @intFromEnum(to)) {
405-
if ((try transition_name.getPos()) == 0) {
405+
if (transition_name.buffered().len == 0) {
406406
try writer.print(" [label = \"", .{});
407407
}
408-
if ((try transition_name.getPos()) > 0) {
409-
try transition_name.writer().print(" || ", .{});
408+
if (transition_name.buffered().len > 0) {
409+
try transition_name.print(" || ", .{});
410410
}
411-
try transition_name.writer().print("{s}", .{@tagName(@as(T, @enumFromInt(event_index)))});
411+
try transition_name.print("{s}", .{@tagName(@as(T, @enumFromInt(event_index)))});
412412
}
413413
}
414-
if ((try transition_name.getPos()) > 0) {
415-
try writer.print("{s}\"]", .{transition_name.getWritten()});
414+
if (transition_name.buffered().len > 0) {
415+
try writer.print("{s}\"]", .{transition_name.buffered()});
416416
}
417417
}
418418
}
@@ -611,19 +611,27 @@ pub fn FsmFromText(comptime input: []const u8) type {
611611
}
612612
_ = fsm.do(.newline) catch unreachable;
613613

614-
const StateEnum = @Type(.{ .@"enum" = .{
615-
.fields = state_enum_fields,
616-
.tag_type = std.math.IntFittingRange(0, state_enum_fields.len),
617-
.decls = &[_]std.builtin.Type.Declaration{},
618-
.is_exhaustive = false,
619-
} });
614+
const StateTag = std.math.IntFittingRange(0, state_enum_fields.len);
615+
const StateEnum = blk: {
616+
var field_names: [state_enum_fields.len][:0]const u8 = undefined;
617+
var field_values: [state_enum_fields.len]StateTag = undefined;
618+
for (state_enum_fields, &field_names, &field_values) |field, *name, *value| {
619+
name.* = field.name;
620+
value.* = @as(StateTag, @intCast(field.value));
621+
}
622+
break :blk @Enum(StateTag, .nonexhaustive, &field_names, &field_values);
623+
};
620624

621-
const EventEnum = if (event_enum_fields.len > 0) @Type(.{ .@"enum" = .{
622-
.fields = event_enum_fields,
623-
.tag_type = std.math.IntFittingRange(0, event_enum_fields.len),
624-
.decls = &[_]std.builtin.Type.Declaration{},
625-
.is_exhaustive = false,
626-
} }) else null;
625+
const EventEnum = if (event_enum_fields.len > 0) blk: {
626+
const EventTag = std.math.IntFittingRange(0, event_enum_fields.len);
627+
var field_names: [event_enum_fields.len][:0]const u8 = undefined;
628+
var field_values: [event_enum_fields.len]EventTag = undefined;
629+
for (event_enum_fields, &field_names, &field_values) |field, *name, *value| {
630+
name.* = field.name;
631+
value.* = @as(EventTag, @intCast(field.value));
632+
}
633+
break :blk @Enum(EventTag, .nonexhaustive, &field_names, &field_values);
634+
} else null;
627635

628636
return StateMachine(StateEnum, EventEnum, @as(StateEnum, @enumFromInt(start_state_index)));
629637
}
@@ -674,10 +682,12 @@ pub fn GenerateConsecutiveEnum(comptime prefix: []const u8, comptime element_cou
674682
.value = i,
675683
}};
676684
}
677-
return @Type(.{ .@"enum" = .{
678-
.fields = fields,
679-
.tag_type = std.math.IntFittingRange(0, element_count),
680-
.decls = &[_]std.builtin.Type.Declaration{},
681-
.is_exhaustive = false,
682-
} });
685+
const Tag = std.math.IntFittingRange(0, element_count);
686+
var field_names: [fields.len][:0]const u8 = undefined;
687+
var field_values: [fields.len]Tag = undefined;
688+
for (fields, &field_names, &field_values) |field, *name, *value| {
689+
name.* = field.name;
690+
value.* = @as(Tag, @intCast(field.value));
691+
}
692+
return @Enum(Tag, .nonexhaustive, &field_names, &field_values);
683693
}

src/tests.zig

Lines changed: 16 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -242,16 +242,8 @@ test "csv parser" {
242242

243243
/// Feeds the input stream through the state machine
244244
fn read(self: *@This()) !void {
245-
var stream = std.io.fixedBufferStream(self.csv);
246-
const reader = stream.reader();
247-
while (true) : (self.cur_index += 1) {
248-
const input = reader.readByte() catch {
249-
// An example of how to handle parsing errors
250-
_ = self.fsm.do(.eof) catch {
251-
std.debug.print("Unexpected end of stream\n", .{});
252-
};
253-
return;
254-
};
245+
while (self.cur_index < self.csv.len) : (self.cur_index += 1) {
246+
const input = self.csv[self.cur_index];
255247

256248
// The order of checks is important to classify input correctly
257249
if (self.fsm.isCurrently(.quoted) and input != '"') {
@@ -268,6 +260,10 @@ test "csv parser" {
268260
_ = try self.fsm.do(.char);
269261
}
270262
}
263+
264+
_ = self.fsm.do(.eof) catch {
265+
std.debug.print("Unexpected end of stream\n", .{});
266+
};
271267
}
272268

273269
/// We use state transitions to extract CSV field slices, and we're not using any extra memory.
@@ -370,16 +366,8 @@ test "csv parser, without handler callback" {
370366

371367
/// Feeds the input stream through the state machine
372368
fn read(self: *@This()) !void {
373-
var stream = std.io.fixedBufferStream(self.csv);
374-
const reader = stream.reader();
375-
while (true) : (self.cur_index += 1) {
376-
const input = reader.readByte() catch {
377-
// An example of how to handle parsing errors
378-
_ = self.fsm.do(.eof) catch {
379-
std.debug.print("Unexpected end of stream\n", .{});
380-
};
381-
return;
382-
};
369+
while (self.cur_index < self.csv.len) : (self.cur_index += 1) {
370+
const input = self.csv[self.cur_index];
383371

384372
// Holds from/to/event if a transition is triggered
385373
var maybe_transition: ?zigfsm.Transition(State, InputEvent) = null;
@@ -425,6 +413,10 @@ test "csv parser, without handler callback" {
425413
}
426414
}
427415
}
416+
417+
_ = self.fsm.do(.eof) catch {
418+
std.debug.print("Unexpected end of stream\n", .{});
419+
};
428420
}
429421
};
430422

@@ -603,11 +595,10 @@ test "export: graphviz export of finite automaton sample" {
603595
// This demonstrates that multiple events on the same transition are concatenated with ||
604596
try fsm.addEvent(.extra, .@"8", .@"5");
605597

606-
var outbuf = std.ArrayList(u8).empty;
607-
defer outbuf.deinit(std.testing.allocator);
608-
const writer = outbuf.writer(std.testing.allocator);
598+
var outbuf: std.Io.Writer.Allocating = .init(std.testing.allocator);
599+
defer outbuf.deinit();
609600

610-
try fsm.exportGraphviz("parser_example", writer, .{});
601+
try fsm.exportGraphviz("parser_example", &outbuf.writer, .{});
611602

612603
const target =
613604
\\digraph parser_example {
@@ -632,7 +623,7 @@ test "export: graphviz export of finite automaton sample" {
632623
\\
633624
;
634625

635-
try expectEqualSlices(u8, target[0..], outbuf.items[0..]);
626+
try expectEqualSlices(u8, target[0..], outbuf.written());
636627
}
637628

638629
test "finite state automaton for accepting a 25p car park charge (from Computers Without Memory - Computerphile)" {

0 commit comments

Comments
 (0)