Skip to content

Update ixdtf to icu4x main git branch #365

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 13 commits into from
Jul 4, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ icu_calendar = { version = "2.0.2", default-features = false }
icu_locale = "2.0.0"
rustc-hash = "2.1.0"
num-traits = { version = "0.2.19", default-features = false }
ixdtf = "0.5.0"
ixdtf = "0.6.0"
iana-time-zone = "0.1.63"
log = "0.4.27"
tzif = "0.4.0"
Expand Down
4 changes: 2 additions & 2 deletions src/builtins/core/duration.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ use crate::{
use alloc::format;
use alloc::string::String;
use core::{cmp::Ordering, str::FromStr};
use ixdtf::parsers::{records::TimeDurationRecord, IsoDurationParser};
use ixdtf::{encoding::Utf8, parsers::IsoDurationParser, records::TimeDurationRecord};
use normalized::NormalizedDurationRecord;

use self::normalized::NormalizedTimeDuration;
Expand Down Expand Up @@ -418,7 +418,7 @@ impl Duration {

// Converts a UTF-8 encoded string into a `Duration`.
pub fn from_utf8(s: &[u8]) -> TemporalResult<Self> {
let parse_record = IsoDurationParser::from_utf8(s)
let parse_record = IsoDurationParser::<Utf8>::from_utf8(s)
.parse()
.map_err(|e| TemporalError::range().with_message(format!("{e}")))?;

Expand Down
2 changes: 1 addition & 1 deletion src/builtins/core/instant.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ use crate::{
Calendar, TemporalError, TemporalResult, TemporalUnwrap, TimeZone,
};

use ixdtf::parsers::records::UtcOffsetRecordOrZ;
use ixdtf::records::UtcOffsetRecordOrZ;
use num_traits::Euclid;
use writeable::Writeable;

Expand Down
31 changes: 24 additions & 7 deletions src/builtins/core/timezone.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,12 @@
use alloc::string::{String, ToString};
use alloc::{vec, vec::Vec};

use ixdtf::parsers::records::{MinutePrecisionOffset, TimeZoneRecord, UtcOffsetRecord};
use ixdtf::parsers::TimeZoneParser;
use core::str::from_utf8;
use ixdtf::encoding::Utf8;
use ixdtf::{
parsers::TimeZoneParser,
records::{MinutePrecisionOffset, TimeZoneRecord, UtcOffsetRecord},
};
use num_traits::ToPrimitive;

use crate::builtins::core::duration::DateDuration;
Expand Down Expand Up @@ -88,11 +92,12 @@ pub enum TimeZone {
impl TimeZone {
// Create a `TimeZone` from an ixdtf `TimeZoneRecord`.
#[inline]
pub(crate) fn from_time_zone_record(record: TimeZoneRecord) -> TemporalResult<Self> {
pub(crate) fn from_time_zone_record(record: TimeZoneRecord<Utf8>) -> TemporalResult<Self> {
let timezone = match record {
TimeZoneRecord::Name(s) => {
TimeZone::IanaIdentifier(String::from_utf8_lossy(s).into_owned())
}
TimeZoneRecord::Name(s) => TimeZone::IanaIdentifier(
String::from_utf8(s.to_vec())
.map_err(|e| TemporalError::range().with_message(e.to_string()))?,
),
TimeZoneRecord::Offset(offset_record) => {
let offset = UtcOffset::from_ixdtf_record(offset_record);
TimeZone::UtcOffset(offset)
Expand All @@ -109,7 +114,19 @@ impl TimeZone {
if identifier == "Z" {
return Ok(TimeZone::UtcOffset(UtcOffset(0)));
}
parse_identifier(identifier)
parse_identifier(identifier).map(|tz| match tz {
TimeZoneRecord::Name(items) => Ok(TimeZone::IanaIdentifier(
from_utf8(items)
.or(Err(
TemporalError::range().with_message("Invalid TimeZone Identifier")
))?
.to_string(),
)),
TimeZoneRecord::Offset(minute_precision_offset) => Ok(TimeZone::UtcOffset(
UtcOffset::from_ixdtf_record(minute_precision_offset),
)),
_ => Err(TemporalError::range().with_message("Invalid TimeZone Identifier")),
})?
}

pub fn try_from_str(src: &str) -> TemporalResult<Self> {
Expand Down
2 changes: 1 addition & 1 deletion src/builtins/core/zoneddatetime.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

use alloc::string::String;
use core::{cmp::Ordering, num::NonZeroU128};
use ixdtf::parsers::records::UtcOffsetRecordOrZ;
use ixdtf::records::UtcOffsetRecordOrZ;
use tinystr::TinyAsciiStr;

use crate::{
Expand Down
2 changes: 1 addition & 1 deletion src/iso.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
//! An `IsoDateTime` has the internal slots of both an `IsoDate` and `IsoTime`.

use core::num::NonZeroU128;
use ixdtf::parsers::records::TimeRecord;
use ixdtf::records::TimeRecord;

use crate::{
builtins::core::{
Expand Down
2 changes: 1 addition & 1 deletion src/options/relative_to.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ use crate::parsers::parse_date_time;
use crate::provider::TimeZoneProvider;
use crate::{TemporalResult, TemporalUnwrap};

use ixdtf::parsers::records::UtcOffsetRecordOrZ;
use ixdtf::records::UtcOffsetRecordOrZ;

// ==== RelativeTo Object ====

Expand Down
29 changes: 15 additions & 14 deletions src/parsers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,10 @@ use crate::{
Sign, TemporalError, TemporalResult,
};
use alloc::format;
use ixdtf::parsers::{
use ixdtf::{
encoding::Utf8,
parsers::IxdtfParser,
records::{Annotation, DateRecord, IxdtfParseRecord, TimeRecord, UtcOffsetRecordOrZ},
IxdtfParser,
};
use writeable::{impl_display_with_writeable, LengthHint, Writeable};

Expand Down Expand Up @@ -658,19 +659,19 @@ enum ParseVariant {
}

#[inline]
fn parse_ixdtf(source: &[u8], variant: ParseVariant) -> TemporalResult<IxdtfParseRecord> {
fn parse_ixdtf(source: &[u8], variant: ParseVariant) -> TemporalResult<IxdtfParseRecord<Utf8>> {
fn cast_handler<'a>(
_: &mut IxdtfParser<'a>,
handler: impl FnMut(Annotation<'a>) -> Option<Annotation<'a>>,
) -> impl FnMut(Annotation<'a>) -> Option<Annotation<'a>> {
_: &mut IxdtfParser<'a, Utf8>,
handler: impl FnMut(Annotation<'a, Utf8>) -> Option<Annotation<'a, Utf8>>,
) -> impl FnMut(Annotation<'a, Utf8>) -> Option<Annotation<'a, Utf8>> {
handler
}

let mut first_calendar: Option<Annotation> = None;
let mut first_calendar: Option<Annotation<Utf8>> = None;
let mut critical_duplicate_calendar = false;
let mut parser = IxdtfParser::from_utf8(source);

let handler = cast_handler(&mut parser, |annotation: Annotation<'_>| {
let handler = cast_handler(&mut parser, |annotation: Annotation<Utf8>| {
if annotation.key == "u-ca".as_bytes() {
match first_calendar {
Some(ref cal) => {
Expand Down Expand Up @@ -716,7 +717,7 @@ fn parse_ixdtf(source: &[u8], variant: ParseVariant) -> TemporalResult<IxdtfPars

/// A utility function for parsing a `DateTime` string
#[inline]
pub(crate) fn parse_date_time(source: &[u8]) -> TemporalResult<IxdtfParseRecord> {
pub(crate) fn parse_date_time(source: &[u8]) -> TemporalResult<IxdtfParseRecord<Utf8>> {
let record = parse_ixdtf(source, ParseVariant::DateTime)?;

if record.offset == Some(UtcOffsetRecordOrZ::Z) {
Expand All @@ -728,7 +729,7 @@ pub(crate) fn parse_date_time(source: &[u8]) -> TemporalResult<IxdtfParseRecord>
}

#[inline]
pub(crate) fn parse_zoned_date_time(source: &str) -> TemporalResult<IxdtfParseRecord> {
pub(crate) fn parse_zoned_date_time(source: &str) -> TemporalResult<IxdtfParseRecord<Utf8>> {
let record = parse_ixdtf(source.as_bytes(), ParseVariant::DateTime)?;

// TODO: Support rejecting subminute precision in time zone annootations
Expand Down Expand Up @@ -769,7 +770,7 @@ pub(crate) fn parse_instant(source: &[u8]) -> TemporalResult<IxdtfParseInstantRe
// Ensure that the record does not have an offset element.
//
// This handles the [~Zoned] in TemporalFooString productions
fn check_offset(record: IxdtfParseRecord) -> TemporalResult<IxdtfParseRecord> {
fn check_offset(record: IxdtfParseRecord<Utf8>) -> TemporalResult<IxdtfParseRecord<Utf8>> {
if record.offset == Some(UtcOffsetRecordOrZ::Z) {
return Err(TemporalError::range()
.with_message("UTC designator is not valid for plain date/time parsing."));
Expand All @@ -779,7 +780,7 @@ fn check_offset(record: IxdtfParseRecord) -> TemporalResult<IxdtfParseRecord> {

/// A utility function for parsing a `YearMonth` string
#[inline]
pub(crate) fn parse_year_month(source: &[u8]) -> TemporalResult<IxdtfParseRecord> {
pub(crate) fn parse_year_month(source: &[u8]) -> TemporalResult<IxdtfParseRecord<Utf8>> {
let ym_record = parse_ixdtf(source, ParseVariant::YearMonth);

let Err(ref e) = ym_record else {
Expand All @@ -796,7 +797,7 @@ pub(crate) fn parse_year_month(source: &[u8]) -> TemporalResult<IxdtfParseRecord
}

/// A utilty function for parsing a `MonthDay` String.
pub(crate) fn parse_month_day(source: &[u8]) -> TemporalResult<IxdtfParseRecord> {
pub(crate) fn parse_month_day(source: &[u8]) -> TemporalResult<IxdtfParseRecord<Utf8>> {
let md_record = parse_ixdtf(source, ParseVariant::MonthDay);
let Err(ref e) = md_record else {
return md_record.and_then(check_offset);
Expand All @@ -812,7 +813,7 @@ pub(crate) fn parse_month_day(source: &[u8]) -> TemporalResult<IxdtfParseRecord>
}

// Ensures that an IxdtfParseRecord was parsed with [~Zoned][+TimeRequired]
fn check_time_record(record: IxdtfParseRecord) -> TemporalResult<TimeRecord> {
fn check_time_record(record: IxdtfParseRecord<Utf8>) -> TemporalResult<TimeRecord> {
// Handle [~Zoned]
let record = check_offset(record)?;
// Handle [+TimeRequired]
Expand Down
Loading