use temporal_rs::provider::TimeZoneId;
use temporal_rs::UtcOffset;
use timezone_provider::provider::{NormalizedId, ResolvedId};
#[diplomat::bridge]
#[diplomat::abi_rename = "temporal_rs_{0}"]
pub mod ffi {
use crate::error::ffi::TemporalError;
use crate::provider::ffi::Provider;
use core::fmt::Write;
use diplomat_runtime::DiplomatWrite;
#[derive(Copy, Clone)]
pub struct TimeZone {
pub offset_minutes: i16,
pub resolved_id: usize,
pub normalized_id: usize,
pub is_iana_id: bool,
}
impl TimeZone {
#[cfg(feature = "compiled_data")]
pub fn try_from_identifier_str(ident: &DiplomatStr) -> Result<Self, TemporalError> {
Self::try_from_identifier_str_with_provider(ident, &Provider::compiled())
}
pub fn try_from_identifier_str_with_provider<'p>(
ident: &DiplomatStr,
p: &Provider<'p>,
) -> Result<Self, TemporalError> {
let Ok(ident) = core::str::from_utf8(ident) else {
return Err(temporal_rs::TemporalError::range().into());
};
with_provider!(p, |p| {
temporal_rs::TimeZone::try_from_identifier_str_with_provider(ident, p)
})
.map(Into::into)
.map_err(Into::into)
}
pub fn try_from_offset_str(ident: &DiplomatStr) -> Result<Self, TemporalError> {
temporal_rs::UtcOffset::from_utf8(ident)
.map(|x| temporal_rs::TimeZone::UtcOffset(x).into())
.map_err(Into::into)
}
#[cfg(feature = "compiled_data")]
pub fn try_from_str(ident: &DiplomatStr) -> Result<Self, TemporalError> {
Self::try_from_str_with_provider(ident, &Provider::compiled())
}
pub fn try_from_str_with_provider<'p>(
ident: &DiplomatStr,
p: &Provider<'p>,
) -> Result<Self, TemporalError> {
let Ok(ident) = core::str::from_utf8(ident) else {
return Err(temporal_rs::TemporalError::range().into());
};
with_provider!(p, |p| temporal_rs::TimeZone::try_from_str_with_provider(
ident, p
))
.map(Into::into)
.map_err(Into::into)
}
#[cfg(feature = "compiled_data")]
pub fn identifier(self, write: &mut DiplomatWrite) {
let _ = self.identifier_with_provider(&Provider::compiled(), write);
}
pub fn identifier_with_provider<'p>(
self,
p: &Provider<'p>,
write: &mut DiplomatWrite,
) -> Result<(), TemporalError> {
let s =
with_provider!(p, |p| self.tz().identifier_with_provider(p)).unwrap_or_default();
let _ = write.write_str(&s);
Ok(())
}
#[cfg(feature = "compiled_data")]
pub fn utc() -> Self {
temporal_rs::TimeZone::utc().into()
}
pub fn utc_with_provider<'p>(p: &Provider<'p>) -> Result<Self, TemporalError> {
Ok(with_provider!(p, |p| { temporal_rs::TimeZone::utc_with_provider(p) }).into())
}
pub fn zero() -> Self {
temporal_rs::TimeZone::UtcOffset(Default::default()).into()
}
#[cfg(feature = "compiled_data")]
pub fn primary_identifier(self) -> Result<Self, TemporalError> {
self.primary_identifier_with_provider(&Provider::compiled())
}
pub fn primary_identifier_with_provider<'p>(
self,
p: &Provider<'p>,
) -> Result<Self, TemporalError> {
with_provider!(p, |p| self.tz().primary_identifier_with_provider(p))
.map(Into::into)
.map_err(Into::into)
}
pub(crate) fn tz(self) -> temporal_rs::TimeZone {
self.into()
}
}
}
impl From<ffi::TimeZone> for temporal_rs::TimeZone {
fn from(other: ffi::TimeZone) -> Self {
if other.is_iana_id {
Self::IanaIdentifier(TimeZoneId {
normalized: NormalizedId(other.normalized_id),
resolved: ResolvedId(other.resolved_id),
})
} else {
Self::UtcOffset(UtcOffset::from_minutes(other.offset_minutes))
}
}
}
impl From<temporal_rs::TimeZone> for ffi::TimeZone {
fn from(other: temporal_rs::TimeZone) -> Self {
match other {
temporal_rs::TimeZone::UtcOffset(offset) => Self {
offset_minutes: offset.minutes(),
is_iana_id: false,
normalized_id: 0,
resolved_id: 0,
},
temporal_rs::TimeZone::IanaIdentifier(id) => Self {
normalized_id: id.normalized.0,
resolved_id: id.resolved.0,
is_iana_id: true,
offset_minutes: 0,
},
}
}
}