Skip to content

Commit c814ae6

Browse files
committed
Add Writeable getters for some types, use in FFI
1 parent 03cdc44 commit c814ae6

File tree

16 files changed

+124
-42
lines changed

16 files changed

+124
-42
lines changed

Cargo.lock

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/builtins/compiled/instant.rs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,4 +15,16 @@ impl Instant {
1515
) -> TemporalResult<String> {
1616
self.to_ixdtf_string_with_provider(timezone, options, &*TZ_PROVIDER)
1717
}
18+
19+
/// Returns the RFC9557 (IXDTF) string for this `Instant` with the
20+
/// provided options as a Writeable
21+
///
22+
/// Enable with the `compiled_data` feature flag.
23+
pub fn to_ixdtf_writeable(
24+
&self,
25+
timezone: Option<&TimeZone>,
26+
options: ToStringRoundingOptions,
27+
) -> TemporalResult<impl writeable::Writeable + '_> {
28+
self.to_ixdtf_writeable_with_provider(timezone, options, &*TZ_PROVIDER)
29+
}
1830
}

src/builtins/core/date.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ use crate::{
1717
use alloc::{format, string::String};
1818
use core::{cmp::Ordering, str::FromStr};
1919
use icu_calendar::AnyCalendarKind;
20+
use writeable::Writeable;
2021

2122
use super::{
2223
calendar::month_to_month_code,
@@ -679,6 +680,13 @@ impl PlainDate {
679680

680681
#[inline]
681682
pub fn to_ixdtf_string(&self, display_calendar: DisplayCalendar) -> String {
683+
self.to_ixdtf_writeable(display_calendar)
684+
.write_to_string()
685+
.into()
686+
}
687+
688+
#[inline]
689+
pub fn to_ixdtf_writeable(&self, display_calendar: DisplayCalendar) -> impl Writeable + '_ {
682690
IxdtfStringBuilder::default()
683691
.with_date(self.iso)
684692
.with_calendar(self.calendar.identifier(), display_calendar)

src/builtins/core/datetime.rs

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ use crate::{
2020
use alloc::string::String;
2121
use core::{cmp::Ordering, str::FromStr};
2222
use tinystr::TinyAsciiStr;
23+
use writeable::Writeable;
2324

2425
/// A partial PlainDateTime record
2526
#[derive(Debug, Default, Clone)]
@@ -806,11 +807,11 @@ impl PlainDateTime {
806807
Ok(PlainTime::new_unchecked(self.iso.time))
807808
}
808809

809-
pub fn to_ixdtf_string(
810+
pub fn to_ixdtf_writeable(
810811
&self,
811812
options: ToStringRoundingOptions,
812813
display_calendar: DisplayCalendar,
813-
) -> TemporalResult<String> {
814+
) -> TemporalResult<impl Writeable + '_> {
814815
let resolved_options = options.resolve()?;
815816
let result = self
816817
.iso
@@ -820,12 +821,20 @@ impl PlainDateTime {
820821
if !result.is_within_limits() {
821822
return Err(TemporalError::range().with_message("DateTime is not within valid limits."));
822823
}
823-
let ixdtf_string = IxdtfStringBuilder::default()
824+
let builder = IxdtfStringBuilder::default()
824825
.with_date(result.date)
825826
.with_time(result.time, resolved_options.precision)
826-
.with_calendar(self.calendar.identifier(), display_calendar)
827-
.build();
828-
Ok(ixdtf_string)
827+
.with_calendar(self.calendar.identifier(), display_calendar);
828+
Ok(builder)
829+
}
830+
831+
pub fn to_ixdtf_string(
832+
&self,
833+
options: ToStringRoundingOptions,
834+
display_calendar: DisplayCalendar,
835+
) -> TemporalResult<String> {
836+
self.to_ixdtf_writeable(options, display_calendar)
837+
.map(|x| x.write_to_string().into())
829838
}
830839
}
831840

src/builtins/core/instant.rs

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ use crate::{
2121

2222
use ixdtf::parsers::records::UtcOffsetRecordOrZ;
2323
use num_traits::Euclid;
24+
use writeable::Writeable;
2425

2526
use super::{
2627
duration::normalized::{NormalizedDurationRecord, NormalizedTimeDuration},
@@ -289,6 +290,16 @@ impl Instant {
289290
options: ToStringRoundingOptions,
290291
provider: &impl TimeZoneProvider,
291292
) -> TemporalResult<String> {
293+
self.to_ixdtf_writeable_with_provider(timezone, options, provider)
294+
.map(|x| x.write_to_string().into())
295+
}
296+
297+
pub fn to_ixdtf_writeable_with_provider(
298+
&self,
299+
timezone: Option<&TimeZone>,
300+
options: ToStringRoundingOptions,
301+
provider: &impl TimeZoneProvider,
302+
) -> TemporalResult<impl Writeable + '_> {
292303
let resolved_options = options.resolve()?;
293304
let round = self.round_instant(ResolvedRoundingOptions::from_to_string_options(
294305
&resolved_options,
@@ -306,12 +317,11 @@ impl Instant {
306317
ixdtf = ixdtf.with_z(DisplayOffset::Auto);
307318
TimeZone::default().get_iso_datetime_for(&rounded_instant, provider)?
308319
};
309-
let ixdtf_string = ixdtf
320+
let builder = ixdtf
310321
.with_date(datetime.date)
311-
.with_time(datetime.time, resolved_options.precision)
312-
.build();
322+
.with_time(datetime.time, resolved_options.precision);
313323

314-
Ok(ixdtf_string)
324+
Ok(builder)
315325
}
316326
}
317327

src/builtins/core/month_day.rs

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ use crate::{
1111
};
1212

1313
use super::{PartialDate, PlainDate};
14+
use writeable::Writeable;
1415

1516
/// The native Rust implementation of `Temporal.PlainMonthDay`
1617
#[non_exhaustive]
@@ -164,14 +165,20 @@ impl PlainMonthDay {
164165
}
165166

166167
pub fn to_ixdtf_string(&self, display_calendar: DisplayCalendar) -> String {
168+
self.to_ixdtf_writeable(display_calendar)
169+
.write_to_string()
170+
.into()
171+
}
172+
173+
pub fn to_ixdtf_writeable(&self, display_calendar: DisplayCalendar) -> impl Writeable + '_ {
167174
let ixdtf = FormattableMonthDay {
168175
date: FormattableDate(self.iso_year(), self.iso_month(), self.iso.day),
169176
calendar: FormattableCalendar {
170177
show: display_calendar,
171178
calendar: self.calendar().identifier(),
172179
},
173180
};
174-
ixdtf.to_string()
181+
ixdtf
175182
}
176183
}
177184

src/builtins/core/time.rs

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ use crate::{
1212
};
1313
use alloc::string::String;
1414
use core::str::FromStr;
15+
use writeable::Writeable;
1516

1617
use super::{duration::normalized::NormalizedTimeDuration, PlainDateTime};
1718

@@ -474,14 +475,21 @@ impl PlainTime {
474475
}
475476

476477
pub fn to_ixdtf_string(&self, options: ToStringRoundingOptions) -> TemporalResult<String> {
478+
self.to_ixdtf_writeable(options)
479+
.map(|x| x.write_to_string().into())
480+
}
481+
482+
#[inline]
483+
pub fn to_ixdtf_writeable(
484+
&self,
485+
options: ToStringRoundingOptions,
486+
) -> TemporalResult<impl Writeable + '_> {
477487
let resolved = options.resolve()?;
478488
let (_, result) = self
479489
.iso
480490
.round(ResolvedRoundingOptions::from_to_string_options(&resolved))?;
481-
let ixdtf_string = IxdtfStringBuilder::default()
482-
.with_time(result, resolved.precision)
483-
.build();
484-
Ok(ixdtf_string)
491+
let builder = IxdtfStringBuilder::default().with_time(result, resolved.precision);
492+
Ok(builder)
485493
}
486494
}
487495

src/builtins/core/year_month.rs

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ use crate::{
2020
use super::{
2121
duration::normalized::NormalizedDurationRecord, Duration, PartialDate, PlainDate, PlainDateTime,
2222
};
23+
use writeable::Writeable;
2324

2425
/// The native Rust implementation of `Temporal.YearMonth`.
2526
#[non_exhaustive]
@@ -430,14 +431,22 @@ impl PlainYearMonth {
430431
/// Returns a RFC9557 IXDTF string for the current `PlainYearMonth`
431432
#[inline]
432433
pub fn to_ixdtf_string(&self, display_calendar: DisplayCalendar) -> String {
434+
self.to_ixdtf_writeable(display_calendar)
435+
.write_to_string()
436+
.into()
437+
}
438+
439+
/// Returns a RFC9557 IXDTF string for the current `PlainYearMonth` as a Writeable
440+
#[inline]
441+
pub fn to_ixdtf_writeable(&self, display_calendar: DisplayCalendar) -> impl Writeable + '_ {
433442
let ixdtf = FormattableYearMonth {
434443
date: FormattableDate(self.iso_year(), self.iso_month(), self.iso.day),
435444
calendar: FormattableCalendar {
436445
show: display_calendar,
437446
calendar: self.calendar().identifier(),
438447
},
439448
};
440-
ixdtf.to_string()
449+
ixdtf
441450
}
442451
}
443452

src/parsers.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,16 @@ impl<'a> IxdtfStringBuilder<'a> {
9191
}
9292
}
9393

94+
impl<'a> Writeable for IxdtfStringBuilder<'a> {
95+
fn write_to<W: core::fmt::Write + ?Sized>(&self, sink: &mut W) -> core::fmt::Result {
96+
self.inner.write_to(sink)
97+
}
98+
99+
fn writeable_length_hint(&self) -> LengthHint {
100+
self.inner.writeable_length_hint()
101+
}
102+
}
103+
94104
#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
95105
pub enum Precision {
96106
#[default]

temporal_capi/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ num-traits.workspace = true
2424
temporal_rs = { workspace = true, default-features = false }
2525
icu_calendar = { version = "2.0.2", default-features = false }
2626
icu_locale = { version = "2.0.0" }
27+
writeable = "0.6.1"
2728

2829
[features]
2930
compiled_data = ["temporal_rs/compiled_data"]

temporal_capi/src/instant.rs

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -138,10 +138,12 @@ pub mod ffi {
138138
options: ToStringRoundingOptions,
139139
write: &mut DiplomatWrite,
140140
) -> Result<(), TemporalError> {
141-
use core::fmt::Write;
142-
let string = self.0.to_ixdtf_string(zone.map(|x| &x.0), options.into())?;
143-
// throw away the error, this should always succeed
144-
let _ = write.write_str(&string);
141+
let writeable = self
142+
.0
143+
.to_ixdtf_writeable(zone.map(|x| &x.0), options.into())?;
144+
// This can only fail in cases where the DiplomatWriteable is capped, we
145+
// don't care about that.
146+
let _ = writeable.write_to(write);
145147

146148
Ok(())
147149
}

temporal_capi/src/plain_date.rs

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ pub mod ffi {
1919
use core::fmt::Write;
2020
use diplomat_runtime::{DiplomatOption, DiplomatStrSlice, DiplomatWrite};
2121
use diplomat_runtime::{DiplomatStr, DiplomatStr16};
22+
use writeable::Writeable;
2223

2324
use core::str::FromStr;
2425

@@ -277,10 +278,10 @@ pub mod ffi {
277278
display_calendar: DisplayCalendar,
278279
write: &mut DiplomatWrite,
279280
) {
280-
// TODO this double-allocates, an API returning a Writeable or impl Write would be better
281-
let string = self.0.to_ixdtf_string(display_calendar.into());
282-
// throw away the error, this should always succeed
283-
let _ = write.write_str(&string);
281+
let writeable = self.0.to_ixdtf_writeable(display_calendar.into());
282+
// This can only fail in cases where the DiplomatWriteable is capped, we
283+
// don't care about that.
284+
let _ = writeable.write_to(write);
284285
}
285286
}
286287
}

temporal_capi/src/plain_date_time.rs

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ pub mod ffi {
2020
use core::str::FromStr;
2121
use diplomat_runtime::DiplomatWrite;
2222
use diplomat_runtime::{DiplomatStr, DiplomatStr16};
23+
use writeable::Writeable;
2324

2425
#[diplomat::opaque]
2526
pub struct PlainDateTime(pub(crate) temporal_rs::PlainDateTime);
@@ -319,12 +320,13 @@ pub mod ffi {
319320
display_calendar: DisplayCalendar,
320321
write: &mut DiplomatWrite,
321322
) -> Result<(), TemporalError> {
322-
// TODO this double-allocates, an API returning a Writeable or impl Write would be better
323-
let string = self
323+
let writeable = self
324324
.0
325-
.to_ixdtf_string(options.into(), display_calendar.into())?;
326-
// throw away the error, this should always succeed
327-
let _ = write.write_str(&string);
325+
.to_ixdtf_writeable(options.into(), display_calendar.into())?;
326+
327+
// This can only fail in cases where the DiplomatWriteable is capped, we
328+
// don't care about that.
329+
let _ = writeable.write_to(write);
328330
Ok(())
329331
}
330332
}

temporal_capi/src/plain_month_day.rs

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ pub mod ffi {
1414
use core::str::FromStr;
1515
use diplomat_runtime::DiplomatWrite;
1616
use diplomat_runtime::{DiplomatStr, DiplomatStr16};
17+
use writeable::Writeable;
1718

1819
#[diplomat::opaque]
1920
pub struct PlainMonthDay(pub(crate) temporal_rs::PlainMonthDay);
@@ -104,10 +105,10 @@ pub mod ffi {
104105
display_calendar: DisplayCalendar,
105106
write: &mut DiplomatWrite,
106107
) {
107-
// TODO this double-allocates, an API returning a Writeable or impl Write would be better
108-
let string = self.0.to_ixdtf_string(display_calendar.into());
109-
// throw away the error, this should always succeed
110-
let _ = write.write_str(&string);
108+
let writeable = self.0.to_ixdtf_writeable(display_calendar.into());
109+
// This can only fail in cases where the DiplomatWriteable is capped, we
110+
// don't care about that.
111+
let _ = writeable.write_to(write);
111112
}
112113
}
113114
}

