refactor: use diplomatewrite wrapper
This commit is contained in:
parent
09536870cb
commit
f577120af8
2 changed files with 29 additions and 201 deletions
165
src/Duration.zig
165
src/Duration.zig
|
|
@ -2,139 +2,6 @@ const std = @import("std");
|
||||||
const temporal_rs = @import("cabi.zig");
|
const temporal_rs = @import("cabi.zig");
|
||||||
const c = temporal_rs.c;
|
const c = temporal_rs.c;
|
||||||
|
|
||||||
/// The Zig implementation of `Temporal.Duration`.
|
|
||||||
///
|
|
||||||
/// Represents a span of time such as "2 hours and 30 minutes" or "3 years, 2 months".
|
|
||||||
/// Unlike `Instant` which represents a specific moment in time, Duration represents
|
|
||||||
/// the amount of time between two moments.
|
|
||||||
///
|
|
||||||
/// A Duration consists of two categories of components:
|
|
||||||
/// - Date components: years, months, weeks, and days
|
|
||||||
/// - Time components: hours, minutes, seconds, and subsecond units (nanosecond precision)
|
|
||||||
///
|
|
||||||
/// Note that date arithmetic can be complex. For example, adding "1 month" to January 31st
|
|
||||||
/// could result in February 28th (non-leap year), February 29th (leap year), or March 3rd
|
|
||||||
/// (if you overflow February), depending on the calendar system and overflow handling.
|
|
||||||
///
|
|
||||||
/// ## Examples
|
|
||||||
///
|
|
||||||
/// ### Creating durations
|
|
||||||
///
|
|
||||||
/// ```zig
|
|
||||||
/// const Duration = @import("Duration.zig");
|
|
||||||
///
|
|
||||||
/// // Create a duration with specific components
|
|
||||||
/// // 2 weeks and 3 days, no time components
|
|
||||||
/// const vacation_duration = try Duration.init(
|
|
||||||
/// 0, 0, 2, 3, // years, months, weeks, days
|
|
||||||
/// 0, 0, 0, // hours, minutes, seconds
|
|
||||||
/// 0, 0, 0 // milliseconds, microseconds, nanoseconds
|
|
||||||
/// );
|
|
||||||
/// defer vacation_duration.deinit();
|
|
||||||
///
|
|
||||||
/// try std.testing.expectEqual(@as(i64, 2), vacation_duration.weeks());
|
|
||||||
/// try std.testing.expectEqual(@as(i64, 3), vacation_duration.days());
|
|
||||||
/// ```
|
|
||||||
///
|
|
||||||
/// ### Parsing ISO 8601 duration strings
|
|
||||||
///
|
|
||||||
/// ```zig
|
|
||||||
/// const Duration = @import("Duration.zig");
|
|
||||||
///
|
|
||||||
/// // Complex duration with multiple components
|
|
||||||
/// const complex = try Duration.from("P1Y2M3DT4H5M6.789S");
|
|
||||||
/// defer complex.deinit();
|
|
||||||
/// try std.testing.expectEqual(@as(i64, 1), complex.years());
|
|
||||||
/// try std.testing.expectEqual(@as(i64, 2), complex.months());
|
|
||||||
/// try std.testing.expectEqual(@as(i64, 3), complex.days());
|
|
||||||
/// try std.testing.expectEqual(@as(i64, 4), complex.hours());
|
|
||||||
/// try std.testing.expectEqual(@as(i64, 5), complex.minutes());
|
|
||||||
/// try std.testing.expectEqual(@as(i64, 6), complex.seconds());
|
|
||||||
///
|
|
||||||
/// // Time-only duration
|
|
||||||
/// const movie_length = try Duration.from("PT2H30M");
|
|
||||||
/// defer movie_length.deinit();
|
|
||||||
/// try std.testing.expectEqual(@as(i64, 2), movie_length.hours());
|
|
||||||
/// try std.testing.expectEqual(@as(i64, 30), movie_length.minutes());
|
|
||||||
///
|
|
||||||
/// // Negative durations
|
|
||||||
/// const negative = try Duration.from("-P1D");
|
|
||||||
/// defer negative.deinit();
|
|
||||||
/// try std.testing.expectEqual(@as(i64, -1), negative.days());
|
|
||||||
/// ```
|
|
||||||
///
|
|
||||||
/// ### Duration arithmetic
|
|
||||||
///
|
|
||||||
/// ```zig
|
|
||||||
/// const Duration = @import("Duration.zig");
|
|
||||||
///
|
|
||||||
/// const commute_time = try Duration.from("PT45M");
|
|
||||||
/// defer commute_time.deinit();
|
|
||||||
/// const lunch_break = try Duration.from("PT1H");
|
|
||||||
/// defer lunch_break.deinit();
|
|
||||||
///
|
|
||||||
/// // Add durations together
|
|
||||||
/// const total_time = try commute_time.add(lunch_break);
|
|
||||||
/// defer total_time.deinit();
|
|
||||||
/// try std.testing.expectEqual(@as(i64, 1), total_time.hours()); // Results in 1 hour 45 minutes
|
|
||||||
/// try std.testing.expectEqual(@as(i64, 45), total_time.minutes());
|
|
||||||
///
|
|
||||||
/// // Subtract duration components
|
|
||||||
/// const shortened = try lunch_break.subtract(try Duration.from("PT15M"));
|
|
||||||
/// defer shortened.deinit();
|
|
||||||
/// try std.testing.expectEqual(@as(i64, 45), shortened.minutes());
|
|
||||||
/// ```
|
|
||||||
///
|
|
||||||
/// ### Working with partial durations
|
|
||||||
///
|
|
||||||
/// ```zig
|
|
||||||
/// const Duration = @import("Duration.zig");
|
|
||||||
///
|
|
||||||
/// var partial = Duration.PartialDuration.empty();
|
|
||||||
/// partial = partial.withHours(3);
|
|
||||||
/// partial = partial.withMinutes(45);
|
|
||||||
///
|
|
||||||
/// const duration = try Duration.fromPartialDuration(partial);
|
|
||||||
/// defer duration.deinit();
|
|
||||||
/// try std.testing.expectEqual(@as(i64, 3), duration.hours());
|
|
||||||
/// try std.testing.expectEqual(@as(i64, 45), duration.minutes());
|
|
||||||
/// try std.testing.expectEqual(@as(i64, 0), duration.days()); // other fields default to 0
|
|
||||||
/// ```
|
|
||||||
///
|
|
||||||
/// ### Duration properties
|
|
||||||
///
|
|
||||||
/// ```zig
|
|
||||||
/// const Duration = @import("Duration.zig");
|
|
||||||
///
|
|
||||||
/// const duration = try Duration.from("P1Y2M3D");
|
|
||||||
/// defer duration.deinit();
|
|
||||||
///
|
|
||||||
/// // Check if duration is zero
|
|
||||||
/// try std.testing.expect(!duration.isZero());
|
|
||||||
///
|
|
||||||
/// // Get the sign of the duration
|
|
||||||
/// const sign_val = duration.sign();
|
|
||||||
///
|
|
||||||
/// // Get absolute value
|
|
||||||
/// const abs_duration = duration.abs();
|
|
||||||
/// defer abs_duration.deinit();
|
|
||||||
/// try std.testing.expectEqual(@as(i64, 1), abs_duration.years());
|
|
||||||
/// try std.testing.expectEqual(@as(i64, 2), abs_duration.months());
|
|
||||||
/// try std.testing.expectEqual(@as(i64, 3), abs_duration.days());
|
|
||||||
///
|
|
||||||
/// // Negate duration
|
|
||||||
/// const negated_dur = duration.negated();
|
|
||||||
/// defer negated_dur.deinit();
|
|
||||||
/// try std.testing.expectEqual(@as(i64, -1), negated_dur.years());
|
|
||||||
/// try std.testing.expectEqual(@as(i64, -2), negated_dur.months());
|
|
||||||
/// try std.testing.expectEqual(@as(i64, -3), negated_dur.days());
|
|
||||||
/// ```
|
|
||||||
///
|
|
||||||
/// ## Reference
|
|
||||||
///
|
|
||||||
/// For more information, see the [MDN documentation][mdn-duration].
|
|
||||||
///
|
|
||||||
/// [mdn-duration]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/Duration
|
|
||||||
const Duration = @This();
|
const Duration = @This();
|
||||||
|
|
||||||
_inner: *c.Duration,
|
_inner: *c.Duration,
|
||||||
|
|
@ -284,45 +151,36 @@ fn roundWithProvider(self: Duration, options: RoundingOptions, relative_to: Rela
|
||||||
/// Compare two durations (Temporal.Duration.compare).
|
/// Compare two durations (Temporal.Duration.compare).
|
||||||
pub fn compare(self: Duration, other: Duration, relative_to: RelativeTo) !i8 {
|
pub fn compare(self: Duration, other: Duration, relative_to: RelativeTo) !i8 {
|
||||||
const res = c.temporal_rs_Duration_compare(self._inner, other._inner, relative_to);
|
const res = c.temporal_rs_Duration_compare(self._inner, other._inner, relative_to);
|
||||||
if (!res.is_ok) return error.TemporalError;
|
return temporal_rs.success(res) orelse return error.TemporalError;
|
||||||
return res.unnamed_0.ok;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Compare two durations with an explicit provider.
|
/// Compare two durations with an explicit provider.
|
||||||
fn compareWithProvider(self: Duration, other: Duration, relative_to: RelativeTo, provider: *const c.Provider) !i8 {
|
fn compareWithProvider(self: Duration, other: Duration, relative_to: RelativeTo, provider: *const c.Provider) !i8 {
|
||||||
const res = c.temporal_rs_Duration_compare_with_provider(self._inner, other._inner, relative_to, provider);
|
const res = c.temporal_rs_Duration_compare_with_provider(self._inner, other._inner, relative_to, provider);
|
||||||
if (!res.is_ok) return error.TemporalError;
|
return temporal_rs.success(res) orelse return error.TemporalError;
|
||||||
return res.unnamed_0.ok;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get the total value of the duration in the specified unit (Temporal.Duration.prototype.total).
|
/// Get the total value of the duration in the specified unit (Temporal.Duration.prototype.total).
|
||||||
pub fn total(self: Duration, unit: Unit, relative_to: RelativeTo) !f64 {
|
pub fn total(self: Duration, unit: Unit, relative_to: RelativeTo) !f64 {
|
||||||
const res = c.temporal_rs_Duration_total(self._inner, @intFromEnum(unit), relative_to);
|
const res = c.temporal_rs_Duration_total(self._inner, @intFromEnum(unit), relative_to);
|
||||||
if (!res.is_ok) return error.TemporalError;
|
return temporal_rs.success(res) orelse return error.TemporalError;
|
||||||
return res.unnamed_0.ok;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get the total value of the duration with an explicit provider.
|
/// Get the total value of the duration with an explicit provider.
|
||||||
fn totalWithProvider(self: Duration, unit: Unit, relative_to: RelativeTo, provider: *const c.Provider) !f64 {
|
fn totalWithProvider(self: Duration, unit: Unit, relative_to: RelativeTo, provider: *const c.Provider) !f64 {
|
||||||
const res = c.temporal_rs_Duration_total_with_provider(self._inner, @intFromEnum(unit), relative_to, provider);
|
const res = c.temporal_rs_Duration_total_with_provider(self._inner, @intFromEnum(unit), relative_to, provider);
|
||||||
if (!res.is_ok) return error.TemporalError;
|
return temporal_rs.success(res) orelse return error.TemporalError;
|
||||||
return res.unnamed_0.ok;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Convert to string (Temporal.Duration.prototype.toString); caller owns returned slice.
|
/// Convert to string (Temporal.Duration.prototype.toString); caller owns returned slice.
|
||||||
pub fn toString(self: Duration, allocator: std.mem.Allocator, options: ToStringRoundingOptions) ![]u8 {
|
pub fn toString(self: Duration, allocator: std.mem.Allocator, options: ToStringRoundingOptions) ![]u8 {
|
||||||
const writer = c.diplomat_buffer_write_create(128);
|
var write = temporal_rs.DiplomatWrite.init(allocator);
|
||||||
defer c.diplomat_buffer_write_destroy(writer);
|
defer write.deinit();
|
||||||
|
|
||||||
const res = c.temporal_rs_Duration_to_string(self._inner, options, writer);
|
const res = c.temporal_rs_Duration_to_string(self._inner, options, &write.inner);
|
||||||
try handleVoidResult(res);
|
try handleVoidResult(res);
|
||||||
|
|
||||||
const len = c.diplomat_buffer_write_len(writer);
|
return try write.toOwnedSlice();
|
||||||
const source = c.diplomat_buffer_write_get_bytes(writer)[0..len];
|
|
||||||
|
|
||||||
const out = try allocator.alloc(u8, len);
|
|
||||||
std.mem.copyForwards(u8, out, source);
|
|
||||||
return out;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn toJSON(self: Duration, allocator: std.mem.Allocator) ![]u8 {
|
pub fn toJSON(self: Duration, allocator: std.mem.Allocator) ![]u8 {
|
||||||
|
|
@ -348,14 +206,11 @@ pub fn deinit(self: Duration) void {
|
||||||
// --- Helpers -----------------------------------------------------------------
|
// --- Helpers -----------------------------------------------------------------
|
||||||
|
|
||||||
fn handleVoidResult(res: anytype) !void {
|
fn handleVoidResult(res: anytype) !void {
|
||||||
if (!res.is_ok) return error.TemporalError;
|
_ = temporal_rs.success(res) orelse return error.TemporalError;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn wrapDuration(res: anytype) !Duration {
|
fn wrapDuration(res: anytype) !Duration {
|
||||||
if (!res.is_ok) return error.TemporalError;
|
const ptr = (temporal_rs.success(res) orelse return error.TemporalError) orelse return error.TemporalError;
|
||||||
const maybe_ptr = res.unnamed_0.ok;
|
|
||||||
if (maybe_ptr == null) return error.TemporalError;
|
|
||||||
const ptr: *c.Duration = maybe_ptr.?;
|
|
||||||
return .{ ._inner = ptr };
|
return .{ ._inner = ptr };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -124,18 +124,13 @@ pub fn toString(self: Instant, allocator: std.mem.Allocator, opts: ToStringOptio
|
||||||
const zone_opt = temporal_rs.toTimeZoneOption(opts.time_zone);
|
const zone_opt = temporal_rs.toTimeZoneOption(opts.time_zone);
|
||||||
const rounding = optsToRounding(opts);
|
const rounding = optsToRounding(opts);
|
||||||
|
|
||||||
const writer = c.diplomat_buffer_write_create(128);
|
var write = temporal_rs.DiplomatWrite.init(allocator);
|
||||||
defer c.diplomat_buffer_write_destroy(writer);
|
defer write.deinit();
|
||||||
|
|
||||||
const res = c.temporal_rs_Instant_to_ixdtf_string_with_compiled_data(self._inner, zone_opt, rounding, writer);
|
const res = c.temporal_rs_Instant_to_ixdtf_string_with_compiled_data(self._inner, zone_opt, rounding, &write.inner);
|
||||||
try handleVoidResult(res);
|
try handleVoidResult(res);
|
||||||
|
|
||||||
const len = c.diplomat_buffer_write_len(writer);
|
return try write.toOwnedSlice();
|
||||||
const source = c.diplomat_buffer_write_get_bytes(writer)[0..len];
|
|
||||||
|
|
||||||
const out = try allocator.alloc(u8, len);
|
|
||||||
std.mem.copyForwards(u8, out, source);
|
|
||||||
return out;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Convert to string using an explicit provider.
|
/// Convert to string using an explicit provider.
|
||||||
|
|
@ -143,18 +138,13 @@ fn toStringWithProvider(self: Instant, allocator: std.mem.Allocator, provider: *
|
||||||
const zone_opt = temporal_rs.toTimeZoneOption(opts.time_zone);
|
const zone_opt = temporal_rs.toTimeZoneOption(opts.time_zone);
|
||||||
const rounding = optsToRounding(opts);
|
const rounding = optsToRounding(opts);
|
||||||
|
|
||||||
const writer = c.diplomat_buffer_write_create(128);
|
var write = temporal_rs.DiplomatWrite.init(allocator);
|
||||||
defer c.diplomat_buffer_write_destroy(writer);
|
defer write.deinit();
|
||||||
|
|
||||||
const res = c.temporal_rs_Instant_to_ixdtf_string_with_provider(self._inner, zone_opt, rounding, provider, writer);
|
const res = c.temporal_rs_Instant_to_ixdtf_string_with_provider(self._inner, zone_opt, rounding, provider, &write.inner);
|
||||||
try handleVoidResult(res);
|
try handleVoidResult(res);
|
||||||
|
|
||||||
const len = c.diplomat_buffer_write_len(writer);
|
return try write.toOwnedSlice();
|
||||||
const source = c.diplomat_buffer_write_get_bytes(writer)[0..len];
|
|
||||||
|
|
||||||
const out = try allocator.alloc(u8, len);
|
|
||||||
std.mem.copyForwards(u8, out, source);
|
|
||||||
return out;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn toJSON(self: Instant, allocator: std.mem.Allocator) ![]u8 {
|
pub fn toJSON(self: Instant, allocator: std.mem.Allocator) ![]u8 {
|
||||||
|
|
@ -190,43 +180,26 @@ pub fn deinit(self: Instant) void {
|
||||||
// --- Helpers -----------------------------------------------------------------
|
// --- Helpers -----------------------------------------------------------------
|
||||||
|
|
||||||
fn wrapInstant(res: anytype) !Instant {
|
fn wrapInstant(res: anytype) !Instant {
|
||||||
if (!res.is_ok) return error.TemporalError;
|
const ptr = (temporal_rs.success(res) orelse return error.TemporalError) orelse return error.TemporalError;
|
||||||
const maybe_ptr = res.unnamed_0.ok;
|
return .{
|
||||||
if (maybe_ptr == null) return error.TemporalError;
|
._inner = ptr,
|
||||||
const ptr: *c.Instant = maybe_ptr.?;
|
.epoch_milliseconds = c.temporal_rs_Instant_epoch_milliseconds(ptr),
|
||||||
return .{ ._inner = ptr, .epoch_milliseconds = c.temporal_rs_Instant_epoch_milliseconds(ptr), .epoch_nanoseconds = temporal_rs.fromI128Nanoseconds(c.temporal_rs_Instant_epoch_nanoseconds(ptr)) };
|
.epoch_nanoseconds = temporal_rs.fromI128Nanoseconds(c.temporal_rs_Instant_epoch_nanoseconds(ptr)),
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
fn wrapDuration(res: anytype) !DurationHandle {
|
fn wrapDuration(res: anytype) !DurationHandle {
|
||||||
if (!res.is_ok) return error.TemporalError;
|
const ptr = (temporal_rs.success(res) orelse return error.TemporalError) orelse return error.TemporalError;
|
||||||
return .{ .ptr = res.unnamed_0.ok orelse return error.TemporalError };
|
return .{ .ptr = ptr };
|
||||||
}
|
}
|
||||||
|
|
||||||
fn wrapZonedDateTime(res: anytype) !ZonedDateTimeHandle {
|
fn wrapZonedDateTime(res: anytype) !ZonedDateTimeHandle {
|
||||||
if (!res.is_ok) return error.TemporalError;
|
const ptr = (temporal_rs.success(res) orelse return error.TemporalError) orelse return error.TemporalError;
|
||||||
return .{ .ptr = res.unnamed_0.ok orelse return error.TemporalError };
|
return .{ .ptr = ptr };
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handleVoidResult(res: anytype) !void {
|
fn handleVoidResult(res: anytype) !void {
|
||||||
if (!res.is_ok) return error.TemporalError;
|
_ = temporal_rs.success(res) orelse return error.TemporalError;
|
||||||
}
|
|
||||||
|
|
||||||
fn i128ToParts(value: i128) temporal_rs.c.I128Nanoseconds {
|
|
||||||
const is_neg = value < 0;
|
|
||||||
const mag: u128 = if (is_neg) @intCast(@as(u128, @intCast(-value))) else @intCast(value);
|
|
||||||
const mask: u64 = 1 << 63;
|
|
||||||
var high: u64 = @intCast(mag >> 64);
|
|
||||||
const low: u64 = @intCast(mag & 0xffff_ffff_ffff_ffff);
|
|
||||||
if (is_neg) high |= mask;
|
|
||||||
return .{ .high = high, .low = low };
|
|
||||||
}
|
|
||||||
|
|
||||||
fn partsToI128(value: temporal_rs.c.I128Nanoseconds) i128 {
|
|
||||||
const mask: u64 = 1 << 63;
|
|
||||||
const is_neg = (value.high & mask) != 0;
|
|
||||||
const mag: u128 = ((@as(u128, value.high & ~mask)) << 64) | value.low;
|
|
||||||
if (is_neg) return -@as(i128, @intCast(mag));
|
|
||||||
return @as(i128, @intCast(mag));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn defaultPrecision() Precision {
|
fn defaultPrecision() Precision {
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue