blob: a105ffe064c4ffc795a48718abb96216dc68804d [file] [log] [blame]
// This file is part of ICU4X. For terms of use, please see the file
// called LICENSE at the top level of the ICU4X source tree
// (online at: https://github.com/unicode-org/icu4x/blob/main/LICENSE ).
use ffi::TimeZoneInfo;
#[diplomat::bridge]
#[diplomat::abi_rename = "icu4x_{0}_mv1"]
#[diplomat::attr(auto, namespace = "icu4x")]
pub mod ffi {
use alloc::boxed::Box;
use crate::{
date::ffi::IsoDate,
datetime::ffi::IsoDateTime,
time::ffi::Time,
utc_offset::ffi::{UtcOffset, UtcOffsetCalculator},
};
#[diplomat::opaque]
#[diplomat::rust_link(icu::time::TimeZone, Struct)]
pub struct TimeZone(pub(crate) icu_time::TimeZone);
impl TimeZone {
/// The unknown time zone.
#[diplomat::rust_link(icu::time::TimeZoneInfo::unknown, FnInStruct)]
#[diplomat::rust_link(icu::time::TimeZone::unknown, FnInStruct, hidden)]
#[diplomat::attr(auto, named_constructor)]
pub fn unknown() -> Box<TimeZone> {
Box::new(TimeZone(icu_time::TimeZone::unknown()))
}
/// Creates a time zone from a BCP-47 string.
///
/// Returns the unknown time zone if the string is not a valid BCP-47 subtag.
#[diplomat::rust_link(icu::time::TimeZone, Struct, compact)]
#[diplomat::rust_link(icu::time::TimeZone::from_str, FnInStruct, hidden)]
#[diplomat::rust_link(icu::time::TimeZone::deref, FnInStruct, hidden)]
#[diplomat::rust_link(icu::time::TimeZone::Target, AssociatedTypeInStruct, hidden)]
#[diplomat::attr(auto, named_constructor = "from_bcp47")]
#[diplomat::demo(default_constructor)]
pub fn create_from_bcp47(id: &DiplomatStr) -> Box<Self> {
tinystr::TinyAsciiStr::try_from_utf8(id)
.map(icu_time::TimeZone)
.map(TimeZone)
.map(Box::new)
.unwrap_or(Self::unknown())
}
#[diplomat::rust_link(icu::time::TimeZone::with_offset, FnInStruct)]
pub fn with_offset(&self, offset: &UtcOffset) -> Box<TimeZoneInfo> {
Box::new(self.0.with_offset(Some(offset.0)).into())
}
#[diplomat::rust_link(icu::time::TimeZone::without_offset, FnInStruct)]
pub fn without_offset(&self) -> Box<TimeZoneInfo> {
Box::new(self.0.without_offset().into())
}
}
#[diplomat::enum_convert(icu_time::zone::TimeZoneVariant, needs_wildcard)]
pub enum TimeZoneVariant {
Standard,
Daylight,
}
impl TimeZoneVariant {
/// Sets the `zone_variant` field to "daylight" time.
#[diplomat::rust_link(icu::time::zone::TimeZoneVariant::from_rearguard_isdst, FnInEnum)]
#[diplomat::rust_link(icu::time::TimeZoneInfo::with_zone_variant, FnInStruct)]
#[diplomat::rust_link(icu::time::zone::TimeZoneVariant, Enum, compact)]
pub fn from_rearguard_isdst(&mut self, isdst: bool) -> Self {
icu_time::zone::TimeZoneVariant::from_rearguard_isdst(isdst).into()
}
}
#[diplomat::opaque]
#[diplomat::rust_link(icu::time::TimeZoneInfo, Struct)]
#[diplomat::rust_link(icu::time::zone::models::AtTime, Enum, hidden)]
#[diplomat::rust_link(icu::time::zone::models::Base, Enum, hidden)]
#[diplomat::rust_link(icu::time::zone::models::Full, Enum, hidden)]
pub struct TimeZoneInfo {
pub(crate) time_zone_id: icu_time::TimeZone,
pub(crate) offset: Option<icu_time::zone::UtcOffset>,
pub(crate) zone_variant: Option<icu_time::zone::TimeZoneVariant>,
pub(crate) local_time: Option<(icu_calendar::Date<icu_calendar::Iso>, icu_time::Time)>,
}
impl TimeZoneInfo {
/// Creates a time zone for UTC (Coordinated Universal Time).
#[diplomat::rust_link(icu::time::TimeZoneInfo::utc, FnInStruct)]
#[diplomat::rust_link(icu::time::zone::UtcOffset::zero, FnInStruct, hidden)]
#[diplomat::attr(auto, named_constructor)]
pub fn utc() -> Box<TimeZoneInfo> {
Box::new(icu_time::TimeZoneInfo::utc().into())
}
/// Creates a time zone info from parts.
#[diplomat::attr(auto, constructor)]
pub fn from_parts(
time_zone_id: &TimeZone,
offset: Option<&UtcOffset>,
zone_variant: Option<TimeZoneVariant>,
) -> Box<TimeZoneInfo> {
Box::new(Self {
time_zone_id: time_zone_id.0,
offset: offset.map(|o| o.0),
zone_variant: zone_variant.map(Into::into),
local_time: None,
})
}
#[diplomat::rust_link(icu::time::TimeZoneInfo::time_zone_id, FnInStruct)]
pub fn time_zone_id(&self) -> Box<TimeZone> {
Box::new(TimeZone(self.time_zone_id))
}
#[diplomat::rust_link(icu::time::TimeZoneInfo::at_time, FnInStruct)]
pub fn at_time(&self, date: &IsoDate, time: &Time) -> Box<Self> {
Box::new(Self {
local_time: Some((date.0, time.0)),
..*self
})
}
#[diplomat::rust_link(icu::time::TimeZoneInfo::local_time, FnInStruct)]
pub fn local_time(&self) -> Option<IsoDateTime> {
Some(IsoDateTime {
date: Box::new(IsoDate(self.local_time?.0)),
time: Box::new(Time(self.local_time?.1)),
})
}
#[diplomat::rust_link(icu::time::TimeZoneInfo::with_zone_variant, FnInStruct)]
pub fn with_zone_variant(&self, time_zone_variant: TimeZoneVariant) -> Box<Self> {
Box::new(Self {
zone_variant: Some(time_zone_variant.into()),
..*self
})
}
/// Infers the zone variant.
///
/// Requires the offset and local time to be set.
#[diplomat::rust_link(icu::time::TimeZoneInfo::infer_zone_variant, FnInStruct)]
#[diplomat::rust_link(icu::time::zone::TimeZoneVariant, Enum, compact)]
pub fn infer_zone_variant(
&mut self,
offset_calculator: &UtcOffsetCalculator,
) -> Option<()> {
let info = self
.time_zone_id
.with_offset(self.offset)
.at_time(self.local_time?)
.infer_zone_variant(&offset_calculator.0);
self.time_zone_id = info.time_zone_id();
self.zone_variant = Some(info.zone_variant());
Some(())
}
#[diplomat::rust_link(icu::time::TimeZoneInfo::zone_variant, FnInStruct)]
pub fn zone_variant(&self) -> Option<TimeZoneVariant> {
self.zone_variant.map(Into::into)
}
}
}
impl From<icu_time::zone::UtcOffset> for TimeZoneInfo {
fn from(other: icu_time::zone::UtcOffset) -> Self {
Self {
time_zone_id: icu_time::TimeZone::unknown(),
offset: Some(other),
zone_variant: None,
local_time: None,
}
}
}
impl From<icu_time::TimeZoneInfo<icu_time::zone::models::Base>> for TimeZoneInfo {
fn from(other: icu_time::TimeZoneInfo<icu_time::zone::models::Base>) -> Self {
Self {
time_zone_id: other.time_zone_id(),
offset: other.offset(),
zone_variant: None,
local_time: None,
}
}
}
impl From<icu_time::TimeZoneInfo<icu_time::zone::models::AtTime>> for TimeZoneInfo {
fn from(other: icu_time::TimeZoneInfo<icu_time::zone::models::AtTime>) -> Self {
Self {
time_zone_id: other.time_zone_id(),
offset: other.offset(),
zone_variant: None,
local_time: Some(other.local_time()),
}
}
}
impl From<icu_time::TimeZoneInfo<icu_time::zone::models::Full>> for TimeZoneInfo {
fn from(other: icu_time::TimeZoneInfo<icu_time::zone::models::Full>) -> Self {
Self {
time_zone_id: other.time_zone_id(),
offset: other.offset(),
zone_variant: Some(other.zone_variant()),
local_time: Some(other.local_time()),
}
}
}