feat(duration): add native zig types

This commit is contained in:
Nurul Huda (Apon) 2026-01-26 14:32:32 +06:00
parent acbadeb89a
commit 9b382eb796
No known key found for this signature in database
GPG key ID: 5D3F1DE2855A2F79
3 changed files with 43 additions and 29 deletions

View file

@ -177,14 +177,14 @@ pub fn toString(self: Duration, allocator: std.mem.Allocator, options: ToStringR
var write = abi.DiplomatWrite.init(allocator); var write = abi.DiplomatWrite.init(allocator);
defer write.deinit(); defer write.deinit();
const res = abi.c.temporal_rs_Duration_to_string(self._inner, options, &write.inner); const res = abi.c.temporal_rs_Duration_to_string(self._inner, options.toCApi(), &write.inner);
try handleVoidResult(res); try handleVoidResult(res);
return try write.toOwnedSlice(); return try write.toOwnedSlice();
} }
pub fn toJSON(self: Duration, allocator: std.mem.Allocator) ![]u8 { pub fn toJSON(self: Duration, allocator: std.mem.Allocator) ![]u8 {
return self.toString(allocator, defaultToStringRoundingOptions()); return self.toString(allocator, .{});
} }
pub fn toLocaleString(self: Duration, allocator: std.mem.Allocator) ![]u8 { pub fn toLocaleString(self: Duration, allocator: std.mem.Allocator) ![]u8 {
@ -214,26 +214,8 @@ fn wrapDuration(res: anytype) !Duration {
return .{ ._inner = ptr }; return .{ ._inner = ptr };
} }
fn defaultToStringRoundingOptions() ToStringRoundingOptions {
return abi.to_string_rounding_options_auto;
}
// --- Public helper types ----------------------------------------------------- // --- Public helper types -----------------------------------------------------
/// Options for Duration.toString()
/// See: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/Duration/toString
pub const ToStringOptions = struct {
/// Specifies the number of fractional seconds digits to display.
fractional_second_digits: ?u8 = null,
/// Specifies how to round off fractional second digits.
/// Defaults to "trunc" (truncate).
rounding_mode: ?RoundingMode = null,
/// Specifies the smallest unit to include in the output.
smallest_unit: ?Unit = null,
};
pub const PartialDuration = abi.c.PartialDuration; pub const PartialDuration = abi.c.PartialDuration;
/// Relative-to context for duration operations. /// Relative-to context for duration operations.
@ -253,7 +235,8 @@ const Unit_option = abi.c.Unit_option;
const RoundingMode_option = abi.c.RoundingMode_option; const RoundingMode_option = abi.c.RoundingMode_option;
pub const RoundingOptions = temporal.RoundingOptions; pub const RoundingOptions = temporal.RoundingOptions;
pub const ToStringRoundingOptions = abi.c.ToStringRoundingOptions; pub const ToStringOptions = temporal.ToStringRoundingOptions;
pub const ToStringRoundingOptions = temporal.ToStringRoundingOptions;
pub const Unit = temporal.Unit; pub const Unit = temporal.Unit;
pub const RoundingMode = temporal.RoundingMode; pub const RoundingMode = temporal.RoundingMode;
pub const Sign = temporal.Sign; pub const Sign = temporal.Sign;
@ -361,7 +344,7 @@ test toString {
defer dur.deinit(); defer dur.deinit();
const allocator = std.testing.allocator; const allocator = std.testing.allocator;
const str = try dur.toString(allocator, defaultToStringRoundingOptions()); const str = try dur.toString(allocator, .{});
defer allocator.free(str); defer allocator.free(str);
// Should output ISO 8601 duration format // Should output ISO 8601 duration format

View file

@ -362,7 +362,7 @@ test until {
.largest_unit = .hour, .largest_unit = .hour,
.smallest_unit = .second, .smallest_unit = .second,
.rounding_mode = .trunc, .rounding_mode = .trunc,
.increment = null, .rounding_increment = null,
}; };
var until_handle = try earlier.until(later, settings); var until_handle = try earlier.until(later, settings);
@ -386,7 +386,7 @@ test since {
.largest_unit = .hour, .largest_unit = .hour,
.smallest_unit = .second, .smallest_unit = .second,
.rounding_mode = .trunc, .rounding_mode = .trunc,
.increment = null, .rounding_increment = null,
}; };
var until_handle = try earlier.until(later, settings); var until_handle = try earlier.until(later, settings);
@ -408,7 +408,7 @@ test round {
.largest_unit = null, .largest_unit = null,
.smallest_unit = .second, .smallest_unit = .second,
.rounding_mode = .half_expand, .rounding_mode = .half_expand,
.increment = null, .rounding_increment = null,
}; };
const rounded = try inst.round(opts); const rounded = try inst.round(opts);

