feat: more native zig types
This commit is contained in:
parent
ca29ace7fa
commit
acbadeb89a
5 changed files with 108 additions and 31 deletions
|
|
@ -16,6 +16,8 @@
|
||||||
.paths = .{
|
.paths = .{
|
||||||
"build.zig",
|
"build.zig",
|
||||||
"build.zig.zon",
|
"build.zig.zon",
|
||||||
|
"Cargo.toml",
|
||||||
|
"Cargo.lock",
|
||||||
"src",
|
"src",
|
||||||
"lib",
|
"lib",
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -140,12 +140,12 @@ pub fn subtract(self: Duration, other: Duration) !Duration {
|
||||||
|
|
||||||
/// Round the duration according to the specified options (Temporal.Duration.prototype.round).
|
/// Round the duration according to the specified options (Temporal.Duration.prototype.round).
|
||||||
pub fn round(self: Duration, options: RoundingOptions, relative_to: RelativeTo) !Duration {
|
pub fn round(self: Duration, options: RoundingOptions, relative_to: RelativeTo) !Duration {
|
||||||
return wrapDuration(abi.c.temporal_rs_Duration_round(self._inner, options, relative_to));
|
return wrapDuration(abi.c.temporal_rs_Duration_round(self._inner, options.toCApi(), relative_to));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Round the duration with an explicit provider.
|
/// Round the duration with an explicit provider.
|
||||||
fn roundWithProvider(self: Duration, options: RoundingOptions, relative_to: RelativeTo, provider: *const abi.c.Provider) !Duration {
|
fn roundWithProvider(self: Duration, options: RoundingOptions, relative_to: RelativeTo, provider: *const abi.c.Provider) !Duration {
|
||||||
return wrapDuration(abi.c.temporal_rs_Duration_round_with_provider(self._inner, options, relative_to, provider));
|
return wrapDuration(abi.c.temporal_rs_Duration_round_with_provider(self._inner, options.toCApi(), relative_to, provider));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Compare two durations (Temporal.Duration.compare).
|
/// Compare two durations (Temporal.Duration.compare).
|
||||||
|
|
@ -252,9 +252,8 @@ const Precision = abi.c.Precision;
|
||||||
const Unit_option = abi.c.Unit_option;
|
const Unit_option = abi.c.Unit_option;
|
||||||
const RoundingMode_option = abi.c.RoundingMode_option;
|
const RoundingMode_option = abi.c.RoundingMode_option;
|
||||||
|
|
||||||
pub const RoundingOptions = abi.c.RoundingOptions;
|
pub const RoundingOptions = temporal.RoundingOptions;
|
||||||
pub const ToStringRoundingOptions = abi.c.ToStringRoundingOptions;
|
pub const ToStringRoundingOptions = abi.c.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;
|
||||||
|
|
|
||||||
|
|
@ -12,6 +12,8 @@ epoch_nanoseconds: i128,
|
||||||
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;
|
||||||
|
pub const RoundingOptions = temporal.RoundingOptions;
|
||||||
|
pub const DifferenceSettings = temporal.DifferenceSettings;
|
||||||
|
|
||||||
/// Construct from epoch nanoseconds (Temporal.Instant.fromEpochNanoseconds).
|
/// Construct from epoch nanoseconds (Temporal.Instant.fromEpochNanoseconds).
|
||||||
pub fn init(epoch_ns: i128) !Instant {
|
pub fn init(epoch_ns: i128) !Instant {
|
||||||
|
|
@ -29,18 +31,41 @@ pub fn fromEpochNanoseconds(epoch_ns: i128) !Instant {
|
||||||
return wrapInstant(abi.c.temporal_rs_Instant_try_new(parts));
|
return wrapInstant(abi.c.temporal_rs_Instant_try_new(parts));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Parse an ISO 8601 string (Temporal.Instant.from).
|
/// Parse an ISO 8601 string (Temporal.Instant.from) or from another Temporal.Instant.
|
||||||
pub fn from(text: []const u8) !Instant {
|
pub fn from(info: anytype) !Instant {
|
||||||
const view = abi.toDiplomatStringView(text);
|
const T = @TypeOf(info);
|
||||||
return wrapInstant(abi.c.temporal_rs_Instant_from_utf8(view));
|
|
||||||
|
if (T == Instant) return info.clone();
|
||||||
|
|
||||||
|
// Handle string types (both literals and slices)
|
||||||
|
const type_info = @typeInfo(T);
|
||||||
|
switch (type_info) {
|
||||||
|
.pointer => {
|
||||||
|
const ptr = type_info.pointer;
|
||||||
|
const ChildType = switch (@typeInfo(ptr.child)) {
|
||||||
|
.array => |arr| arr.child,
|
||||||
|
else => ptr.child,
|
||||||
|
};
|
||||||
|
|
||||||
|
if (ChildType == u8) return fromUtf8(info);
|
||||||
|
if (ChildType == u16) return fromUtf16(info);
|
||||||
|
},
|
||||||
|
else => @compileError("from() expects an Instant, []const u8, or []const u16"),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Parse an ISO 8601 UTF-16 string (Temporal.Instant.from).
|
/// Parse an ISO 8601 UTF-16 string (Temporal.Instant.from).
|
||||||
fn fromUtf16(text: []const u16) !Instant {
|
inline fn fromUtf16(text: []const u16) !Instant {
|
||||||
const view = abi.toDiplomatString16View(text);
|
const view = abi.toDiplomatString16View(text);
|
||||||
return wrapInstant(abi.c.temporal_rs_Instant_from_utf16(view));
|
return wrapInstant(abi.c.temporal_rs_Instant_from_utf16(view));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Parse an ISO 8601 UTF-16 string (Temporal.Instant.from).
|
||||||
|
inline fn fromUtf8(text: []const u8) !Instant {
|
||||||
|
const view = abi.toDiplomatStringView(text);
|
||||||
|
return wrapInstant(abi.c.temporal_rs_Instant_from_utf8(view));
|
||||||
|
}
|
||||||
|
|
||||||
/// Add a Duration to this instant (Temporal.Instant.prototype.add).
|
/// Add a Duration to this instant (Temporal.Instant.prototype.add).
|
||||||
pub fn add(self: Instant, duration: *Duration) !Instant {
|
pub fn add(self: Instant, duration: *Duration) !Instant {
|
||||||
return wrapInstant(abi.c.temporal_rs_Instant_add(self._inner, duration._inner));
|
return wrapInstant(abi.c.temporal_rs_Instant_add(self._inner, duration._inner));
|
||||||
|
|
@ -52,18 +77,18 @@ pub fn subtract(self: Instant, duration: *Duration) !Instant {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Difference until another instant (Temporal.Instant.prototype.until).
|
/// Difference until another instant (Temporal.Instant.prototype.until).
|
||||||
pub fn until(self: Instant, other: Instant, settings: abi.c.DifferenceSettings) !DurationHandle {
|
pub fn until(self: Instant, other: Instant, settings: DifferenceSettings) !DurationHandle {
|
||||||
return wrapDuration(abi.c.temporal_rs_Instant_until(self._inner, other._inner, settings));
|
return wrapDuration(abi.c.temporal_rs_Instant_until(self._inner, other._inner, settings.toCApi()));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Difference since another instant (Temporal.Instant.prototype.since).
|
/// Difference since another instant (Temporal.Instant.prototype.since).
|
||||||
pub fn since(self: Instant, other: Instant, settings: abi.c.DifferenceSettings) !DurationHandle {
|
pub fn since(self: Instant, other: Instant, settings: DifferenceSettings) !DurationHandle {
|
||||||
return wrapDuration(abi.c.temporal_rs_Instant_since(self._inner, other._inner, settings));
|
return wrapDuration(abi.c.temporal_rs_Instant_since(self._inner, other._inner, settings.toCApi()));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Round this instant (Temporal.Instant.prototype.round).
|
/// Round this instant (Temporal.Instant.prototype.round).
|
||||||
pub fn round(self: Instant, options: abi.c.RoundingOptions) !Instant {
|
pub fn round(self: Instant, options: RoundingOptions) !Instant {
|
||||||
return wrapInstant(abi.c.temporal_rs_Instant_round(self._inner, options));
|
return wrapInstant(abi.c.temporal_rs_Instant_round(self._inner, options.toCApi()));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Compare two instants (Temporal.Instant.compare).
|
/// Compare two instants (Temporal.Instant.compare).
|
||||||
|
|
@ -258,10 +283,17 @@ test fromEpochNanoseconds {
|
||||||
}
|
}
|
||||||
|
|
||||||
test from {
|
test from {
|
||||||
|
// Test parsing from UTF-8 string
|
||||||
const inst = try Instant.from("2024-03-15T14:30:45.123Z");
|
const inst = try Instant.from("2024-03-15T14:30:45.123Z");
|
||||||
defer inst.deinit();
|
defer inst.deinit();
|
||||||
|
|
||||||
try std.testing.expectEqual(@as(i64, 1_710_513_045_123), inst.epoch_milliseconds);
|
try std.testing.expectEqual(@as(i64, 1_710_513_045_123), inst.epoch_milliseconds);
|
||||||
|
|
||||||
|
// Test creating from another Instant
|
||||||
|
const inst2 = try Instant.from(inst);
|
||||||
|
defer inst2.deinit();
|
||||||
|
try std.testing.expectEqual(inst.epoch_milliseconds, inst2.epoch_milliseconds);
|
||||||
|
try std.testing.expectEqual(inst.epoch_nanoseconds, inst2.epoch_nanoseconds);
|
||||||
|
try std.testing.expect(Instant.equals(inst, inst2));
|
||||||
}
|
}
|
||||||
|
|
||||||
test fromUtf16 {
|
test fromUtf16 {
|
||||||
|
|
@ -326,11 +358,11 @@ test until {
|
||||||
const later = try Instant.fromEpochMilliseconds(3_600_000);
|
const later = try Instant.fromEpochMilliseconds(3_600_000);
|
||||||
defer later.deinit();
|
defer later.deinit();
|
||||||
|
|
||||||
const settings = abi.c.DifferenceSettings{
|
const settings = DifferenceSettings{
|
||||||
.largest_unit = abi.toUnitOption(Unit.hour.toCApi()),
|
.largest_unit = .hour,
|
||||||
.smallest_unit = abi.toUnitOption(Unit.second.toCApi()),
|
.smallest_unit = .second,
|
||||||
.rounding_mode = abi.toRoundingModeOption(RoundingMode.trunc.toCApi()),
|
.rounding_mode = .trunc,
|
||||||
.increment = abi.toOption(abi.c.OptionU32, null),
|
.increment = null,
|
||||||
};
|
};
|
||||||
|
|
||||||
var until_handle = try earlier.until(later, settings);
|
var until_handle = try earlier.until(later, settings);
|
||||||
|
|
@ -350,11 +382,11 @@ test since {
|
||||||
const later = try Instant.fromEpochMilliseconds(3_600_000);
|
const later = try Instant.fromEpochMilliseconds(3_600_000);
|
||||||
defer later.deinit();
|
defer later.deinit();
|
||||||
|
|
||||||
const settings = abi.c.DifferenceSettings{
|
const settings = DifferenceSettings{
|
||||||
.largest_unit = abi.toUnitOption(Unit.hour.toCApi()),
|
.largest_unit = .hour,
|
||||||
.smallest_unit = abi.toUnitOption(Unit.second.toCApi()),
|
.smallest_unit = .second,
|
||||||
.rounding_mode = abi.toRoundingModeOption(RoundingMode.trunc.toCApi()),
|
.rounding_mode = .trunc,
|
||||||
.increment = abi.toOption(abi.c.OptionU32, null),
|
.increment = null,
|
||||||
};
|
};
|
||||||
|
|
||||||
var until_handle = try earlier.until(later, settings);
|
var until_handle = try earlier.until(later, settings);
|
||||||
|
|
@ -372,11 +404,11 @@ test round {
|
||||||
const inst = try Instant.fromEpochNanoseconds(1_609_459_245_123_456_789);
|
const inst = try Instant.fromEpochNanoseconds(1_609_459_245_123_456_789);
|
||||||
defer inst.deinit();
|
defer inst.deinit();
|
||||||
|
|
||||||
const opts = abi.c.RoundingOptions{
|
const opts = RoundingOptions{
|
||||||
.largest_unit = abi.toUnitOption(null),
|
.largest_unit = null,
|
||||||
.smallest_unit = abi.toUnitOption(Unit.second.toCApi()),
|
.smallest_unit = .second,
|
||||||
.rounding_mode = abi.toRoundingModeOption(RoundingMode.half_expand.toCApi()),
|
.rounding_mode = .half_expand,
|
||||||
.increment = abi.toOption(abi.c.OptionU32, null),
|
.increment = null,
|
||||||
};
|
};
|
||||||
|
|
||||||
const rounded = try inst.round(opts);
|
const rounded = try inst.round(opts);
|
||||||
|
|
|
||||||
|
|
@ -114,6 +114,8 @@ test Instant {
|
||||||
"Unit",
|
"Unit",
|
||||||
"RoundingMode",
|
"RoundingMode",
|
||||||
"Sign",
|
"Sign",
|
||||||
|
"RoundingOptions",
|
||||||
|
"DifferenceSettings",
|
||||||
};
|
};
|
||||||
|
|
||||||
try assertDecls(Instant, checks);
|
try assertDecls(Instant, checks);
|
||||||
|
|
|
||||||
|
|
@ -93,3 +93,45 @@ pub const Sign = enum {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/// Options for rounding operations (Instant.round, Duration.round, etc.).
|
||||||
|
pub const RoundingOptions = struct {
|
||||||
|
largest_unit: ?Unit = null,
|
||||||
|
smallest_unit: ?Unit = null,
|
||||||
|
rounding_mode: ?RoundingMode = null,
|
||||||
|
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.increment),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Options for computing differences between instants.
|
||||||
|
pub const DifferenceSettings = struct {
|
||||||
|
largest_unit: ?Unit = null,
|
||||||
|
smallest_unit: ?Unit = null,
|
||||||
|
rounding_mode: ?RoundingMode = null,
|
||||||
|
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.increment),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue