diff --git a/build.zig b/build.zig index a02217a..7448f7f 100644 --- a/build.zig +++ b/build.zig @@ -4,6 +4,7 @@ const build_crab = @import("build_crab"); pub fn build(b: *std.Build) !void { const target = b.standardTargetOptions(.{}); const optimize = b.standardOptimizeOption(.{}); + const is_wasm_freestanding = target.result.cpu.arch.isWasm() and target.result.os.tag == .freestanding; // --- Zig Module: temporalz --- // const mod = b.addModule("temporalz", .{ @@ -11,6 +12,9 @@ pub fn build(b: *std.Build) !void { .target = target, .optimize = optimize, }); + if (is_wasm_freestanding) { + mod.addIncludePath(b.path("src/stubs/c_headers")); + } // --- Rust C ABI: temporal_capi --- // const temporal_rs = b.dependency("temporal_rs", .{ @@ -82,7 +86,7 @@ pub fn build(b: *std.Build) !void { .linkage = .static, .name = "unwind_stubs", .root_module = b.createModule(.{ - .root_source_file = b.path("src/unwind_stubs.zig"), + .root_source_file = b.path("src/stubs/unwind.zig"), .target = target, .optimize = optimize, }), @@ -91,10 +95,14 @@ pub fn build(b: *std.Build) !void { } // --- Zig Executable: temporalz --- // + const exe_root = if (is_wasm_freestanding) + b.path("example/src/wasm.zig") + else + b.path("example/src/main.zig"); const exe = b.addExecutable(.{ .name = "temporalz", .root_module = b.createModule(.{ - .root_source_file = b.path("example/src/main.zig"), + .root_source_file = exe_root, .target = target, .optimize = optimize, .imports = &.{ @@ -106,11 +114,17 @@ pub fn build(b: *std.Build) !void { // --- Steps: Run --- // { - const run_cmd = b.addRunArtifact(exe); - run_cmd.step.dependOn(b.getInstallStep()); - if (b.args) |args| run_cmd.addArgs(args); const run_step = b.step("run", "Run the app"); - run_step.dependOn(&run_cmd.step); + if (is_wasm_freestanding) { + const run_cmd = b.addSystemCommand(&.{ "node", "example/src/main.mjs" }); + run_cmd.step.dependOn(b.getInstallStep()); + run_step.dependOn(&run_cmd.step); + } else { + const run_cmd = b.addRunArtifact(exe); + run_cmd.step.dependOn(b.getInstallStep()); + if (b.args) |args| run_cmd.addArgs(args); + run_step.dependOn(&run_cmd.step); + } } // --- Steps: Docs --- // @@ -136,10 +150,12 @@ pub fn build(b: *std.Build) !void { .mode = .simple, }, }); - mod_tests.root_module.link_libc = true; + mod_tests.root_module.link_libc = !is_wasm_freestanding; test_step.dependOn(&b.addRunArtifact(mod_tests).step); - const exe_tests = b.addTest(.{ .root_module = exe.root_module }); - test_step.dependOn(&b.addRunArtifact(exe_tests).step); + if (!is_wasm_freestanding) { + const exe_tests = b.addTest(.{ .root_module = exe.root_module }); + test_step.dependOn(&b.addRunArtifact(exe_tests).step); + } } // --- Steps: test-262 --- // @@ -159,7 +175,7 @@ pub fn build(b: *std.Build) !void { .mode = .simple, }, }); - test262_tests.root_module.link_libc = true; + test262_tests.root_module.link_libc = !is_wasm_freestanding; test262_step.dependOn(&b.addRunArtifact(test262_tests).step); } @@ -200,4 +216,5 @@ const platforms = [_][]const u8{ "x86_64-linux-gnu", "x86_64-windows-gnu", "aarch64-windows-gnu", + "wasm32-freestanding", }; diff --git a/build.zig.zon b/build.zig.zon index cbed7d7..7002592 100644 --- a/build.zig.zon +++ b/build.zig.zon @@ -9,8 +9,8 @@ .hash = "N-V-__8AANlkNAB77Z946lqp-lgp2qSsOBDADValZC86PhB-", }, .build_crab = .{ - .url = "git+https://github.com/linusg/build.crab?ref=zig-dev#a4c247befef7c1642e7fdfdaf47d3a74dd96d46c", - .hash = "build_crab-0.2.1-U0id_yXEAADD2lzWEocoHFMzBXzSABdi0Z7lZPVxN-Ve", + .url = "git+https://github.com/nurulhudaapon/build.crab?ref=zig-dev#658db72f1695987612e9356c023575ff8dc753a2", + .hash = "build_crab-0.2.1-U0id__PFAACr0518VaPmWuEJDMJezJhmAsFRY6d49v6e", }, }, .paths = .{ diff --git a/example/build.zig b/example/build.zig index 1065dcf..357ae9f 100644 --- a/example/build.zig +++ b/example/build.zig @@ -3,15 +3,16 @@ const std = @import("std"); pub fn build(b: *std.Build) void { const target = b.standardTargetOptions(.{}); const optimize = b.standardOptimizeOption(.{}); + const is_wasm = target.result.cpu.arch.isWasm(); const temporalz = b.dependency("temporalz", .{ .target = target, .optimize = optimize, }); const exe = b.addExecutable(.{ - .name = "example", + .name = "temporalz", .root_module = b.createModule(.{ - .root_source_file = b.path("src/main.zig"), + .root_source_file = b.path(if (is_wasm) "src/wasm.zig" else "src/main.zig"), .target = target, .optimize = optimize, .imports = &.{}, @@ -21,8 +22,14 @@ pub fn build(b: *std.Build) void { b.installArtifact(exe); const run_step = b.step("run", "Run the app"); - const run_cmd = b.addRunArtifact(exe); - run_step.dependOn(&run_cmd.step); - run_cmd.step.dependOn(b.getInstallStep()); - if (b.args) |args| run_cmd.addArgs(args); + if (is_wasm) { + const run_cmd = b.addSystemCommand(&.{ "node", "src/main.mjs" }); + run_cmd.step.dependOn(b.getInstallStep()); + run_step.dependOn(&run_cmd.step); + } else { + const run_cmd = b.addRunArtifact(exe); + run_step.dependOn(&run_cmd.step); + run_cmd.step.dependOn(b.getInstallStep()); + if (b.args) |args| run_cmd.addArgs(args); + } } diff --git a/example/src/main.mjs b/example/src/main.mjs new file mode 100644 index 0000000..f5ab43a --- /dev/null +++ b/example/src/main.mjs @@ -0,0 +1,17 @@ +import { readFile } from 'fs/promises'; + +let memory = null; + +const buffer = await readFile('zig-out/bin/temporalz.wasm'); +const temporalz = await WebAssembly.instantiate(buffer, { + env: { + console(ptr, len) { + const bytes = new Uint8Array(memory.buffer, ptr, len); + const message = new TextDecoder().decode(bytes); + console.log(message); + }, + }, +}); + +memory = temporalz.instance.exports.memory; +temporalz.instance.exports._start(); diff --git a/example/src/main.zig b/example/src/main.zig index 286c264..7b318c4 100644 --- a/example/src/main.zig +++ b/example/src/main.zig @@ -1,465 +1,9 @@ const std = @import("std"); -const Temporal = @import("temporalz"); +const program = @import("root.zig"); pub fn main(init: std.process.Init) !void { const allocator = init.arena.allocator(); const io = init.io; - // --- Instant --- // - const instant = try Temporal.Instant.init(1_704_067_200_000_000_000); // 2024-01-01 00:00:00 UTC - defer instant.deinit(); - std.debug.print( - \\Instant - \\ - milliseconds: {} - \\ - nanoseconds: {} - \\ - toString(): {s} - \\ - \\ - , .{ - instant.epochMilliseconds(), - instant.epochNanoseconds(), - try instant.toString(allocator, .{}), - }); - - // --- Duration --- // - const dur = try Temporal.Duration.from("PT1H"); - defer dur.deinit(); - std.debug.print( - \\Duration - \\ - nanoseconds: {} - \\ - milliseconds: {} - \\ - seconds: {} - \\ - minutes: {} - \\ - hours: {} - \\ - days: {} - \\ - weeks: {} - \\ - months: {} - \\ - years: {} - \\ - toString(): {s} - \\ - \\ - , .{ - dur.nanoseconds(), - dur.milliseconds(), - dur.seconds(), - dur.minutes(), - dur.hours(), - dur.days(), - dur.weeks(), - dur.months(), - dur.years(), - try dur.toString(allocator, .{}), - }); - - // --- Now --- // - const now_instant = try Temporal.Now.instant(io); - defer now_instant.deinit(); - const now_date = try Temporal.Now.plainDateISO(io); - defer now_date.deinit(); - const now_datetime = try Temporal.Now.plainDateTimeISO(io); - const now_time = try Temporal.Now.plainTimeISO(io); - std.debug.print( - \\Now - \\ - instant: {s} - \\ - date: {s} - \\ - datetime: {s} - \\ - time: {s} - \\ - \\ - , .{ - try now_instant.toString(allocator, .{}), - try now_date.toString(allocator, .{}), - try now_datetime.toString(allocator, .{}), - try now_time.toString(allocator), - }); - - // --- PlainDate --- // - const date = try Temporal.PlainDate.init(2024, 2, 2); - defer date.deinit(); - std.debug.print( - \\PlainDate - \\ - year: {} - \\ - month: {} - \\ - day: {} - \\ - toString(): {s} - \\ - \\ - , .{ - date.year(), - date.month(), - date.day(), - try date.toString(allocator, .{}), - }); - - // --- PlainDateTime --- // - const dt = try Temporal.PlainDateTime.init(2024, 2, 2, 13, 45, 30, 123, 456, 789); - std.debug.print( - \\PlainDateTime - \\ - year: {} - \\ - month: {} - \\ - day: {} - \\ - hour: {} - \\ - minute: {} - \\ - second: {} - \\ - toString(): {s} - \\ - \\ - , .{ - dt.year(), - dt.month(), - dt.day(), - dt.hour(), - dt.minute(), - dt.second(), - try dt.toString(allocator, .{}), - }); - - // --- PlainMonthDay --- // - const md = try Temporal.PlainMonthDay.init(2, 2, null); - std.debug.print( - \\PlainMonthDay - \\ - monthCode: {s} - \\ - day: {} - \\ - toString(): {s} - \\ - \\ - , .{ - try md.monthCode(allocator), - md.day(), - try md.toString(allocator), - }); - - // --- PlainTime --- // - const tm = try Temporal.PlainTime.init(13, 45, 30, 123, 456, 789); - std.debug.print( - \\PlainTime - \\ - hour: {} - \\ - minute: {} - \\ - second: {} - \\ - toString(): {s} - \\ - \\ - , .{ - tm.hour(), - tm.minute(), - tm.second(), - try tm.toString(allocator), - }); - - // --- PlainYearMonth --- // - const ym = try Temporal.PlainYearMonth.init(2024, 2, null); - std.debug.print( - \\PlainYearMonth - \\ - year: {} - \\ - month: {} - \\ - toString(): {s} - \\ - \\ - , .{ ym.year(), ym.month(), try ym.toString(allocator) }); - - // --- ZonedDateTime --- // - const tz = try Temporal.ZonedDateTime.TimeZone.init("UTC"); - // Example: 2024-02-02T13:45:30.123456789Z in nanoseconds since epoch - const zdt_epoch_ns: i128 = 1706881530123456789; - const zdt = try Temporal.ZonedDateTime.fromEpochNanoseconds(zdt_epoch_ns, tz); - defer zdt.deinit(); - std.debug.print( - \\ZonedDateTime - \\ - year: {} - \\ - month: {} - \\ - day: {} - \\ - hour: {} - \\ - minute: {} - \\ - second: {} - \\ - timeZone: {s} - \\ - toString(): {s} - \\ - \\ - , .{ - zdt.year(), - zdt.month(), - zdt.day(), - zdt.hour(), - zdt.minute(), - zdt.second(), - try zdt.timeZoneId(allocator), - try zdt.toString(allocator, .{}), - }); - - // ---- - // More complex Temporal API examples - // ---- - - // Duration arithmetic - const dur1 = try Temporal.Duration.from("P1DT2H"); - const dur2 = try Temporal.Duration.from("PT30M"); - const dur_sum = try dur1.add(dur2); - std.debug.print( - \\Duration Arithmetic - \\ - dur1: {s} - \\ - dur2: {s} - \\ - dur1 + dur2: {s} - \\ - \\ - , .{ - try dur1.toString(allocator, .{}), - try dur2.toString(allocator, .{}), - try dur_sum.toString(allocator, .{}), - }); - - // Instant comparison and arithmetic - const inst1 = try Temporal.Instant.init(1_704_067_200_000_000_000); - const inst2 = try Temporal.Instant.init(1_704_153_600_000_000_000); // +1 day - const inst_diff = try inst2.since(inst1, Temporal.Instant.DifferenceSettings{}); - std.debug.print( - \\Instant Comparison - \\ - inst1: {s} - \\ - inst2: {s} - \\ - inst2.since(inst1): {s} - \\ - \\ - , .{ - try inst1.toString(allocator, .{}), - try inst2.toString(allocator, .{}), - try inst_diff.toString(allocator, .{}), - }); - - // PlainDate to PlainDateTime and back - const pd = try Temporal.PlainDate.init(2024, 2, 2); - const pdt = try pd.toPlainDateTime(try Temporal.PlainTime.init(12, 0, 0, 0, 0, 0)); - std.debug.print( - \\PlainDate/PlainDateTime Conversion - \\ - PlainDate: {s} - \\ - toPlainDateTime(12:00): {s} - \\ - toPlainDate(): {s} - \\ - \\ - , .{ - try pd.toString(allocator, .{}), - try pdt.toString(allocator, .{}), - try (try pdt.toPlainDate()).toString(allocator, .{}), - }); - - // ZonedDateTime to Instant and back - const zdt2 = try Temporal.ZonedDateTime.fromEpochNanoseconds(1706881530123456789, tz); - const zdt2_inst = try zdt2.toInstant(); - const zdt2_from_inst = try Temporal.ZonedDateTime.fromEpochNanoseconds(zdt2_inst.epochNanoseconds(), tz); - std.debug.print( - \\ZonedDateTime/Instant Conversion - \\ - ZonedDateTime: {s} - \\ - toInstant(): {s} - \\ - fromEpochNanoseconds(instant): {s} - \\ - \\ - , .{ - try zdt2.toString(allocator, .{}), - try zdt2_inst.toString(allocator, .{}), - try zdt2_from_inst.toString(allocator, .{}), - }); - - // ---- - // Further more complex examples covering more methods - // ---- - - // Duration: abs, negated, round, subtract, total, valueOf - const dur_neg = dur.negated(); - const dur_abs = dur_neg.abs(); - const dur_sub = try dur.subtract(dur2); - const dur_rounded = try dur.round(.{ .smallest_unit = Temporal.Duration.Unit.hour }); - const dur_total_hours = try dur.total(.{ .unit = Temporal.Duration.Unit.hour }); - std.debug.print( - \\Duration Advanced - \\ - negated: {s} - \\ - abs: {s} - \\ - subtract dur2: {s} - \\ - round to hour: {s} - \\ - total hours: {d} - \\ - \\ - , .{ - try dur_neg.toString(allocator, .{}), - try dur_abs.toString(allocator, .{}), - try dur_sub.toString(allocator, .{}), - try dur_rounded.toString(allocator, .{}), - dur_total_hours, - }); - - // Instant: add, subtract, round, equals, valueOf - const inst_add = try inst1.add(@constCast(&dur)); - const inst_sub = try inst2.subtract(@constCast(&dur)); - const inst_rounded = try inst1.round(.{ .smallest_unit = Temporal.Instant.Unit.second }); - const inst_eq = Temporal.Instant.compare(inst1, inst1) == 0; - std.debug.print( - \\Instant Advanced - \\ - add duration: {s} - \\ - subtract duration: {s} - \\ - round to second: {s} - \\ - inst1 equals inst1: {} - \\ - \\ - , .{ - try inst_add.toString(allocator, .{}), - try inst_sub.toString(allocator, .{}), - try inst_rounded.toString(allocator, .{}), - inst_eq, - }); - - // PlainDate: add, subtract, with, equals, since, until, withCalendar - const date_added = try date.add(dur); - const date_sub = try date.subtract(dur); - // const date_with = try date.with(.{ .year = 2025 }); - const date_eq = date.equals(date); - const date_since = try date.since(date, Temporal.PlainDate.DifferenceSettings{}); - const date_until = try date.until(date, Temporal.PlainDate.DifferenceSettings{}); - const date_with_cal = try date.withCalendar("iso8601"); - std.debug.print( - \\PlainDate Advanced - \\ - equals self: {} - \\ - add duration: {s} - \\ - subtract duration: {s} - \\ - since self: {s} - \\ - until self: {s} - \\ - withCalendar: {s} - \\ - with year=2025: {{s}} - \\ - \\ - , - .{ - date_eq, - try date_added.toString(allocator, .{}), - try date_sub.toString(allocator, .{}), - try date_since.toString(allocator, .{}), - try date_until.toString(allocator, .{}), - try date_with_cal.toString(allocator, .{}), - // try date_with.toString(allocator, .{}), - }, - ); - - // PlainDateTime: add, subtract, round, with, equals, since, until, withCalendar, withPlainTime - const dt_added = try dt.add(dur); - const dt_sub = try dt.subtract(dur); - const dt_rounded = try dt.round(.{ .smallest_unit = Temporal.PlainDateTime.Unit.minute }); - const dt_with = try dt.with(.{ .year = 2025 }); - const dt_eq = dt.equals(dt); - const dt_since = try dt.since(dt, Temporal.PlainDateTime.DifferenceSettings{}); - const dt_until = try dt.until(dt, Temporal.PlainDateTime.DifferenceSettings{}); - const dt_with_cal = try dt.withCalendar("iso8601"); - const dt_with_time = try dt.withPlainTime(try Temporal.PlainTime.init(1, 2, 3, 4, 5, 6)); - std.debug.print( - \\PlainDateTime Advanced - \\ - add duration: {s} - \\ - subtract duration: {s} - \\ - round to minute: {s} - \\ - with year=2025: {s} - \\ - equals self: {} - \\ - since self: {s} - \\ - until self: {s} - \\ - withCalendar: {s} - \\ - withPlainTime: {s} - \\ - \\ - , .{ - try dt_added.toString(allocator, .{}), - try dt_sub.toString(allocator, .{}), - try dt_rounded.toString(allocator, .{}), - try dt_with.toString(allocator, .{}), - dt_eq, - try dt_since.toString(allocator, .{}), - try dt_until.toString(allocator, .{}), - try dt_with_cal.toString(allocator, .{}), - try dt_with_time.toString(allocator, .{}), - }); - - // PlainTime: add, subtract, round, with, equals, since, until - const tm_added = try tm.add(dur); - const tm_sub = try tm.subtract(dur); - const tm_rounded = try tm.round(.{ .smallest_unit = Temporal.PlainTime.Unit.second }); - const tm_with = try tm.with(.{ .hour = 1 }); - const tm_eq = tm.equals(tm); - const tm_since = try tm.since(tm, Temporal.PlainTime.DifferenceSettings{}); - const tm_until = try tm.until(tm, Temporal.PlainTime.DifferenceSettings{}); - std.debug.print( - \\PlainTime Advanced - \\ - add duration: {s} - \\ - subtract duration: {s} - \\ - round to second: {s} - \\ - with hour=1: {s} - \\ - equals self: {} - \\ - since self: {s} - \\ - until self: {s} - \\ - \\ - , .{ - try tm_added.toString(allocator), - try tm_sub.toString(allocator), - try tm_rounded.toString(allocator), - try tm_with.toString(allocator), - tm_eq, - try tm_since.toString(allocator, .{}), - try tm_until.toString(allocator, .{}), - }); - - // PlainYearMonth: add, subtract, with, equals, since, until, withCalendar - const ym_added = try ym.add(dur); - const ym_sub = try ym.subtract(dur); - const ym_with = try ym.with(.{ .year = 2025 }); - const ym_eq = ym.equals(ym); - const ym_since = try ym.since(ym, Temporal.PlainYearMonth.DifferenceSettings{}); - const ym_until = try ym.until(ym, Temporal.PlainYearMonth.DifferenceSettings{}); - std.debug.print( - \\PlainYearMonth Advanced - \\ - add duration: {s} - \\ - subtract duration: {s} - \\ - with year=2025: {s} - \\ - equals self: {} - \\ - since self: {s} - \\ - until self: {s} - \\ - \\ - , .{ - try ym_added.toString(allocator), - try ym_sub.toString(allocator), - try ym_with.toString(allocator), - ym_eq, - try ym_since.toString(allocator, .{}), - try ym_until.toString(allocator, .{}), - }); - - // ZonedDateTime: add, subtract, round, with, equals, since, until, withCalendar, withPlainTime, withTimeZone - const zdt_added = try zdt.add(dur); - const zdt_sub = try zdt.subtract(dur); - const zdt_rounded = try zdt.round(.{ .smallest_unit = Temporal.ZonedDateTime.Unit.hour }); - // const zdt_with = try zdt.with(allocator, .{ .year = 2025 }); - const zdt_eq = zdt.equals(zdt); - const zdt_since = try zdt.since(zdt, Temporal.ZonedDateTime.DifferenceSettings{}); - const zdt_until = try zdt.until(zdt, Temporal.ZonedDateTime.DifferenceSettings{}); - const zdt_with_cal = try zdt.withCalendar("iso8601"); - const zdt_with_time = try zdt.withPlainTime(try Temporal.PlainTime.init(1, 2, 3, 4, 5, 6)); - const zdt_with_tz = try zdt.withTimeZone(tz); - std.debug.print( - \\ZonedDateTime Advanced - \\ - add duration: {s} - \\ - subtract duration: {s} - \\ - round to hour: {s} - \\ - with year=2025: {{s}} - \\ - equals self: {} - \\ - since self: {s} - \\ - until self: {s} - \\ - withCalendar: {s} - \\ - withPlainTime: {s} - \\ - withTimeZone: {s} - \\ - \\ - , .{ - try zdt_added.toString(allocator, .{}), - try zdt_sub.toString(allocator, .{}), - try zdt_rounded.toString(allocator, .{}), - // try zdt_with.toString(allocator, .{}), - zdt_eq, - try zdt_since.toString(allocator, .{}), - try zdt_until.toString(allocator, .{}), - try zdt_with_cal.toString(allocator, .{}), - try zdt_with_time.toString(allocator, .{}), - try zdt_with_tz.toString(allocator, .{}), - }); + try program.run(allocator, io); } diff --git a/example/src/root.zig b/example/src/root.zig new file mode 100644 index 0000000..3217270 --- /dev/null +++ b/example/src/root.zig @@ -0,0 +1,480 @@ +const std = @import("std"); +const builtin = @import("builtin"); +const Temporal = @import("temporalz"); + +pub fn run(allocator: std.mem.Allocator, io_optional: ?std.Io) !void { + // --- Instant --- // + const instant = try Temporal.Instant.init(1_704_067_200_000_000_000); // 2024-01-01 00:00:00 UTC + defer instant.deinit(); + std.log.info( + \\Instant + \\ - milliseconds: {} + \\ - nanoseconds: {} + \\ - toString(): {s} + \\ + \\ + , .{ + instant.epochMilliseconds(), + instant.epochNanoseconds(), + try instant.toString(allocator, .{}), + }); + + // --- Duration --- // + const dur = try Temporal.Duration.from("PT1H"); + defer dur.deinit(); + std.log.info( + \\Duration + \\ - nanoseconds: {} + \\ - milliseconds: {} + \\ - seconds: {} + \\ - minutes: {} + \\ - hours: {} + \\ - days: {} + \\ - weeks: {} + \\ - months: {} + \\ - years: {} + \\ - toString(): {s} + \\ + \\ + , .{ + dur.nanoseconds(), + dur.milliseconds(), + dur.seconds(), + dur.minutes(), + dur.hours(), + dur.days(), + dur.weeks(), + dur.months(), + dur.years(), + try dur.toString(allocator, .{}), + }); + + // --- Now --- // + if (io_optional) |io| { + const now_instant = try Temporal.Now.instant(io); + defer now_instant.deinit(); + const now_date = try Temporal.Now.plainDateISO(io); + defer now_date.deinit(); + const now_datetime = try Temporal.Now.plainDateTimeISO(io); + const now_time = try Temporal.Now.plainTimeISO(io); + std.log.info( + \\Now + \\ - instant: {s} + \\ - date: {s} + \\ - datetime: {s} + \\ - time: {s} + \\ + \\ + , .{ + try now_instant.toString(allocator, .{}), + try now_date.toString(allocator, .{}), + try now_datetime.toString(allocator, .{}), + try now_time.toString(allocator), + }); + } + + // --- PlainDate --- // + const date = try Temporal.PlainDate.init(2024, 2, 2); + defer date.deinit(); + std.log.info( + \\PlainDate + \\ - year: {} + \\ - month: {} + \\ - day: {} + \\ - toString(): {s} + \\ + \\ + , .{ + date.year(), + date.month(), + date.day(), + try date.toString(allocator, .{}), + }); + + // --- PlainDateTime --- // + const dt = try Temporal.PlainDateTime.init(2024, 2, 2, 13, 45, 30, 123, 456, 789); + std.log.info( + \\PlainDateTime + \\ - year: {} + \\ - month: {} + \\ - day: {} + \\ - hour: {} + \\ - minute: {} + \\ - second: {} + \\ - toString(): {s} + \\ + \\ + , .{ + dt.year(), + dt.month(), + dt.day(), + dt.hour(), + dt.minute(), + dt.second(), + try dt.toString(allocator, .{}), + }); + + // --- PlainMonthDay --- // + const md = try Temporal.PlainMonthDay.init(2, 2, null); + std.log.info( + \\PlainMonthDay + \\ - monthCode: {s} + \\ - day: {} + \\ - toString(): {s} + \\ + \\ + , .{ + try md.monthCode(allocator), + md.day(), + try md.toString(allocator), + }); + + // --- PlainTime --- // + const tm = try Temporal.PlainTime.init(13, 45, 30, 123, 456, 789); + std.log.info( + \\PlainTime + \\ - hour: {} + \\ - minute: {} + \\ - second: {} + \\ - toString(): {s} + \\ + \\ + , .{ + tm.hour(), + tm.minute(), + tm.second(), + try tm.toString(allocator), + }); + + // --- PlainYearMonth --- // + const ym = try Temporal.PlainYearMonth.init(2024, 2, null); + std.log.info( + \\PlainYearMonth + \\ - year: {} + \\ - month: {} + \\ - toString(): {s} + \\ + \\ + , .{ ym.year(), ym.month(), try ym.toString(allocator) }); + + // --- ZonedDateTime --- // + const tz = try Temporal.ZonedDateTime.TimeZone.init("UTC"); + // Example: 2024-02-02T13:45:30.123456789Z in nanoseconds since epoch + const zdt_epoch_ns: i128 = 1706881530123456789; + const zdt = try Temporal.ZonedDateTime.fromEpochNanoseconds(zdt_epoch_ns, tz); + defer zdt.deinit(); + std.log.info( + \\ZonedDateTime + \\ - year: {} + \\ - month: {} + \\ - day: {} + \\ - hour: {} + \\ - minute: {} + \\ - second: {} + \\ - timeZone: {s} + \\ - toString(): {s} + \\ + \\ + , .{ + zdt.year(), + zdt.month(), + zdt.day(), + zdt.hour(), + zdt.minute(), + zdt.second(), + try zdt.timeZoneId(allocator), + try zdt.toString(allocator, .{}), + }); + + // ---- + // More complex Temporal API examples + // ---- + + // Duration arithmetic + const dur1 = try Temporal.Duration.from("P1DT2H"); + const dur2 = try Temporal.Duration.from("PT30M"); + const dur_sum = try dur1.add(dur2); + std.log.info( + \\Duration Arithmetic + \\ - dur1: {s} + \\ - dur2: {s} + \\ - dur1 + dur2: {s} + \\ + \\ + , .{ + try dur1.toString(allocator, .{}), + try dur2.toString(allocator, .{}), + try dur_sum.toString(allocator, .{}), + }); + + // Instant comparison and arithmetic + const inst1 = try Temporal.Instant.init(1_704_067_200_000_000_000); + const inst2 = try Temporal.Instant.init(1_704_153_600_000_000_000); // +1 day + const inst_diff = try inst2.since(inst1, Temporal.Instant.DifferenceSettings{}); + std.log.info( + \\Instant Comparison + \\ - inst1: {s} + \\ - inst2: {s} + \\ - inst2.since(inst1): {s} + \\ + \\ + , .{ + try inst1.toString(allocator, .{}), + try inst2.toString(allocator, .{}), + try inst_diff.toString(allocator, .{}), + }); + + // PlainDate to PlainDateTime and back + const pd = try Temporal.PlainDate.init(2024, 2, 2); + const pdt = try pd.toPlainDateTime(try Temporal.PlainTime.init(12, 0, 0, 0, 0, 0)); + std.log.info( + \\PlainDate/PlainDateTime Conversion + \\ - PlainDate: {s} + \\ - toPlainDateTime(12:00): {s} + \\ - toPlainDate(): {s} + \\ + \\ + , .{ + try pd.toString(allocator, .{}), + try pdt.toString(allocator, .{}), + try (try pdt.toPlainDate()).toString(allocator, .{}), + }); + + // ZonedDateTime to Instant and back + const zdt2 = try Temporal.ZonedDateTime.fromEpochNanoseconds(1706881530123456789, tz); + const zdt2_inst = try zdt2.toInstant(); + const zdt2_from_inst = try Temporal.ZonedDateTime.fromEpochNanoseconds(zdt2_inst.epochNanoseconds(), tz); + std.log.info( + \\ZonedDateTime/Instant Conversion + \\ - ZonedDateTime: {s} + \\ - toInstant(): {s} + \\ - fromEpochNanoseconds(instant): {s} + \\ + \\ + , .{ + try zdt2.toString(allocator, .{}), + try zdt2_inst.toString(allocator, .{}), + try zdt2_from_inst.toString(allocator, .{}), + }); + + // ---- + // Further more complex examples covering more methods + // ---- + + // Duration: abs, negated, round, subtract, total, valueOf + const dur_neg = dur.negated(); + const dur_abs = dur_neg.abs(); + const dur_sub = try dur.subtract(dur2); + const dur_rounded = try dur.round(.{ .smallest_unit = Temporal.Duration.Unit.hour }); + const dur_total_hours = try dur.total(.{ .unit = Temporal.Duration.Unit.hour }); + std.log.info( + \\Duration Advanced + \\ - negated: {s} + \\ - abs: {s} + \\ - subtract dur2: {s} + \\ - round to hour: {s} + \\ - total hours: {d} + \\ + \\ + , .{ + try dur_neg.toString(allocator, .{}), + try dur_abs.toString(allocator, .{}), + try dur_sub.toString(allocator, .{}), + try dur_rounded.toString(allocator, .{}), + dur_total_hours, + }); + + // Instant: add, subtract, round, equals, valueOf + const inst_add = try inst1.add(@constCast(&dur)); + const inst_sub = try inst2.subtract(@constCast(&dur)); + const inst_rounded = try inst1.round(.{ .smallest_unit = Temporal.Instant.Unit.second }); + const inst_eq = Temporal.Instant.compare(inst1, inst1) == 0; + std.log.info( + \\Instant Advanced + \\ - add duration: {s} + \\ - subtract duration: {s} + \\ - round to second: {s} + \\ - inst1 equals inst1: {} + \\ + \\ + , .{ + try inst_add.toString(allocator, .{}), + try inst_sub.toString(allocator, .{}), + try inst_rounded.toString(allocator, .{}), + inst_eq, + }); + + // PlainDate: add, subtract, with, equals, since, until, withCalendar + const date_added = try date.add(dur); + const date_sub = try date.subtract(dur); + // const date_with = try date.with(.{ .year = 2025 }); + const date_eq = date.equals(date); + const date_since = try date.since(date, Temporal.PlainDate.DifferenceSettings{}); + const date_until = try date.until(date, Temporal.PlainDate.DifferenceSettings{}); + const date_with_cal = try date.withCalendar("iso8601"); + std.log.info( + \\PlainDate Advanced + \\ - equals self: {} + \\ - add duration: {s} + \\ - subtract duration: {s} + \\ - since self: {s} + \\ - until self: {s} + \\ - withCalendar: {s} + \\ - with year=2025: {{s}} + \\ + \\ + , + .{ + date_eq, + try date_added.toString(allocator, .{}), + try date_sub.toString(allocator, .{}), + try date_since.toString(allocator, .{}), + try date_until.toString(allocator, .{}), + try date_with_cal.toString(allocator, .{}), + // try date_with.toString(allocator, .{}), + }, + ); + + // PlainDateTime: add, subtract, round, with, equals, since, until, withCalendar, withPlainTime + const dt_added = try dt.add(dur); + const dt_sub = try dt.subtract(dur); + const dt_rounded = try dt.round(.{ .smallest_unit = Temporal.PlainDateTime.Unit.minute }); + const dt_with = try dt.with(.{ .year = 2025 }); + const dt_eq = dt.equals(dt); + const dt_since = try dt.since(dt, Temporal.PlainDateTime.DifferenceSettings{}); + const dt_until = try dt.until(dt, Temporal.PlainDateTime.DifferenceSettings{}); + const dt_with_cal = try dt.withCalendar("iso8601"); + const dt_with_time = try dt.withPlainTime(try Temporal.PlainTime.init(1, 2, 3, 4, 5, 6)); + std.log.info( + \\PlainDateTime Advanced + \\ - add duration: {s} + \\ - subtract duration: {s} + \\ - round to minute: {s} + \\ - with year=2025: {s} + \\ - equals self: {} + \\ - since self: {s} + \\ - until self: {s} + \\ - withCalendar: {s} + \\ - withPlainTime: {s} + \\ + \\ + , .{ + try dt_added.toString(allocator, .{}), + try dt_sub.toString(allocator, .{}), + try dt_rounded.toString(allocator, .{}), + try dt_with.toString(allocator, .{}), + dt_eq, + try dt_since.toString(allocator, .{}), + try dt_until.toString(allocator, .{}), + try dt_with_cal.toString(allocator, .{}), + try dt_with_time.toString(allocator, .{}), + }); + + // PlainTime: add, subtract, round, with, equals, since, until + const tm_added = try tm.add(dur); + const tm_sub = try tm.subtract(dur); + const tm_rounded = try tm.round(.{ .smallest_unit = Temporal.PlainTime.Unit.second }); + const tm_with = try tm.with(.{ .hour = 1 }); + const tm_eq = tm.equals(tm); + const tm_since = try tm.since(tm, Temporal.PlainTime.DifferenceSettings{}); + const tm_until = try tm.until(tm, Temporal.PlainTime.DifferenceSettings{}); + std.log.info( + \\PlainTime Advanced + \\ - add duration: {s} + \\ - subtract duration: {s} + \\ - round to second: {s} + \\ - with hour=1: {s} + \\ - equals self: {} + \\ - since self: {s} + \\ - until self: {s} + \\ + \\ + , .{ + try tm_added.toString(allocator), + try tm_sub.toString(allocator), + try tm_rounded.toString(allocator), + try tm_with.toString(allocator), + tm_eq, + try tm_since.toString(allocator, .{}), + try tm_until.toString(allocator, .{}), + }); + + // PlainYearMonth: add, subtract, with, equals, since, until, withCalendar + const ym_added = try ym.add(dur); + const ym_sub = try ym.subtract(dur); + const ym_with = try ym.with(.{ .year = 2025 }); + const ym_eq = ym.equals(ym); + const ym_since = try ym.since(ym, Temporal.PlainYearMonth.DifferenceSettings{}); + const ym_until = try ym.until(ym, Temporal.PlainYearMonth.DifferenceSettings{}); + std.log.info( + \\PlainYearMonth Advanced + \\ - add duration: {s} + \\ - subtract duration: {s} + \\ - with year=2025: {s} + \\ - equals self: {} + \\ - since self: {s} + \\ - until self: {s} + \\ + \\ + , .{ + try ym_added.toString(allocator), + try ym_sub.toString(allocator), + try ym_with.toString(allocator), + ym_eq, + try ym_since.toString(allocator, .{}), + try ym_until.toString(allocator, .{}), + }); + + // ZonedDateTime: add, subtract, round, with, equals, since, until, withCalendar, withPlainTime, withTimeZone + const zdt_added = try zdt.add(dur); + const zdt_sub = try zdt.subtract(dur); + const zdt_rounded = try zdt.round(.{ .smallest_unit = Temporal.ZonedDateTime.Unit.hour }); + // const zdt_with = try zdt.with(allocator, .{ .year = 2025 }); + const zdt_eq = zdt.equals(zdt); + const zdt_since = try zdt.since(zdt, Temporal.ZonedDateTime.DifferenceSettings{}); + const zdt_until = try zdt.until(zdt, Temporal.ZonedDateTime.DifferenceSettings{}); + const zdt_with_cal = try zdt.withCalendar("iso8601"); + const zdt_with_time = try zdt.withPlainTime(try Temporal.PlainTime.init(1, 2, 3, 4, 5, 6)); + const zdt_with_tz = try zdt.withTimeZone(tz); + std.log.info( + \\ZonedDateTime Advanced + \\ - add duration: {s} + \\ - subtract duration: {s} + \\ - round to hour: {s} + \\ - with year=2025: {{s}} + \\ - equals self: {} + \\ - since self: {s} + \\ - until self: {s} + \\ - withCalendar: {s} + \\ - withPlainTime: {s} + \\ - withTimeZone: {s} + \\ + \\ + , .{ + try zdt_added.toString(allocator, .{}), + try zdt_sub.toString(allocator, .{}), + try zdt_rounded.toString(allocator, .{}), + // try zdt_with.toString(allocator, .{}), + zdt_eq, + try zdt_since.toString(allocator, .{}), + try zdt_until.toString(allocator, .{}), + try zdt_with_cal.toString(allocator, .{}), + try zdt_with_time.toString(allocator, .{}), + try zdt_with_tz.toString(allocator, .{}), + }); +} + +extern fn consoleLog(ptr: [*]u8, len: u32) void; +pub fn logFn(comptime message_level: std.log.Level, comptime scope: @TypeOf(.enum_literal), comptime format: []const u8, args: anytype) void { + if (builtin.os.tag == .freestanding) { + const prefix = if (scope == .default) "" else "(" ++ @tagName(scope) ++ ") "; + const formatted = std.fmt.allocPrint(std.heap.wasm_allocator, prefix ++ format, args) catch return; + consoleLog(formatted.ptr, formatted.len); + } + + std.log.defaultLog(message_level, scope, format, args); +} + +pub const std_options: std.Options = .{ + .logFn = logFn, +}; diff --git a/example/src/wasm.zig b/example/src/wasm.zig new file mode 100644 index 0000000..36a1420 --- /dev/null +++ b/example/src/wasm.zig @@ -0,0 +1,16 @@ +const std = @import("std"); +const program = @import("root.zig"); + +export fn _start() void { + const allocator = std.heap.wasm_allocator; + program.run(allocator, null) catch {}; +} + +extern fn console(ptr: [*]u8, len: u32) void; + +fn logFn(comptime _: anytype, comptime _: anytype, comptime format: []const u8, args: anytype) void { + const formatted = std.fmt.allocPrint(std.heap.wasm_allocator, format, args) catch return; + console(formatted.ptr, formatted.len); +} + +pub const std_options: std.Options = .{ .logFn = logFn }; diff --git a/src/stubs/c_headers/assert.h b/src/stubs/c_headers/assert.h new file mode 100644 index 0000000..798ef7a --- /dev/null +++ b/src/stubs/c_headers/assert.h @@ -0,0 +1,10 @@ +#ifndef TEMPORALZ_ASSERT_H +#define TEMPORALZ_ASSERT_H + +#ifndef static_assert +#define static_assert _Static_assert +#endif + +#define assert(expr) ((void)0) + +#endif diff --git a/src/stubs/c_headers/stdbool.h b/src/stubs/c_headers/stdbool.h new file mode 100644 index 0000000..bd45db1 --- /dev/null +++ b/src/stubs/c_headers/stdbool.h @@ -0,0 +1,8 @@ +#ifndef TEMPORALZ_STDBOOL_H +#define TEMPORALZ_STDBOOL_H + +typedef _Bool bool; +#define true 1 +#define false 0 + +#endif diff --git a/src/stubs/c_headers/stddef.h b/src/stubs/c_headers/stddef.h new file mode 100644 index 0000000..3873456 --- /dev/null +++ b/src/stubs/c_headers/stddef.h @@ -0,0 +1,11 @@ +#ifndef TEMPORALZ_STDDEF_H +#define TEMPORALZ_STDDEF_H + +typedef unsigned long size_t; +typedef long ptrdiff_t; + +#ifndef NULL +#define NULL ((void*)0) +#endif + +#endif diff --git a/src/stubs/c_headers/stdint.h b/src/stubs/c_headers/stdint.h new file mode 100644 index 0000000..f48121b --- /dev/null +++ b/src/stubs/c_headers/stdint.h @@ -0,0 +1,25 @@ +#ifndef TEMPORALZ_STDINT_H +#define TEMPORALZ_STDINT_H + +typedef signed char int8_t; +typedef unsigned char uint8_t; +typedef signed short int16_t; +typedef unsigned short uint16_t; +typedef signed int int32_t; +typedef unsigned int uint32_t; +typedef signed long long int64_t; +typedef unsigned long long uint64_t; + +typedef int8_t int_least8_t; +typedef uint8_t uint_least8_t; +typedef int16_t int_least16_t; +typedef uint16_t uint_least16_t; +typedef int32_t int_least32_t; +typedef uint32_t uint_least32_t; +typedef int64_t int_least64_t; +typedef uint64_t uint_least64_t; + +typedef long intptr_t; +typedef unsigned long uintptr_t; + +#endif diff --git a/src/stubs/c_headers/stdio.h b/src/stubs/c_headers/stdio.h new file mode 100644 index 0000000..ba94e7c --- /dev/null +++ b/src/stubs/c_headers/stdio.h @@ -0,0 +1,7 @@ +#ifndef TEMPORALZ_STDIO_H +#define TEMPORALZ_STDIO_H + +typedef struct FILE FILE; +#define EOF (-1) + +#endif diff --git a/src/unwind_stubs.zig b/src/stubs/unwind.zig similarity index 100% rename from src/unwind_stubs.zig rename to src/stubs/unwind.zig