diff --git a/src/lib/buzz_time.zig b/src/lib/buzz_time.zig new file mode 100644 index 00000000..8497af90 --- /dev/null +++ b/src/lib/buzz_time.zig @@ -0,0 +1,32 @@ +const api = @import("buzz_api.zig"); +const std = @import("std"); + +pub export fn timeNow(ctx: *api.NativeCtx) callconv(.c) c_int { + const ts = std.Io.Timestamp.now(ctx.getIo(), .real); + const ms = ts.toMilliseconds(); + ctx.vm.bz_push(.fromDouble(@floatFromInt(ms))); + return 1; +} + +pub export fn timeMonotonic(ctx: *api.NativeCtx) callconv(.c) c_int { + const ts = std.Io.Timestamp.now(ctx.getIo(), .awake); + const ms = ts.toMilliseconds(); + ctx.vm.bz_push(.fromDouble(@floatFromInt(ms))); + return 1; +} + +pub export fn timeCpu(ctx: *api.NativeCtx) callconv(.c) c_int { + const ts = std.Io.Timestamp.now(ctx.getIo(), .cpu_process); + const ms = ts.toMilliseconds(); + ctx.vm.bz_push(.fromDouble(@floatFromInt(ms))); + return 1; +} + +pub const library = api.BuzzApi( + "time", + &.{ + &.{ "now", timeNow }, + &.{ "monotonic", timeMonotonic }, + &.{ "cpu", timeCpu }, + }, +){}; diff --git a/src/lib/static_headers.zig b/src/lib/static_headers.zig index 4ece9fa0..905bba89 100644 --- a/src/lib/static_headers.zig +++ b/src/lib/static_headers.zig @@ -22,6 +22,7 @@ pub const math = Header{ .name = "math", .path = "math.buzz" }; pub const os = Header{ .name = "os", .path = "os.buzz" }; pub const serialize = Header{ .name = "serialize", .path = "serialize.buzz" }; pub const std = Header{ .name = "std", .path = "std.buzz" }; +pub const time = Header{ .name = "time", .path = "time.buzz" }; pub const testing = Header{ .name = "test", .path = "testing.buzz" }; /// Buzz headers bundled with the compiler/runtime and installed for tooling. @@ -41,4 +42,5 @@ pub const all = [_]Header{ serialize, std, testing, + time, }; diff --git a/src/lib/static_libraries.zig b/src/lib/static_libraries.zig index 6463a3c5..d64f59bb 100644 --- a/src/lib/static_libraries.zig +++ b/src/lib/static_libraries.zig @@ -30,6 +30,7 @@ pub const all = [_]Library{ .{ .header = static_headers.os, .zig_path = "buzz_os.zig", .wasm_native = false }, .{ .header = static_headers.serialize, .zig_path = "buzz_serialize.zig", .wasm_native = true }, .{ .header = static_headers.std, .zig_path = "buzz_std.zig", .wasm_native = true }, + .{ .header = static_headers.time, .zig_path = "buzz_time.zig", .wasm_native = false }, .{ .header = static_headers.testing, .zig_path = null, .wasm_native = false }, }; @@ -98,6 +99,7 @@ fn nativeMethods(comptime library: Library) std.StaticStringMap(buzz_api.NativeF if (std.mem.eql(u8, zig_path, "buzz_os.zig")) return checkedNativeMethods(library, @import("buzz_os.zig").library); if (std.mem.eql(u8, zig_path, "buzz_serialize.zig")) return checkedNativeMethods(library, @import("buzz_serialize.zig").library); if (std.mem.eql(u8, zig_path, "buzz_std.zig")) return checkedNativeMethods(library, @import("buzz_std.zig").library); + if (std.mem.eql(u8, zig_path, "buzz_time.zig")) return checkedNativeMethods(library, @import("buzz_time.zig").library); @compileError("unknown native library path: " ++ zig_path); } diff --git a/src/lib/time.buzz b/src/lib/time.buzz new file mode 100644 index 00000000..15d7f98f --- /dev/null +++ b/src/lib/time.buzz @@ -0,0 +1,12 @@ +namespace time; + +import "buzz:errors"; + +/// Real-time (wall-clock) in milliseconds since Unix epoch +export extern fun now() > double; + +/// Monotonic clock in milliseconds (never goes backwards for intervals) +export extern fun monotonic() > double; + +/// Cpu time used by the current process in milliseconds +export extern fun cpu() > double !> errors\UnexpectedError; diff --git a/tests/behavior/time.buzz b/tests/behavior/time.buzz new file mode 100644 index 00000000..31118957 --- /dev/null +++ b/tests/behavior/time.buzz @@ -0,0 +1,29 @@ +import "buzz:std"; +import "buzz:time"; +import "buzz:os" as os; + +test "now returns a positive number" { + final now = time\now(); + std\assert( + now > 0, + message: "now should be greater than 0" + ); +} + +test "monotonic increases" { + final start = time\monotonic(); + os\sleep(12.0); + final end = time\monotonic(); + std\assert( + end > start, + message: "monotonic should increase after sleep" + ); +} + +test "cpu returns a positive number" { + final cpu = time\cpu(); + std\assert( + cpu >= 0, + message: "cpu time should be >= 0" + ); +}