View file

@ -95,35 +95,66 @@ pub const Sign = enum {
}; };
/// Options for rounding operations (Instant.round, Duration.round, etc.). /// Options for rounding operations (Instant.round, Duration.round, etc.).
/// MDN: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/Duration/round
pub const RoundingOptions = struct { pub const RoundingOptions = struct {
largest_unit: ?Unit = null, largest_unit: ?Unit = null,
smallest_unit: ?Unit = null, smallest_unit: ?Unit = null,
rounding_mode: ?RoundingMode = null, rounding_mode: ?RoundingMode = null,
increment: ?u32 = null, rounding_increment: ?u32 = null,
pub fn toCApi(self: RoundingOptions) c.RoundingOptions { pub fn toCApi(self: RoundingOptions) c.RoundingOptions {
return .{ return .{
.largest_unit = abi.toUnitOption(toCUnit(self.largest_unit)), .largest_unit = abi.toUnitOption(toCUnit(self.largest_unit)),
.smallest_unit = abi.toUnitOption(toCUnit(self.smallest_unit)), .smallest_unit = abi.toUnitOption(toCUnit(self.smallest_unit)),
.rounding_mode = abi.toRoundingModeOption(toCRoundingMode(self.rounding_mode)), .rounding_mode = abi.toRoundingModeOption(toCRoundingMode(self.rounding_mode)),
.increment = abi.toOption(c.OptionU32, self.increment), .increment = abi.toOption(c.OptionU32, self.rounding_increment),
}; };
} }
}; };
/// Options for computing differences between instants. /// Options for computing differences between instants.
/// MDN: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/Instant/until
pub const DifferenceSettings = struct { pub const DifferenceSettings = struct {
largest_unit: ?Unit = null, largest_unit: ?Unit = null,
smallest_unit: ?Unit = null, smallest_unit: ?Unit = null,
rounding_mode: ?RoundingMode = null, rounding_mode: ?RoundingMode = null,
increment: ?u32 = null, rounding_increment: ?u32 = null,
pub fn toCApi(self: DifferenceSettings) c.DifferenceSettings { pub fn toCApi(self: DifferenceSettings) c.DifferenceSettings {
return .{ return .{
.largest_unit = abi.toUnitOption(toCUnit(self.largest_unit)), .largest_unit = abi.toUnitOption(toCUnit(self.largest_unit)),
.smallest_unit = abi.toUnitOption(toCUnit(self.smallest_unit)), .smallest_unit = abi.toUnitOption(toCUnit(self.smallest_unit)),
.rounding_mode = abi.toRoundingModeOption(toCRoundingMode(self.rounding_mode)), .rounding_mode = abi.toRoundingModeOption(toCRoundingMode(self.rounding_mode)),
.increment = abi.toOption(c.OptionU32, self.increment), .increment = abi.toOption(c.OptionU32, self.rounding_increment),
};
}
};
/// Options for Duration.toString() formatting.
/// MDN: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/Duration/toString
pub const ToStringRoundingOptions = struct {
fractional_second_digits: ?u8 = null,
smallest_unit: ?Unit = null,
rounding_mode: ?RoundingMode = null,
pub fn toCApi(self: ToStringRoundingOptions) c.ToStringRoundingOptions {
const precision: c.Precision = if (self.fractional_second_digits) |fsd|
.{ .is_minute = false, .precision = abi.toOption(c.OptionU8, fsd) }
else if (self.smallest_unit) |su|
switch (su) {
.second => .{ .is_minute = false, .precision = abi.toOption(c.OptionU8, 0) },
.millisecond => .{ .is_minute = false, .precision = abi.toOption(c.OptionU8, 3) },
.microsecond => .{ .is_minute = false, .precision = abi.toOption(c.OptionU8, 6) },
.nanosecond => .{ .is_minute = false, .precision = abi.toOption(c.OptionU8, 9) },
else => .{ .is_minute = false, .precision = abi.toOption(c.OptionU8, null) },
}
else
.{ .is_minute = false, .precision = abi.toOption(c.OptionU8, null) };
return .{
.precision = precision,
.smallest_unit = abi.toUnitOption(toCUnit(self.smallest_unit)),
.rounding_mode = abi.toRoundingModeOption(toCRoundingMode(self.rounding_mode)),
}; };
} }
}; };