temporalz/src/temporal.zig
2026-01-26 14:32:32 +06:00

168 lines
5.7 KiB
Zig

const abi = @import("abi.zig");
const c = abi.c;
/// Time unit for Temporal operations.
/// See: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal
pub const Unit = enum {
auto,
nanosecond,
microsecond,
millisecond,
second,
minute,
hour,
day,
week,
month,
year,
pub fn toCApi(self: Unit) c_uint {
return switch (self) {
.auto => c.Unit_Auto,
.nanosecond => c.Unit_Nanosecond,
.microsecond => c.Unit_Microsecond,
.millisecond => c.Unit_Millisecond,
.second => c.Unit_Second,
.minute => c.Unit_Minute,
.hour => c.Unit_Hour,
.day => c.Unit_Day,
.week => c.Unit_Week,
.month => c.Unit_Month,
.year => c.Unit_Year,
};
}
};
/// Rounding mode for Temporal operations.
/// See: https://tc39.es/ecma402/#table-sanctioned-single-unit-identifiers
pub const RoundingMode = enum {
/// Round toward positive infinity
ceil,
/// Round toward negative infinity
floor,
/// Round away from zero
expand,
/// Round toward zero (truncate)
trunc,
/// Round half toward positive infinity
half_ceil,
/// Round half toward negative infinity
half_floor,
/// Round half away from zero
half_expand,
/// Round half toward zero
half_trunc,
/// Round half to even (banker's rounding)
half_even,
pub fn toCApi(self: RoundingMode) c_uint {
return switch (self) {
.ceil => c.RoundingMode_Ceil,
.floor => c.RoundingMode_Floor,
.expand => c.RoundingMode_Expand,
.trunc => c.RoundingMode_Trunc,
.half_ceil => c.RoundingMode_HalfCeil,
.half_floor => c.RoundingMode_HalfFloor,
.half_expand => c.RoundingMode_HalfExpand,
.half_trunc => c.RoundingMode_HalfTrunc,
.half_even => c.RoundingMode_HalfEven,
};
}
};
/// Sign of a duration or time value.
pub const Sign = enum {
positive,
zero,
negative,
pub fn toCApi(self: Sign) c_int {
return switch (self) {
.positive => c.Sign_Positive,
.zero => c.Sign_Zero,
.negative => c.Sign_Negative,
};
}
pub fn fromCApi(value: c_int) Sign {
return switch (value) {
c.Sign_Positive => .positive,
c.Sign_Zero => .zero,
c.Sign_Negative => .negative,
else => .zero,
};
}
};
/// 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 {
largest_unit: ?Unit = null,
smallest_unit: ?Unit = null,
rounding_mode: ?RoundingMode = null,
rounding_increment: ?u32 = null,
pub fn toCApi(self: RoundingOptions) c.RoundingOptions {
return .{
.largest_unit = abi.toUnitOption(toCUnit(self.largest_unit)),
.smallest_unit = abi.toUnitOption(toCUnit(self.smallest_unit)),
.rounding_mode = abi.toRoundingModeOption(toCRoundingMode(self.rounding_mode)),
.increment = abi.toOption(c.OptionU32, self.rounding_increment),
};
}
};
/// 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 {
largest_unit: ?Unit = null,
smallest_unit: ?Unit = null,
rounding_mode: ?RoundingMode = null,
rounding_increment: ?u32 = null,
pub fn toCApi(self: DifferenceSettings) c.DifferenceSettings {
return .{
.largest_unit = abi.toUnitOption(toCUnit(self.largest_unit)),
.smallest_unit = abi.toUnitOption(toCUnit(self.smallest_unit)),
.rounding_mode = abi.toRoundingModeOption(toCRoundingMode(self.rounding_mode)),
.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)),
};
}
};
fn toCUnit(opt: ?Unit) ?c.Unit {
return if (opt) |u| @as(c.Unit, @intCast(u.toCApi())) else null;
}
fn toCRoundingMode(opt: ?RoundingMode) ?c.RoundingMode {
return if (opt) |m| @as(c.RoundingMode, @intCast(m.toCApi())) else null;
}