temporal_capi/src/plain_time.rs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,10 @@ pub mod ffi {
1010
ArithmeticOverflow, DifferenceSettings, RoundingMode, ToStringRoundingOptions, Unit,
1111
};
1212
use alloc::string::String;
13-
use core::fmt::Write;
1413
use core::str::FromStr;
1514
use diplomat_runtime::{DiplomatOption, DiplomatWrite};
1615
use diplomat_runtime::{DiplomatStr, DiplomatStr16};
16+
use writeable::Writeable;
1717

1818
#[diplomat::opaque]
1919
pub struct PlainTime(pub(crate) temporal_rs::PlainTime);
@@ -205,10 +205,10 @@ pub mod ffi {
205205
options: ToStringRoundingOptions,
206206
write: &mut DiplomatWrite,
207207
) -> Result<(), TemporalError> {
208-
// TODO this double-allocates, an API returning a Writeable or impl Write would be better
209-
let string = self.0.to_ixdtf_string(options.into())?;
210-
// throw away the error, the write itself should always succeed
211-
let _ = write.write_str(&string);
208+
let writeable = self.0.to_ixdtf_writeable(options.into())?;
209+
// This can only fail in cases where the DiplomatWriteable is capped, we
210+
// don't care about that.
211+
let _ = writeable.write_to(write);
212212

213213
Ok(())
214214
}

temporal_capi/src/plain_year_month.rs

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ pub mod ffi {
1313
use core::fmt::Write;
1414
use diplomat_runtime::DiplomatWrite;
1515
use diplomat_runtime::{DiplomatStr, DiplomatStr16};
16+
use writeable::Writeable;
1617

1718
use core::str::FromStr;
1819

@@ -178,10 +179,10 @@ pub mod ffi {
178179
display_calendar: DisplayCalendar,
179180
write: &mut DiplomatWrite,
180181
) {
181-
// TODO this double-allocates, an API returning a Writeable or impl Write would be better
182-
let string = self.0.to_ixdtf_string(display_calendar.into());
183-
// throw away the error, this should always succeed
184-
let _ = write.write_str(&string);
182+
let writeable = self.0.to_ixdtf_writeable(display_calendar.into());
183+
// This can only fail in cases where the DiplomatWriteable is capped, we
184+
// don't care about that.
185+
let _ = writeable.write_to(write);
185186
}
186187
}
187188
}

0 commit comments

Comments
 (0)