refactor: abstract abi

This commit is contained in:
Nurul Huda (Apon) 2026-01-30 02:51:09 +06:00
parent 68f2bad1a8
commit f4f7c35a23
No known key found for this signature in database
GPG key ID: 5D3F1DE2855A2F79
10 changed files with 250 additions and 245 deletions

View file

@ -1,6 +1,6 @@
const std = @import("std");
const abi = @import("abi.zig");
const temporal = @import("temporal.zig");
const t = @import("temporal.zig");
const PlainDate = @import("PlainDate.zig");
const PlainDateTime = @import("PlainDateTime.zig");
@ -8,11 +8,13 @@ const ZonedDateTime = @import("ZonedDateTime.zig");
const Duration = @This();
pub const ToStringOptions = temporal.ToStringRoundingOptions;
pub const ToStringRoundingOptions = temporal.ToStringRoundingOptions;
pub const Unit = temporal.Unit;
pub const RoundingMode = temporal.RoundingMode;
pub const Sign = temporal.Sign;
_inner: *abi.c.Duration,
pub const ToStringOptions = t.ToStringRoundingOptions;
pub const ToStringRoundingOptions = t.ToStringRoundingOptions;
pub const Unit = t.Unit;
pub const RoundingMode = t.RoundingMode;
pub const Sign = t.Sign;
pub const RoundingOptions = struct {
largest_unit: ?Unit = null,
@ -20,15 +22,6 @@ pub const RoundingOptions = struct {
rounding_mode: ?RoundingMode = null,
rounding_increment: ?u32 = null,
relative_to: ?RelativeTo = null,
pub fn toCApi(self: RoundingOptions) abi.c.RoundingOptions {
return .{
.largest_unit = abi.toUnitOption(temporal.toCUnit(self.largest_unit)),
.smallest_unit = abi.toUnitOption(temporal.toCUnit(self.smallest_unit)),
.rounding_mode = abi.toRoundingModeOption(temporal.toCRoundingMode(self.rounding_mode)),
.increment = abi.toOption(abi.c.OptionU32, self.rounding_increment),
};
}
};
/// Partial duration specification for creating Duration objects.
@ -44,31 +37,6 @@ pub const PartialDuration = struct {
milliseconds: ?i64 = null,
microseconds: ?f64 = null,
nanoseconds: ?f64 = null,
fn toCApi(self: PartialDuration) abi.c.PartialDuration {
return .{
.years = abi.toOption(abi.c.OptionI64, self.years),
.months = abi.toOption(abi.c.OptionI64, self.months),
.weeks = abi.toOption(abi.c.OptionI64, self.weeks),
.days = abi.toOption(abi.c.OptionI64, self.days),
.hours = abi.toOption(abi.c.OptionI64, self.hours),
.minutes = abi.toOption(abi.c.OptionI64, self.minutes),
.seconds = abi.toOption(abi.c.OptionI64, self.seconds),
.milliseconds = abi.toOption(abi.c.OptionI64, self.milliseconds),
.microseconds = abi.toOption(abi.c.OptionF64, self.microseconds),
.nanoseconds = abi.toOption(abi.c.OptionF64, self.nanoseconds),
};
}
};
/// Wrapper for PlainDate reference in RelativeTo
const PlainDateRef = struct {
_inner: *abi.c.PlainDate,
};
/// Wrapper for ZonedDateTime reference in RelativeTo
const ZonedDateTimeRef = struct {
_inner: *abi.c.ZonedDateTime,
};
/// Relative-to context for duration operations.
@ -76,14 +44,6 @@ pub const RelativeTo = union(enum) {
plain_date: PlainDate,
plain_date_time: PlainDateTime,
zoned_date_time: ZonedDateTime,
fn toCApi(self: RelativeTo) abi.c.RelativeTo {
switch (self) {
.plain_date => |pd| return .{ .date = pd._inner },
.zoned_date_time => |zdt| return .{ .zoned = zdt._inner },
.plain_date_time => |pdt| return .{ .date = (pdt.toPlainDate() catch unreachable)._inner },
}
}
};
/// Options for Duration.total() providing unit and relative-to context.
@ -96,8 +56,6 @@ pub const CompareOptions = struct {
relative_to: ?RelativeTo = null,
};
_inner: *abi.c.Duration,
/// Construct a Duration from years, months, weeks, days, hours, minutes, seconds, milliseconds, microseconds, and nanoseconds.
/// Equivalent to `Temporal.Duration.from()` or the constructor.
pub fn init(
@ -176,7 +134,7 @@ inline fn fromUtf8(text: []const u8) !Duration {
/// Create a Duration from a partial duration (where some fields may be omitted).
fn fromPartialDuration(partial: PartialDuration) !Duration {
return wrapDuration(abi.c.temporal_rs_Duration_from_partial_duration(partial.toCApi()));
return wrapDuration(abi.c.temporal_rs_Duration_from_partial_duration(abi.to.partialdur(partial)));
}
/// Check if the time portion of the duration is within valid ranges.
@ -236,7 +194,7 @@ pub fn nanoseconds(self: Duration) f64 {
/// Get the sign of the duration: positive (1), zero (0), or negative (-1).
pub fn sign(self: Duration) Sign {
return Sign.fromCApi(abi.c.temporal_rs_Duration_sign(self._inner));
return abi.from.sign(abi.c.temporal_rs_Duration_sign(self._inner));
}
/// Check if the duration is zero (all fields are zero).
@ -268,8 +226,8 @@ pub fn subtract(self: Duration, other: Duration) !Duration {
/// Round the duration according to the specified options (Temporal.Duration.prototype.round).
pub fn round(self: Duration, options: RoundingOptions) !Duration {
const rel = if (options.relative_to) |r| r.toCApi() else abi.c.RelativeTo{ .date = null, .zoned = null };
return wrapDuration(abi.c.temporal_rs_Duration_round(self._inner, options.toCApi(), rel));
const rel = if (options.relative_to) |r| abi.to.durRelativeTo(r) else abi.c.RelativeTo{ .date = null, .zoned = null };
return wrapDuration(abi.c.temporal_rs_Duration_round(self._inner, abi.to.durRoundingOpts(options), rel));
}
/// Round the duration with an explicit provider.
@ -279,7 +237,7 @@ fn roundWithProvider(self: Duration, options: RoundingOptions, relative_to: Rela
/// Compare two durations (Temporal.Duration.compare).
pub fn compare(self: Duration, other: Duration, options: CompareOptions) !i8 {
const rel = if (options.relative_to) |r| r.toCApi() else abi.c.RelativeTo{ .date = null, .zoned = null };
const rel = if (options.relative_to) |r| abi.to.durRelativeTo(r) else abi.c.RelativeTo{ .date = null, .zoned = null };
const res = abi.c.temporal_rs_Duration_compare(self._inner, other._inner, rel);
return try abi.extractResult(res);
}
@ -292,14 +250,14 @@ fn compareWithProvider(self: Duration, other: Duration, relative_to: RelativeTo,
/// Get the total value of the duration in the specified unit (Temporal.Duration.prototype.total).
pub fn total(self: Duration, options: TotalOptions) !f64 {
const rel = if (options.relative_to) |r| r.toCApi() else abi.c.RelativeTo{ .date = null, .zoned = null };
const res = abi.c.temporal_rs_Duration_total(self._inner, options.unit.toCApi(), rel);
const rel = if (options.relative_to) |r| abi.to.durRelativeTo(r) else abi.c.RelativeTo{ .date = null, .zoned = null };
const res = abi.c.temporal_rs_Duration_total(self._inner, abi.to.unit(options.unit).?, rel);
return try abi.extractResult(res);
}
/// Get the total value of the duration with an explicit provider.
fn totalWithProvider(self: Duration, options: TotalOptions, provider: *const abi.c.Provider) !f64 {
const rel = if (options.relative_to) |r| r.toCApi() else abi.c.RelativeTo{ .date = null, .zoned = null };
const rel = if (options.relative_to) |r| abi.to.durRelativeTo(r) else abi.c.RelativeTo{ .date = null, .zoned = null };
const res = abi.c.temporal_rs_Duration_total_with_provider(self._inner, options.unit.toCApi(), rel, provider);
return try abi.extractResult(res);
}
@ -309,7 +267,7 @@ pub fn toString(self: Duration, allocator: std.mem.Allocator, options: ToStringR
var write = abi.DiplomatWrite.init(allocator);
defer write.deinit();
const res = abi.c.temporal_rs_Duration_to_string(self._inner, options.toCApi(), &write.inner);
const res = abi.c.temporal_rs_Duration_to_string(self._inner, abi.to.strRoundingOpts(options), &write.inner);
try handleVoidResult(res);
return try write.toOwnedSlice();
@ -580,15 +538,15 @@ test total {
const dur = try Duration.init(0, 0, 0, 0, 1, 30, 0, 0, 0, 0);
defer dur.deinit();
const t = try dur.total(.{ .unit = .hour });
try std.testing.expectEqual(1.5, t);
const ttl = try dur.total(.{ .unit = .hour });
try std.testing.expectEqual(1.5, ttl);
}
{
const dur = try Duration.from("PT4H5M6S");
defer dur.deinit();
const t = try dur.total(.{ .unit = .hour });
try std.testing.expectEqual(4.085, t);
const ttl = try dur.total(.{ .unit = .hour });
try std.testing.expectEqual(4.085, ttl);
}
{

View file

@ -1,30 +1,19 @@
const std = @import("std");
const abi = @import("abi.zig");
const temporal = @import("temporal.zig");
const t = @import("temporal.zig");
const Duration = @import("Duration.zig");
const Instant = @This();
pub const Unit = temporal.Unit;
pub const RoundingMode = temporal.RoundingMode;
pub const Sign = temporal.Sign;
pub const RoundingOptions = temporal.RoundingOptions;
pub const DifferenceSettings = temporal.DifferenceSettings;
_inner: *abi.c.Instant,
/// Time zone identifier for Temporal operations
pub const TimeZone = struct {
_inner: abi.c.TimeZone,
pub fn init(id: []const u8) TimeZone {
const view = abi.toDiplomatStringView(id);
return .{ ._inner = .{ .id = view } };
}
fn toCApi(self: TimeZone) abi.c.TimeZone {
return self._inner;
}
};
pub const Unit = t.Unit;
pub const RoundingMode = t.RoundingMode;
pub const Sign = t.Sign;
pub const RoundingOptions = t.RoundingOptions;
pub const DifferenceSettings = t.DifferenceSettings;
pub const TimeZone = t.TimeZone;
/// Options for Instant.toString()
/// See: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/Instant/toString
@ -47,8 +36,6 @@ pub const ToStringOptions = struct {
time_zone: ?TimeZone = null,
};
_inner: *abi.c.Instant,
/// Construct from epoch nanoseconds (Temporal.Instant.fromEpochNanoseconds).
pub fn init(epoch_ns: i128) !Instant {
return fromEpochNanoseconds(epoch_ns);
@ -112,19 +99,19 @@ pub fn subtract(self: Instant, duration: *Duration) !Instant {
/// Difference until another instant (Temporal.Instant.prototype.until).
pub fn until(self: Instant, other: Instant, settings: DifferenceSettings) !Duration {
const ptr = (try abi.extractResult(abi.c.temporal_rs_Instant_until(self._inner, other._inner, settings.toCApi()))) orelse return abi.TemporalError.Generic;
const ptr = (try abi.extractResult(abi.c.temporal_rs_Instant_until(self._inner, other._inner, abi.to.diffsettings(settings)))) orelse return abi.TemporalError.Generic;
return .{ ._inner = ptr };
}
/// Difference since another instant (Temporal.Instant.prototype.since).
pub fn since(self: Instant, other: Instant, settings: DifferenceSettings) !Duration {
const ptr = (try abi.extractResult(abi.c.temporal_rs_Instant_since(self._inner, other._inner, settings.toCApi()))) orelse return abi.TemporalError.Generic;
const ptr = (try abi.extractResult(abi.c.temporal_rs_Instant_since(self._inner, other._inner, abi.to.diffsettings(settings)))) orelse return abi.TemporalError.Generic;
return .{ ._inner = ptr };
}
/// Round this instant (Temporal.Instant.prototype.round).
pub fn round(self: Instant, options: RoundingOptions) !Instant {
return wrapInstant(abi.c.temporal_rs_Instant_round(self._inner, options.toCApi()));
return wrapInstant(abi.c.temporal_rs_Instant_round(self._inner, abi.to.roundingOpts(options)));
}
/// Compare two instants (Temporal.Instant.compare).
@ -235,8 +222,8 @@ fn optsToRounding(opts: ToStringOptions) abi.c.ToStringRoundingOptions {
else
defaultPrecision();
const smallest_unit = if (opts.smallest_unit) |unit| unit.toCApi() else null;
const rounding_mode = if (opts.rounding_mode) |mode| mode.toCApi() else null;
const smallest_unit = if (opts.smallest_unit) |unit| abi.to.unit(unit).? else null;
const rounding_mode = if (opts.rounding_mode) |mode| abi.to.roundingMode(mode) else null;
return .{
.precision = precision,

View file

@ -1,6 +1,6 @@
const std = @import("std");
const abi = @import("abi.zig");
const temporal = @import("temporal.zig");
const t = @import("temporal.zig");
const PlainDateTime = @import("PlainDateTime.zig");
const PlainMonthDay = @import("PlainMonthDay.zig");
@ -11,10 +11,12 @@ const Duration = @import("Duration.zig");
const PlainDate = @This();
pub const Unit = temporal.Unit;
pub const RoundingMode = temporal.RoundingMode;
pub const Sign = temporal.Sign;
pub const DifferenceSettings = temporal.DifferenceSettings;
_inner: *abi.c.PlainDate,
pub const Unit = t.Unit;
pub const RoundingMode = t.RoundingMode;
pub const Sign = t.Sign;
pub const DifferenceSettings = t.DifferenceSettings;
pub const ToStringOptions = struct {
calendar_id: ?CalendarDisplay = null,
@ -41,8 +43,6 @@ pub const ToZonedDateTimeOptions = struct {
plain_time: ?PlainTime = null,
};
_inner: *abi.c.PlainDate,
pub fn init(year_val: i32, month_val: u8, day_val: u8) !PlainDate {
return calInit(year_val, month_val, day_val, "iso8601");
}
@ -104,12 +104,12 @@ pub fn subtract(self: PlainDate, duration: Duration) !PlainDate {
}
pub fn until(self: PlainDate, other: PlainDate, settings: DifferenceSettings) !Duration {
const ptr = (try abi.extractResult(abi.c.temporal_rs_PlainDate_until(self._inner, other._inner, settings.toCApi()))) orelse return abi.TemporalError.Generic;
const ptr = (try abi.extractResult(abi.c.temporal_rs_PlainDate_until(self._inner, other._inner, abi.to.diffsettings(settings)))) orelse return abi.TemporalError.Generic;
return .{ ._inner = ptr };
}
pub fn since(self: PlainDate, other: PlainDate, settings: DifferenceSettings) !Duration {
const ptr = (try abi.extractResult(abi.c.temporal_rs_PlainDate_since(self._inner, other._inner, settings.toCApi()))) orelse return abi.TemporalError.Generic;
const ptr = (try abi.extractResult(abi.c.temporal_rs_PlainDate_since(self._inner, other._inner, abi.to.diffsettings(settings)))) orelse return abi.TemporalError.Generic;
return .{ ._inner = ptr };
}
@ -129,7 +129,7 @@ pub fn withCalendar(self: PlainDate, calendar: []const u8) !PlainDate {
}
pub fn toPlainDateTime(self: PlainDate, time: ?PlainTime) !PlainDateTime {
const time_ptr = if (time) |t| t._inner else null;
const time_ptr = if (time) |tt| tt._inner else null;
const ptr = (try abi.extractResult(abi.c.temporal_rs_PlainDate_to_plain_date_time(self._inner, time_ptr))) orelse return abi.TemporalError.Generic;
return .{ ._inner = ptr };
}
@ -149,7 +149,7 @@ pub fn toZonedDateTime(self: PlainDate, options: ToZonedDateTimeOptions) !ZonedD
const tz_result = abi.c.temporal_rs_TimeZone_try_from_str(tz_view);
const time_zone = try abi.extractResult(tz_result);
const time_ptr = if (options.plain_time) |t| t._inner else null;
const time_ptr = if (options.plain_time) |tt| tt._inner else null;
const ptr = (try abi.extractResult(abi.c.temporal_rs_PlainDate_to_zoned_date_time(self._inner, time_zone, time_ptr))) orelse return abi.TemporalError.Generic;
return .{ ._inner = ptr };

View file

@ -1,6 +1,6 @@
const std = @import("std");
const abi = @import("abi.zig");
const temporal = @import("temporal.zig");
const t = @import("temporal.zig");
const PlainDate = @import("PlainDate.zig");
const PlainTime = @import("PlainTime.zig");
@ -12,11 +12,11 @@ const PlainDateTime = @This();
_inner: *abi.c.PlainDateTime,
// Import types from temporal.zig
pub const Unit = temporal.Unit;
pub const RoundingMode = temporal.RoundingMode;
pub const Sign = temporal.Sign;
pub const DifferenceSettings = temporal.DifferenceSettings;
pub const RoundOptions = temporal.RoundingOptions;
pub const Unit = t.Unit;
pub const RoundingMode = t.RoundingMode;
pub const Sign = t.Sign;
pub const DifferenceSettings = t.DifferenceSettings;
pub const RoundOptions = t.RoundingOptions;
// Type definitions for API compatibility
pub const CalendarDisplay = enum {
auto,
@ -208,20 +208,20 @@ pub fn subtract(self: PlainDateTime, duration: Duration) !PlainDateTime {
}
pub fn until(self: PlainDateTime, other: PlainDateTime, options: DifferenceSettings) !Duration {
const result = abi.c.temporal_rs_PlainDateTime_until(self._inner, other._inner, options.toCApi());
const result = abi.c.temporal_rs_PlainDateTime_until(self._inner, other._inner, abi.to.diffsettings(options));
const ptr = (try abi.extractResult(result)) orelse return abi.TemporalError.Generic;
return .{ ._inner = ptr };
}
pub fn since(self: PlainDateTime, other: PlainDateTime, options: DifferenceSettings) !Duration {
const result = abi.c.temporal_rs_PlainDateTime_since(self._inner, other._inner, options.toCApi());
const result = abi.c.temporal_rs_PlainDateTime_since(self._inner, other._inner, abi.to.diffsettings(options));
const ptr = (try abi.extractResult(result)) orelse return abi.TemporalError.Generic;
return .{ ._inner = ptr };
}
// Rounding
pub fn round(self: PlainDateTime, options: RoundOptions) !PlainDateTime {
return wrapPlainDateTime(abi.c.temporal_rs_PlainDateTime_round(self._inner, options.toCApi()));
return wrapPlainDateTime(abi.c.temporal_rs_PlainDateTime_round(self._inner, abi.to.roundingOpts(options)));
}
// Property accessors - Date fields
@ -375,12 +375,12 @@ pub fn withCalendar(self: PlainDateTime, calendar: []const u8) !PlainDateTime {
}
pub fn withPlainTime(self: PlainDateTime, time: ?PlainTime) !PlainDateTime {
const new_hour: u8 = if (time) |t| t.hour() else 0;
const new_minute: u8 = if (time) |t| t.minute() else 0;
const new_second: u8 = if (time) |t| t.second() else 0;
const new_millisecond: u16 = if (time) |t| t.millisecond() else 0;
const new_microsecond: u16 = if (time) |t| t.microsecond() else 0;
const new_nanosecond: u16 = if (time) |t| t.nanosecond() else 0;
const new_hour: u8 = if (time) |tt| tt.hour() else 0;
const new_minute: u8 = if (time) |tt| tt.minute() else 0;
const new_second: u8 = if (time) |tt| tt.second() else 0;
const new_millisecond: u16 = if (time) |tt| tt.millisecond() else 0;
const new_microsecond: u16 = if (time) |tt| tt.microsecond() else 0;
const new_nanosecond: u16 = if (time) |tt| tt.nanosecond() else 0;
const calendar_ptr = abi.c.temporal_rs_PlainDateTime_calendar(self._inner) orelse return error.TemporalError;
const cal_id_view = abi.c.temporal_rs_Calendar_identifier(calendar_ptr);
@ -597,10 +597,10 @@ test toPlainDate {
test toPlainTime {
const dt = try PlainDateTime.init(2024, 1, 15, 14, 30, 45, 0, 0, 0);
const t = try dt.toPlainTime();
try std.testing.expectEqual(@as(u8, 14), t.hour());
try std.testing.expectEqual(@as(u8, 30), t.minute());
try std.testing.expectEqual(@as(u8, 45), t.second());
const tt = try dt.toPlainTime();
try std.testing.expectEqual(@as(u8, 14), tt.hour());
try std.testing.expectEqual(@as(u8, 30), tt.minute());
try std.testing.expectEqual(@as(u8, 45), tt.second());
}
test toZonedDateTime {
@ -635,8 +635,8 @@ test withCalendar {
test withPlainTime {
const dt = try PlainDateTime.init(2024, 1, 15, 14, 30, 0, 0, 0, 0);
const t = try PlainTime.from("10:15:30");
const result = try dt.withPlainTime(t);
const tt = try PlainTime.from("10:15:30");
const result = try dt.withPlainTime(tt);
try std.testing.expectEqual(@as(u8, 10), result.hour());
try std.testing.expectEqual(@as(u8, 15), result.minute());
try std.testing.expectEqual(@as(u8, 30), result.second());

View file

@ -1,9 +1,10 @@
const std = @import("std");
const abi = @import("abi.zig");
const temporal_types = @import("temporal.zig");
const t = @import("temporal.zig");
const PlainDate = @import("PlainDate.zig");
const PlainMonthDay = @This();
const PlainDate = @import("PlainDate.zig");
_inner: *abi.c.PlainMonthDay,

View file

@ -1,17 +1,18 @@
const std = @import("std");
const abi = @import("abi.zig");
const temporal_types = @import("temporal.zig");
const t = @import("temporal.zig");
const Duration = @import("Duration.zig");
const PlainTime = @This();
const Duration = @import("Duration.zig");
_inner: *abi.c.PlainTime,
// Import types from temporal.zig
pub const Unit = temporal_types.Unit;
pub const RoundingMode = temporal_types.RoundingMode;
pub const DifferenceSettings = temporal_types.DifferenceSettings;
pub const RoundOptions = temporal_types.RoundingOptions;
pub const Unit = t.Unit;
pub const RoundingMode = t.RoundingMode;
pub const DifferenceSettings = t.DifferenceSettings;
pub const RoundOptions = t.RoundingOptions;
pub const WithOptions = struct {
hour: ?u8 = null,
@ -81,14 +82,14 @@ pub fn subtract(self: PlainTime, duration: Duration) !PlainTime {
}
pub fn until(self: PlainTime, other: PlainTime, options: DifferenceSettings) !Duration {
const settings = options.toCApi();
const settings = abi.to.diffsettings(options);
const result = abi.c.temporal_rs_PlainTime_until(self._inner, other._inner, settings);
const ptr = (try abi.extractResult(result)) orelse return abi.TemporalError.Generic;
return .{ ._inner = ptr };
}
pub fn since(self: PlainTime, other: PlainTime, options: DifferenceSettings) !Duration {
const settings = options.toCApi();
const settings = abi.to.diffsettings(options);
const result = abi.c.temporal_rs_PlainTime_since(self._inner, other._inner, settings);
const ptr = (try abi.extractResult(result)) orelse return abi.TemporalError.Generic;
return .{ ._inner = ptr };
@ -96,7 +97,7 @@ pub fn since(self: PlainTime, other: PlainTime, options: DifferenceSettings) !Du
// Rounding
pub fn round(self: PlainTime, options: RoundOptions) !PlainTime {
return wrapPlainTime(abi.c.temporal_rs_PlainTime_round(self._inner, options.toCApi()));
return wrapPlainTime(abi.c.temporal_rs_PlainTime_round(self._inner, abi.to.roundingOpts(options)));
}
// Property accessors
@ -146,8 +147,8 @@ pub fn toString(self: PlainTime, allocator: std.mem.Allocator) ![]u8 {
return toStringWithOptions(self, allocator, .{});
}
fn toStringWithOptions(self: PlainTime, allocator: std.mem.Allocator, options: temporal_types.ToStringRoundingOptions) ![]u8 {
const rounding_opts = options.toCApi();
fn toStringWithOptions(self: PlainTime, allocator: std.mem.Allocator, options: t.ToStringRoundingOptions) ![]u8 {
const rounding_opts = abi.to.strRoundingOpts(options);
var write = abi.DiplomatWrite.init(allocator);
defer write.deinit();

View file

@ -1,18 +1,19 @@
const std = @import("std");
const abi = @import("abi.zig");
const temporal_types = @import("temporal.zig");
const t = @import("temporal.zig");
const PlainYearMonth = @This();
const PlainDate = @import("PlainDate.zig");
const Duration = @import("Duration.zig");
const PlainYearMonth = @This();
_inner: *abi.c.PlainYearMonth,
// Import types from temporal.zig
pub const Unit = temporal_types.Unit;
pub const RoundingMode = temporal_types.RoundingMode;
pub const DifferenceSettings = temporal_types.DifferenceSettings;
pub const RoundOptions = temporal_types.RoundingOptions;
pub const Unit = t.Unit;
pub const RoundingMode = t.RoundingMode;
pub const DifferenceSettings = t.DifferenceSettings;
pub const RoundOptions = t.RoundingOptions;
// Type definitions for API compatibility
pub const CalendarDisplay = enum {
@ -95,14 +96,14 @@ pub fn subtract(self: PlainYearMonth, duration: Duration) !PlainYearMonth {
}
pub fn until(self: PlainYearMonth, other: PlainYearMonth, options: DifferenceSettings) !Duration {
const settings = options.toCApi();
const settings = abi.to.diffsettings(options);
const result = abi.c.temporal_rs_PlainYearMonth_until(self._inner, other._inner, settings);
const ptr = (try abi.extractResult(result)) orelse return abi.TemporalError.Generic;
return .{ ._inner = ptr };
}
pub fn since(self: PlainYearMonth, other: PlainYearMonth, options: DifferenceSettings) !Duration {
const settings = options.toCApi();
const settings = abi.to.diffsettings(options);
const result = abi.c.temporal_rs_PlainYearMonth_since(self._inner, other._inner, settings);
const ptr = (try abi.extractResult(result)) orelse return abi.TemporalError.Generic;
return .{ ._inner = ptr };

View file

@ -1,6 +1,6 @@
const std = @import("std");
const abi = @import("abi.zig");
const temporal_types = @import("temporal.zig");
const t = @import("temporal.zig");
const Instant = @import("Instant.zig");
const PlainDate = @import("PlainDate.zig");
@ -13,11 +13,11 @@ const ZonedDateTime = @This();
_inner: *abi.c.ZonedDateTime,
// Import types from temporal.zig
pub const Unit = temporal_types.Unit;
pub const RoundingMode = temporal_types.RoundingMode;
pub const Sign = temporal_types.Sign;
pub const DifferenceSettings = temporal_types.DifferenceSettings;
pub const RoundOptions = temporal_types.RoundingOptions;
pub const Unit = t.Unit;
pub const RoundingMode = t.RoundingMode;
pub const Sign = t.Sign;
pub const DifferenceSettings = t.DifferenceSettings;
pub const RoundOptions = t.RoundingOptions;
pub const TimeZone = struct {
_inner: abi.c.TimeZone,
@ -179,12 +179,12 @@ pub fn getTimeZoneTransition(self: ZonedDateTime, direction: enum { next, previo
/// Round to the given options
pub fn round(self: ZonedDateTime, options: RoundOptions) !ZonedDateTime {
return wrapZonedDateTime(abi.c.temporal_rs_ZonedDateTime_round(self._inner, options.toCApi()));
return wrapZonedDateTime(abi.c.temporal_rs_ZonedDateTime_round(self._inner, abi.to.roundingOpts(options)));
}
/// Calculate duration since another ZonedDateTime
pub fn since(self: ZonedDateTime, other: ZonedDateTime, settings: DifferenceSettings) !Duration {
const ptr = try abi.extractResult(abi.c.temporal_rs_ZonedDateTime_since(self._inner, other._inner, settings.toCApi()));
const ptr = try abi.extractResult(abi.c.temporal_rs_ZonedDateTime_since(self._inner, other._inner, abi.to.diffsettings(settings)));
return .{ ._inner = ptr };
}
@ -253,7 +253,7 @@ pub fn toString(self: ZonedDateTime, allocator: std.mem.Allocator, opts: ToStrin
/// Calculate duration until another ZonedDateTime
pub fn until(self: ZonedDateTime, other: ZonedDateTime, settings: DifferenceSettings) !Duration {
const ptr = try abi.extractResult(abi.c.temporal_rs_ZonedDateTime_until(self._inner, other._inner, settings.toCApi()));
const ptr = try abi.extractResult(abi.c.temporal_rs_ZonedDateTime_until(self._inner, other._inner, abi.to.diffsettings(settings)));
return .{ ._inner = ptr };
}
@ -281,7 +281,7 @@ pub fn withCalendar(self: ZonedDateTime, calendar: []const u8) !ZonedDateTime {
/// Create a new ZonedDateTime with a different time
pub fn withPlainTime(self: ZonedDateTime, time: ?PlainTime) !ZonedDateTime {
const time_ptr = if (time) |t| t._inner else null;
const time_ptr = if (time) |tt| tt._inner else null;
return wrapZonedDateTime(abi.c.temporal_rs_ZonedDateTime_with_plain_time(self._inner, time_ptr));
}

View file

@ -304,3 +304,145 @@ pub inline fn extractResult(result: anytype) TemporalError!Success(@TypeOf(resul
// Fallback for result types without detailed error information
return TemporalError.Generic;
}
const t = @import("temporal.zig");
const dur = @import("Duration.zig");
const ins = @import("Instant.zig");
pub const to = struct {
pub fn unit(opt: ?t.Unit) ?c.Unit {
return if (opt) |u| @as(c.Unit, @intCast(to.unitToCApi(u))) else null;
}
fn unitToCApi(u: t.Unit) c_uint {
return switch (u) {
.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,
};
}
pub fn roundingMode(opt: ?t.RoundingMode) ?c.RoundingMode {
return if (opt) |m| @as(c.RoundingMode, @intCast(to.roundingModeToCApi(m))) else null;
}
fn roundingModeToCApi(m: t.RoundingMode) c_uint {
return switch (m) {
.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,
};
}
pub fn sign(opt: ?t.Sign) ?c.Sign {
return if (opt) |s| @as(c.Sign, @intCast(to.signToCApi(s))) else null;
}
fn signToCApi(s: t.Sign) c_int {
return switch (s) {
.positive => c.Sign_Positive,
.zero => c.Sign_Zero,
.negative => c.Sign_Negative,
};
}
pub fn strRoundingOpts(self: t.ToStringRoundingOptions) c.ToStringRoundingOptions {
const precision: c.Precision = if (self.fractional_second_digits) |fsd|
.{ .is_minute = false, .precision = toOption(c.OptionU8, fsd) }
else if (self.smallest_unit) |su|
switch (su) {
.second => .{ .is_minute = false, .precision = toOption(c.OptionU8, 0) },
.millisecond => .{ .is_minute = false, .precision = toOption(c.OptionU8, 3) },
.microsecond => .{ .is_minute = false, .precision = toOption(c.OptionU8, 6) },
.nanosecond => .{ .is_minute = false, .precision = toOption(c.OptionU8, 9) },
else => .{ .is_minute = false, .precision = toOption(c.OptionU8, null) },
}
else
.{ .is_minute = false, .precision = toOption(c.OptionU8, null) };
return .{
.precision = precision,
.smallest_unit = toUnitOption(unit(self.smallest_unit)),
.rounding_mode = toRoundingModeOption(roundingMode(self.rounding_mode)),
};
}
pub fn durRoundingOpts(self: dur.RoundingOptions) c.RoundingOptions {
return .{
.largest_unit = toUnitOption(unit(self.largest_unit)),
.smallest_unit = toUnitOption(unit(self.smallest_unit)),
.rounding_mode = toRoundingModeOption(roundingMode(self.rounding_mode)),
.increment = toOption(c.OptionU32, self.rounding_increment),
};
}
pub fn tz(self: ins.TimeZone) c.TimeZone {
return self._inner;
}
pub fn partialdur(self: dur.PartialDuration) c.PartialDuration {
return .{
.years = toOption(c.OptionI64, self.years),
.months = toOption(c.OptionI64, self.months),
.weeks = toOption(c.OptionI64, self.weeks),
.days = toOption(c.OptionI64, self.days),
.hours = toOption(c.OptionI64, self.hours),
.minutes = toOption(c.OptionI64, self.minutes),
.seconds = toOption(c.OptionI64, self.seconds),
.milliseconds = toOption(c.OptionI64, self.milliseconds),
.microseconds = toOption(c.OptionF64, self.microseconds),
.nanoseconds = toOption(c.OptionF64, self.nanoseconds),
};
}
pub fn durRelativeTo(self: dur.RelativeTo) c.RelativeTo {
switch (self) {
.plain_date => |pd| return .{ .date = pd._inner },
.zoned_date_time => |zdt| return .{ .zoned = zdt._inner },
.plain_date_time => |pdt| return .{ .date = (pdt.toPlainDate() catch unreachable)._inner },
}
}
pub fn roundingOpts(self: t.RoundingOptions) c.RoundingOptions {
return .{
.largest_unit = toUnitOption(to.unit(self.largest_unit)),
.smallest_unit = toUnitOption(to.unit(self.smallest_unit)),
.rounding_mode = toRoundingModeOption(to.roundingMode(self.rounding_mode)),
.increment = toOption(c.OptionU32, self.rounding_increment),
};
}
pub fn diffsettings(self: t.DifferenceSettings) c.DifferenceSettings {
return .{
.largest_unit = toUnitOption(to.unit(self.largest_unit)),
.smallest_unit = toUnitOption(to.unit(self.smallest_unit)),
.rounding_mode = toRoundingModeOption(to.roundingMode(self.rounding_mode)),
.increment = toOption(c.OptionU32, self.rounding_increment),
};
}
};
pub const from = struct {
pub fn sign(value: c_int) t.Sign {
return switch (value) {
c.Sign_Positive => .positive,
c.Sign_Zero => .zero,
c.Sign_Negative => .negative,
else => .zero,
};
}
};

View file

@ -1,6 +1,3 @@
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 {
@ -15,22 +12,6 @@ pub const Unit = enum {
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.
@ -54,20 +35,6 @@ pub const RoundingMode = enum {
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.
@ -75,23 +42,6 @@ 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.).
@ -101,15 +51,6 @@ pub const RoundingOptions = struct {
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.
@ -119,15 +60,6 @@ pub const DifferenceSettings = struct {
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.
@ -136,33 +68,16 @@ 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) };
/// Time zone identifier for Temporal operations
pub const TimeZone = struct {
_inner: abi.c.TimeZone,
return .{
.precision = precision,
.smallest_unit = abi.toUnitOption(toCUnit(self.smallest_unit)),
.rounding_mode = abi.toRoundingModeOption(toCRoundingMode(self.rounding_mode)),
};
pub fn init(id: []const u8) TimeZone {
const view = abi.toDiplomatStringView(id);
return .{ ._inner = .{ .id = view } };
}
};
pub fn toCUnit(opt: ?Unit) ?c.Unit {
return if (opt) |u| @as(c.Unit, @intCast(u.toCApi())) else null;
}
pub fn toCRoundingMode(opt: ?RoundingMode) ?c.RoundingMode {
return if (opt) |m| @as(c.RoundingMode, @intCast(m.toCApi())) else null;
}
const abi = @import("abi.zig");