feat: extend bindings
This commit is contained in:
parent
ba5b777de4
commit
f302c55135
6 changed files with 154 additions and 15 deletions
|
|
@ -479,7 +479,7 @@ pub fn run(allocator: std.mem.Allocator, io_optional: ?std.Io) !void {
|
||||||
\\ - blank: {}
|
\\ - blank: {}
|
||||||
\\ - microseconds: {d}
|
\\ - microseconds: {d}
|
||||||
\\ - toJSON(): {s}
|
\\ - toJSON(): {s}
|
||||||
\\ - toLocaleString implemented: {}
|
\\ - toLocaleString supported: {}
|
||||||
\\
|
\\
|
||||||
\\
|
\\
|
||||||
, .{
|
, .{
|
||||||
|
|
@ -522,16 +522,17 @@ pub fn run(allocator: std.mem.Allocator, io_optional: ?std.Io) !void {
|
||||||
try instant_zdt.toString(allocator, .{}),
|
try instant_zdt.toString(allocator, .{}),
|
||||||
});
|
});
|
||||||
|
|
||||||
const now_zdt_supported = Temporal.Now.zonedDateTimeISO() != error.TemporalNotImplemented;
|
const now_zdt = try Temporal.Now.zonedDateTimeISO();
|
||||||
|
defer now_zdt.deinit();
|
||||||
std.log.info(
|
std.log.info(
|
||||||
\\Now Coverage
|
\\Now Coverage
|
||||||
\\ - timeZoneId(): {s}
|
\\ - timeZoneId(): {s}
|
||||||
\\ - zonedDateTimeISO implemented: {}
|
\\ - zonedDateTimeISO(): {s}
|
||||||
\\
|
\\
|
||||||
\\
|
\\
|
||||||
, .{
|
, .{
|
||||||
Temporal.Now.timeZoneId(),
|
Temporal.Now.timeZoneId(),
|
||||||
now_zdt_supported,
|
try now_zdt.toString(allocator, .{}),
|
||||||
});
|
});
|
||||||
|
|
||||||
const date_cal = try Temporal.PlainDate.calInit(2024, 2, 2, "iso8601");
|
const date_cal = try Temporal.PlainDate.calInit(2024, 2, 2, "iso8601");
|
||||||
|
|
@ -558,7 +559,7 @@ pub fn run(allocator: std.mem.Allocator, io_optional: ?std.Io) !void {
|
||||||
\\ - toPlainYearMonth: {s}
|
\\ - toPlainYearMonth: {s}
|
||||||
\\ - toZonedDateTime: {s}
|
\\ - toZonedDateTime: {s}
|
||||||
\\ - toJSON(): {s}
|
\\ - toJSON(): {s}
|
||||||
\\ - toLocaleString implemented: {}
|
\\ - toLocaleString supported: {}
|
||||||
\\ - valueOf supported: {}
|
\\ - valueOf supported: {}
|
||||||
\\ - with year/month/day: {s}
|
\\ - with year/month/day: {s}
|
||||||
\\
|
\\
|
||||||
|
|
@ -736,7 +737,8 @@ pub fn run(allocator: std.mem.Allocator, io_optional: ?std.Io) !void {
|
||||||
const zdt_plain_datetime = try zdt.toPlainDateTime();
|
const zdt_plain_datetime = try zdt.toPlainDateTime();
|
||||||
const zdt_plain_time = try zdt.toPlainTime();
|
const zdt_plain_time = try zdt.toPlainTime();
|
||||||
const zdt_valueof_supported = zdt.valueOf() != error.ValueOfNotSupported;
|
const zdt_valueof_supported = zdt.valueOf() != error.ValueOfNotSupported;
|
||||||
const zdt_with_supported = zdt.with(allocator, .{ .year = 2025 }) != error.TemporalNoteImplemented;
|
const zdt_with_coverage = try zdt.with(allocator, .{ .year = 2025 });
|
||||||
|
defer zdt_with_coverage.deinit();
|
||||||
std.log.info(
|
std.log.info(
|
||||||
\\ZonedDateTime Coverage
|
\\ZonedDateTime Coverage
|
||||||
\\ - init: {s}
|
\\ - init: {s}
|
||||||
|
|
@ -786,7 +788,7 @@ pub fn run(allocator: std.mem.Allocator, io_optional: ?std.Io) !void {
|
||||||
\\ - offset/offsetNanoseconds: {s}/{}
|
\\ - offset/offsetNanoseconds: {s}/{}
|
||||||
\\ - weekOfYear/yearOfWeek: {?}/{?}
|
\\ - weekOfYear/yearOfWeek: {?}/{?}
|
||||||
\\ - valueOf supported: {}
|
\\ - valueOf supported: {}
|
||||||
\\ - with implemented: {}
|
\\ - with year=2025: {s}
|
||||||
\\
|
\\
|
||||||
\\
|
\\
|
||||||
, .{
|
, .{
|
||||||
|
|
@ -804,7 +806,7 @@ pub fn run(allocator: std.mem.Allocator, io_optional: ?std.Io) !void {
|
||||||
zdt.weekOfYear(),
|
zdt.weekOfYear(),
|
||||||
zdt.yearOfWeek(),
|
zdt.yearOfWeek(),
|
||||||
zdt_valueof_supported,
|
zdt_valueof_supported,
|
||||||
zdt_with_supported,
|
try zdt_with_coverage.toString(allocator, .{}),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -320,7 +320,8 @@ pub fn toJSON(self: Duration, allocator: std.mem.Allocator) ![]u8 {
|
||||||
return self.toString(allocator, .{});
|
return self.toString(allocator, .{});
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns a string with a language-sensitive representation of this duration. Not implemented.
|
/// Returns a string with a language-sensitive representation of this duration.
|
||||||
|
/// Not implemented.
|
||||||
/// See: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/Duration/toLocaleString
|
/// See: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/Duration/toLocaleString
|
||||||
pub fn toLocaleString(self: Duration, allocator: std.mem.Allocator) ![]u8 {
|
pub fn toLocaleString(self: Duration, allocator: std.mem.Allocator) ![]u8 {
|
||||||
_ = self;
|
_ = self;
|
||||||
|
|
|
||||||
23
src/Now.zig
23
src/Now.zig
|
|
@ -87,7 +87,8 @@ pub fn timeZoneId() []const u8 {
|
||||||
///
|
///
|
||||||
/// See: [MDN Temporal.Now.zonedDateTimeISO](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/Now/zonedDateTimeISO)
|
/// See: [MDN Temporal.Now.zonedDateTimeISO](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/Now/zonedDateTimeISO)
|
||||||
pub fn zonedDateTimeISO() !ZonedDateTime {
|
pub fn zonedDateTimeISO() !ZonedDateTime {
|
||||||
return error.TemporalNotImplemented;
|
const time_zone = try ZonedDateTime.TimeZone.init(timeZoneId());
|
||||||
|
return ZonedDateTime.fromEpochNanoseconds(currentEpochNanoseconds(), time_zone);
|
||||||
}
|
}
|
||||||
|
|
||||||
const CurrentParts = struct {
|
const CurrentParts = struct {
|
||||||
|
|
@ -132,6 +133,18 @@ fn currentParts(io: std.Io) CurrentParts {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn currentEpochNanoseconds() i128 {
|
||||||
|
var timespec: std.posix.timespec = undefined;
|
||||||
|
switch (std.posix.errno(std.posix.system.clock_gettime(.REALTIME, ×pec))) {
|
||||||
|
.SUCCESS => {},
|
||||||
|
else => return 0,
|
||||||
|
}
|
||||||
|
|
||||||
|
const seconds: i128 = @intCast(timespec.sec);
|
||||||
|
const nanos: i128 = @intCast(timespec.nsec);
|
||||||
|
return seconds * std.time.ns_per_s + nanos;
|
||||||
|
}
|
||||||
|
|
||||||
// ---------- Tests ---------------------
|
// ---------- Tests ---------------------
|
||||||
test instant {
|
test instant {
|
||||||
const io = std.testing.io;
|
const io = std.testing.io;
|
||||||
|
|
@ -168,5 +181,11 @@ test timeZoneId {
|
||||||
try std.testing.expectEqualStrings("UTC", tz);
|
try std.testing.expectEqualStrings("UTC", tz);
|
||||||
}
|
}
|
||||||
test zonedDateTimeISO {
|
test zonedDateTimeISO {
|
||||||
try std.testing.expectError(error.TemporalNotImplemented, zonedDateTimeISO());
|
const zdt = try zonedDateTimeISO();
|
||||||
|
defer zdt.deinit();
|
||||||
|
|
||||||
|
try std.testing.expect(zdt.epochNanoseconds() > 0);
|
||||||
|
const tz = try zdt.timeZoneId(std.testing.allocator);
|
||||||
|
defer std.testing.allocator.free(tz);
|
||||||
|
try std.testing.expectEqualStrings("UTC", tz);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -99,6 +99,24 @@ pub const ToStringOptions = struct {
|
||||||
time_zone_name: DisplayTimeZone = .auto,
|
time_zone_name: DisplayTimeZone = .auto,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/// Options for `with()` method.
|
||||||
|
pub const WithOptions = struct {
|
||||||
|
year: ?i32 = null,
|
||||||
|
month: ?u8 = null,
|
||||||
|
month_code: ?[]const u8 = null,
|
||||||
|
day: ?u8 = null,
|
||||||
|
era: ?[]const u8 = null,
|
||||||
|
era_year: ?i32 = null,
|
||||||
|
hour: ?u8 = null,
|
||||||
|
minute: ?u8 = null,
|
||||||
|
second: ?u8 = null,
|
||||||
|
millisecond: ?u16 = null,
|
||||||
|
microsecond: ?u16 = null,
|
||||||
|
nanosecond: ?u16 = null,
|
||||||
|
offset: ?[]const u8 = null,
|
||||||
|
time_zone: ?TimeZone = null,
|
||||||
|
};
|
||||||
|
|
||||||
/// Helper function to wrap a C API result into a ZonedDateTime
|
/// Helper function to wrap a C API result into a ZonedDateTime
|
||||||
fn wrapZonedDateTime(result: anytype) !ZonedDateTime {
|
fn wrapZonedDateTime(result: anytype) !ZonedDateTime {
|
||||||
const ptr = (try abi.extractResult(result)) orelse return abi.TemporalError.Generic;
|
const ptr = (try abi.extractResult(result)) orelse return abi.TemporalError.Generic;
|
||||||
|
|
@ -273,9 +291,21 @@ pub fn valueOf(_: ZonedDateTime) !void {
|
||||||
/// See [MDN Temporal.ZonedDateTime.prototype.with()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/ZonedDateTime/with)
|
/// See [MDN Temporal.ZonedDateTime.prototype.with()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/ZonedDateTime/with)
|
||||||
pub fn with(self: ZonedDateTime, allocator: std.mem.Allocator, fields: anytype) !ZonedDateTime {
|
pub fn with(self: ZonedDateTime, allocator: std.mem.Allocator, fields: anytype) !ZonedDateTime {
|
||||||
_ = allocator;
|
_ = allocator;
|
||||||
_ = fields;
|
const partial = abi.toPartialZonedDateTime(fields);
|
||||||
_ = self;
|
const disambiguation = abi.toOption(abi.c.Disambiguation_option, abi.to.toDisambiguation(Disambiguation.compatible));
|
||||||
return error.TemporalNoteImplemented; // Need PartialZonedDateTime mapping
|
const offset_option = abi.toOption(abi.c.OffsetDisambiguation_option, abi.to.toOffsetDisambiguation(OffsetDisambiguation.prefer_offset));
|
||||||
|
const overflow = abi.c.ArithmeticOverflow_option{
|
||||||
|
.is_ok = true,
|
||||||
|
.unnamed_0 = .{ .ok = abi.c.ArithmeticOverflow_Constrain },
|
||||||
|
};
|
||||||
|
|
||||||
|
return wrapZonedDateTime(abi.c.temporal_rs_ZonedDateTime_with(
|
||||||
|
self._inner,
|
||||||
|
partial,
|
||||||
|
disambiguation,
|
||||||
|
offset_option,
|
||||||
|
overflow,
|
||||||
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns a new ZonedDateTime interpreted in the new calendar system.
|
/// Returns a new ZonedDateTime interpreted in the new calendar system.
|
||||||
|
|
@ -760,7 +790,14 @@ test valueOf {
|
||||||
test with {
|
test with {
|
||||||
const zdt = try from("2021-01-01T12:00:00+00:00[UTC]", null, .compatible, .reject);
|
const zdt = try from("2021-01-01T12:00:00+00:00[UTC]", null, .compatible, .reject);
|
||||||
defer zdt.deinit();
|
defer zdt.deinit();
|
||||||
try std.testing.expectError(error.TemporalNoteImplemented, zdt.with(std.testing.allocator, .{}));
|
|
||||||
|
const result = try zdt.with(std.testing.allocator, .{ .year = 2022, .month = 2, .day = 3, .hour = 4 });
|
||||||
|
defer result.deinit();
|
||||||
|
|
||||||
|
try std.testing.expectEqual(@as(i32, 2022), result.year());
|
||||||
|
try std.testing.expectEqual(@as(u8, 2), result.month());
|
||||||
|
try std.testing.expectEqual(@as(u8, 3), result.day());
|
||||||
|
try std.testing.expectEqual(@as(u8, 4), result.hour());
|
||||||
}
|
}
|
||||||
|
|
||||||
test withCalendar {
|
test withCalendar {
|
||||||
|
|
|
||||||
79
src/abi.zig
79
src/abi.zig
|
|
@ -90,6 +90,85 @@ pub fn toTimeZoneOption(maybe_value: ?c.TimeZone) c.TimeZone_option {
|
||||||
return toOption(c.TimeZone_option, maybe_value);
|
return toOption(c.TimeZone_option, maybe_value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn toPartialZonedDateTime(fields: anytype) c.PartialZonedDateTime {
|
||||||
|
return .{
|
||||||
|
.date = .{
|
||||||
|
.year = toI32OptionField(fields, "year"),
|
||||||
|
.month = toU8OptionField(fields, "month"),
|
||||||
|
.month_code = toStringViewField(fields, "month_code"),
|
||||||
|
.day = toU8OptionField(fields, "day"),
|
||||||
|
.era = toStringViewField(fields, "era"),
|
||||||
|
.era_year = toI32OptionField(fields, "era_year"),
|
||||||
|
.calendar = c.AnyCalendarKind_Iso,
|
||||||
|
},
|
||||||
|
.time = .{
|
||||||
|
.hour = toU8OptionField(fields, "hour"),
|
||||||
|
.minute = toU8OptionField(fields, "minute"),
|
||||||
|
.second = toU8OptionField(fields, "second"),
|
||||||
|
.millisecond = toU16OptionField(fields, "millisecond"),
|
||||||
|
.microsecond = toU16OptionField(fields, "microsecond"),
|
||||||
|
.nanosecond = toU16OptionField(fields, "nanosecond"),
|
||||||
|
},
|
||||||
|
.offset = toOptionStringViewField(fields, "offset"),
|
||||||
|
.timezone = toTimeZoneOptionField(fields, "time_zone"),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
fn toI32OptionField(fields: anytype, comptime name: []const u8) c.OptionI32 {
|
||||||
|
return toOption(c.OptionI32, intField(i32, fields, name));
|
||||||
|
}
|
||||||
|
|
||||||
|
fn toU8OptionField(fields: anytype, comptime name: []const u8) c.OptionU8 {
|
||||||
|
return toOption(c.OptionU8, intField(u8, fields, name));
|
||||||
|
}
|
||||||
|
|
||||||
|
fn toU16OptionField(fields: anytype, comptime name: []const u8) c.OptionU16 {
|
||||||
|
return toOption(c.OptionU16, intField(u16, fields, name));
|
||||||
|
}
|
||||||
|
|
||||||
|
fn intField(comptime Int: type, fields: anytype, comptime name: []const u8) ?Int {
|
||||||
|
if (!@hasField(@TypeOf(fields), name)) return null;
|
||||||
|
|
||||||
|
const value = @field(fields, name);
|
||||||
|
return switch (@typeInfo(@TypeOf(value))) {
|
||||||
|
.optional => if (value) |payload| @as(Int, @intCast(payload)) else null,
|
||||||
|
else => @as(Int, @intCast(value)),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
fn toStringViewField(fields: anytype, comptime name: []const u8) c.DiplomatStringView {
|
||||||
|
if (stringField(fields, name)) |value| return toDiplomatStringView(value);
|
||||||
|
return .{ .data = null, .len = 0 };
|
||||||
|
}
|
||||||
|
|
||||||
|
fn toOptionStringViewField(fields: anytype, comptime name: []const u8) c.OptionStringView {
|
||||||
|
if (stringField(fields, name)) |value| {
|
||||||
|
return .{ .is_ok = true, .unnamed_0 = .{ .ok = toDiplomatStringView(value) } };
|
||||||
|
}
|
||||||
|
return .{ .is_ok = false };
|
||||||
|
}
|
||||||
|
|
||||||
|
fn stringField(fields: anytype, comptime name: []const u8) ?[]const u8 {
|
||||||
|
if (!@hasField(@TypeOf(fields), name)) return null;
|
||||||
|
|
||||||
|
const value = @field(fields, name);
|
||||||
|
return switch (@typeInfo(@TypeOf(value))) {
|
||||||
|
.optional => value,
|
||||||
|
else => value,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
fn toTimeZoneOptionField(fields: anytype, comptime name: []const u8) c.TimeZone_option {
|
||||||
|
if (!@hasField(@TypeOf(fields), name)) return .{ .is_ok = false };
|
||||||
|
|
||||||
|
const value = @field(fields, name);
|
||||||
|
const maybe_time_zone = switch (@typeInfo(@TypeOf(value))) {
|
||||||
|
.optional => if (value) |payload| payload._inner else null,
|
||||||
|
else => value._inner,
|
||||||
|
};
|
||||||
|
return toOption(c.TimeZone_option, maybe_time_zone);
|
||||||
|
}
|
||||||
|
|
||||||
/// Convert a Zig `?Unit` to a Rust `Option<Unit>`.
|
/// Convert a Zig `?Unit` to a Rust `Option<Unit>`.
|
||||||
pub fn toUnitOption(maybe_value: ?c.Unit) c.Unit_option {
|
pub fn toUnitOption(maybe_value: ?c.Unit) c.Unit_option {
|
||||||
return toOption(c.Unit_option, maybe_value);
|
return toOption(c.Unit_option, maybe_value);
|
||||||
|
|
|
||||||
|
|
@ -502,6 +502,7 @@ test ZonedDateTime {
|
||||||
"DisplayOffset",
|
"DisplayOffset",
|
||||||
"DisplayTimeZone",
|
"DisplayTimeZone",
|
||||||
"ToStringOptions",
|
"ToStringOptions",
|
||||||
|
"WithOptions",
|
||||||
};
|
};
|
||||||
|
|
||||||
try assertDecls(ZonedDateTime, checks);
|
try assertDecls(ZonedDateTime, checks);
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue