diff options
Diffstat (limited to 'intl/icu_capi/src/timezone.rs')
-rw-r--r-- | intl/icu_capi/src/timezone.rs | 328 |
1 files changed, 328 insertions, 0 deletions
diff --git a/intl/icu_capi/src/timezone.rs b/intl/icu_capi/src/timezone.rs new file mode 100644 index 0000000000..4c8b2659b7 --- /dev/null +++ b/intl/icu_capi/src/timezone.rs @@ -0,0 +1,328 @@ +// 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 icu_timezone::CustomTimeZone; + +#[diplomat::bridge] +pub mod ffi { + use crate::errors::ffi::ICU4XError; + use alloc::boxed::Box; + use core::fmt::Write; + use core::str::{self}; + use icu_timezone::CustomTimeZone; + use icu_timezone::GmtOffset; + use icu_timezone::ZoneVariant; + + #[diplomat::opaque] + #[diplomat::rust_link(icu::timezone::CustomTimeZone, Struct)] + pub struct ICU4XCustomTimeZone(pub CustomTimeZone); + + impl ICU4XCustomTimeZone { + /// Creates a time zone from an offset string. + #[diplomat::rust_link(icu::timezone::CustomTimeZone::from_str, FnInStruct)] + #[diplomat::rust_link(icu::timezone::CustomTimeZone::try_from_bytes, FnInStruct, hidden)] + #[diplomat::rust_link(icu::timezone::GmtOffset::from_str, FnInStruct, hidden)] + #[diplomat::rust_link(icu::timezone::GmtOffset::try_from_bytes, FnInStruct, hidden)] + pub fn create_from_string(s: &str) -> Result<Box<ICU4XCustomTimeZone>, ICU4XError> { + let bytes = s.as_bytes(); + Ok(Box::new(ICU4XCustomTimeZone::from( + CustomTimeZone::try_from_bytes(bytes)?, + ))) + } + + /// Creates a time zone with no information. + #[diplomat::rust_link(icu::timezone::CustomTimeZone::new_empty, FnInStruct)] + pub fn create_empty() -> Box<ICU4XCustomTimeZone> { + Box::new(CustomTimeZone::new_empty().into()) + } + + /// Creates a time zone for UTC. + #[diplomat::rust_link(icu::timezone::CustomTimeZone::utc, FnInStruct)] + #[diplomat::rust_link(icu::timezone::GmtOffset::utc, FnInStruct, hidden)] + pub fn create_utc() -> Box<ICU4XCustomTimeZone> { + Box::new(CustomTimeZone::utc().into()) + } + + /// Sets the `gmt_offset` field from offset seconds. + /// + /// Errors if the offset seconds are out of range. + #[diplomat::rust_link(icu::timezone::GmtOffset::try_from_offset_seconds, FnInStruct)] + #[diplomat::rust_link(icu::timezone::GmtOffset, Struct, compact)] + #[diplomat::rust_link( + icu::timezone::GmtOffset::from_offset_seconds_unchecked, + FnInStruct, + hidden + )] + #[diplomat::rust_link(icu::timezone::CustomTimeZone::new_with_offset, FnInStruct, hidden)] + pub fn try_set_gmt_offset_seconds( + &mut self, + offset_seconds: i32, + ) -> Result<(), ICU4XError> { + self.0.gmt_offset = Some(GmtOffset::try_from_offset_seconds(offset_seconds)?); + Ok(()) + } + + /// Clears the `gmt_offset` field. + #[diplomat::rust_link(icu::timezone::GmtOffset::offset_seconds, FnInStruct)] + #[diplomat::rust_link(icu::timezone::GmtOffset, Struct, compact)] + pub fn clear_gmt_offset(&mut self) { + self.0.gmt_offset.take(); + } + + /// Returns the value of the `gmt_offset` field as offset seconds. + /// + /// Errors if the `gmt_offset` field is empty. + #[diplomat::rust_link(icu::timezone::GmtOffset::offset_seconds, FnInStruct)] + #[diplomat::rust_link(icu::timezone::GmtOffset, Struct, compact)] + pub fn gmt_offset_seconds(&self) -> Result<i32, ICU4XError> { + self.0 + .gmt_offset + .ok_or(ICU4XError::TimeZoneMissingInputError) + .map(GmtOffset::offset_seconds) + } + + /// Returns whether the `gmt_offset` field is positive. + /// + /// Errors if the `gmt_offset` field is empty. + #[diplomat::rust_link(icu::timezone::GmtOffset::is_positive, FnInStruct)] + pub fn is_gmt_offset_positive(&self) -> Result<bool, ICU4XError> { + self.0 + .gmt_offset + .ok_or(ICU4XError::TimeZoneMissingInputError) + .map(GmtOffset::is_positive) + } + + /// Returns whether the `gmt_offset` field is zero. + /// + /// Errors if the `gmt_offset` field is empty (which is not the same as zero). + #[diplomat::rust_link(icu::timezone::GmtOffset::is_zero, FnInStruct)] + pub fn is_gmt_offset_zero(&self) -> Result<bool, ICU4XError> { + self.0 + .gmt_offset + .ok_or(ICU4XError::TimeZoneMissingInputError) + .map(GmtOffset::is_zero) + } + + /// Returns whether the `gmt_offset` field has nonzero minutes. + /// + /// Errors if the `gmt_offset` field is empty. + #[diplomat::rust_link(icu::timezone::GmtOffset::has_minutes, FnInStruct)] + pub fn gmt_offset_has_minutes(&self) -> Result<bool, ICU4XError> { + self.0 + .gmt_offset + .ok_or(ICU4XError::TimeZoneMissingInputError) + .map(GmtOffset::has_minutes) + } + + /// Returns whether the `gmt_offset` field has nonzero seconds. + /// + /// Errors if the `gmt_offset` field is empty. + #[diplomat::rust_link(icu::timezone::GmtOffset::has_seconds, FnInStruct)] + pub fn gmt_offset_has_seconds(&self) -> Result<bool, ICU4XError> { + self.0 + .gmt_offset + .ok_or(ICU4XError::TimeZoneMissingInputError) + .map(GmtOffset::has_seconds) + } + + /// Sets the `time_zone_id` field from a BCP-47 string. + /// + /// Errors if the string is not a valid BCP-47 time zone ID. + #[diplomat::rust_link(icu::timezone::CustomTimeZone::time_zone_id, StructField)] + #[diplomat::rust_link(icu::timezone::TimeZoneBcp47Id, Struct, compact)] + #[diplomat::rust_link(icu::timezone::TimeZoneBcp47Id::from_str, FnInStruct, hidden)] + pub fn try_set_time_zone_id(&mut self, id: &str) -> Result<(), ICU4XError> { + self.0.time_zone_id = Some(id.parse()?); + Ok(()) + } + + /// Sets the `time_zone_id` field from an IANA string by looking up + /// the corresponding BCP-47 string. + /// + /// Errors if the string is not a valid BCP-47 time zone ID. + #[diplomat::rust_link(icu::timezone::IanaToBcp47MapperBorrowed::get, FnInStruct)] + pub fn try_set_iana_time_zone_id( + &mut self, + mapper: &crate::iana_bcp47_mapper::ffi::ICU4XIanaToBcp47Mapper, + id: &str, + ) -> Result<(), ICU4XError> { + match mapper.0.as_borrowed().get(id) { + Some(id) => { + self.0.time_zone_id = Some(id); + Ok(()) + } + None => Err(ICU4XError::TimeZoneInvalidIdError), + } + } + + /// Clears the `time_zone_id` field. + #[diplomat::rust_link(icu::timezone::CustomTimeZone::time_zone_id, StructField)] + #[diplomat::rust_link(icu::timezone::TimeZoneBcp47Id, Struct, compact)] + pub fn clear_time_zone_id(&mut self) { + self.0.time_zone_id.take(); + } + + /// Writes the value of the `time_zone_id` field as a string. + /// + /// Errors if the `time_zone_id` field is empty. + #[diplomat::rust_link(icu::timezone::CustomTimeZone::time_zone_id, StructField)] + #[diplomat::rust_link(icu::timezone::TimeZoneBcp47Id, Struct, compact)] + pub fn time_zone_id( + &self, + write: &mut diplomat_runtime::DiplomatWriteable, + ) -> Result<(), ICU4XError> { + write.write_str( + self.0 + .time_zone_id + .ok_or(ICU4XError::TimeZoneMissingInputError)? + .0 + .as_str(), + )?; + Ok(()) + } + + /// Sets the `metazone_id` field from a string. + /// + /// Errors if the string is not a valid BCP-47 metazone ID. + #[diplomat::rust_link(icu::timezone::CustomTimeZone::metazone_id, StructField)] + #[diplomat::rust_link(icu::timezone::MetazoneId, Struct, compact)] + #[diplomat::rust_link(icu::timezone::MetazoneId::from_str, FnInStruct, hidden)] + pub fn try_set_metazone_id(&mut self, id: &str) -> Result<(), ICU4XError> { + self.0.metazone_id = Some(id.parse()?); + Ok(()) + } + + /// Clears the `metazone_id` field. + #[diplomat::rust_link(icu::timezone::CustomTimeZone::metazone_id, StructField)] + #[diplomat::rust_link(icu::timezone::MetazoneId, Struct, compact)] + pub fn clear_metazone_id(&mut self) { + self.0.metazone_id.take(); + } + + /// Writes the value of the `metazone_id` field as a string. + /// + /// Errors if the `metazone_id` field is empty. + #[diplomat::rust_link(icu::timezone::CustomTimeZone::metazone_id, StructField)] + #[diplomat::rust_link(icu::timezone::MetazoneId, Struct, compact)] + pub fn metazone_id( + &self, + write: &mut diplomat_runtime::DiplomatWriteable, + ) -> Result<(), ICU4XError> { + write.write_str( + self.0 + .metazone_id + .ok_or(ICU4XError::TimeZoneMissingInputError)? + .0 + .as_str(), + )?; + Ok(()) + } + + /// Sets the `zone_variant` field from a string. + /// + /// Errors if the string is not a valid zone variant. + #[diplomat::rust_link(icu::timezone::CustomTimeZone::zone_variant, StructField)] + #[diplomat::rust_link(icu::timezone::ZoneVariant, Struct, compact)] + #[diplomat::rust_link(icu::timezone::ZoneVariant::from_str, FnInStruct, hidden)] + pub fn try_set_zone_variant(&mut self, id: &str) -> Result<(), ICU4XError> { + self.0.zone_variant = Some(id.parse()?); + Ok(()) + } + + /// Clears the `zone_variant` field. + #[diplomat::rust_link(icu::timezone::CustomTimeZone::zone_variant, StructField)] + #[diplomat::rust_link(icu::timezone::ZoneVariant, Struct, compact)] + pub fn clear_zone_variant(&mut self) { + self.0.zone_variant.take(); + } + + /// Writes the value of the `zone_variant` field as a string. + /// + /// Errors if the `zone_variant` field is empty. + #[diplomat::rust_link(icu::timezone::CustomTimeZone::zone_variant, StructField)] + #[diplomat::rust_link(icu::timezone::ZoneVariant, Struct, compact)] + pub fn zone_variant( + &self, + write: &mut diplomat_runtime::DiplomatWriteable, + ) -> Result<(), ICU4XError> { + write.write_str( + self.0 + .zone_variant + .ok_or(ICU4XError::TimeZoneMissingInputError)? + .0 + .as_str(), + )?; + Ok(()) + } + + /// Sets the `zone_variant` field to standard time. + #[diplomat::rust_link(icu::timezone::ZoneVariant::standard, FnInStruct)] + #[diplomat::rust_link(icu::timezone::CustomTimeZone::zone_variant, StructField, compact)] + pub fn set_standard_time(&mut self) { + self.0.zone_variant = Some(ZoneVariant::standard()) + } + + /// Sets the `zone_variant` field to daylight time. + #[diplomat::rust_link(icu::timezone::ZoneVariant::daylight, FnInStruct)] + #[diplomat::rust_link(icu::timezone::CustomTimeZone::zone_variant, StructField, compact)] + pub fn set_daylight_time(&mut self) { + self.0.zone_variant = Some(ZoneVariant::daylight()) + } + + /// Returns whether the `zone_variant` field is standard time. + /// + /// Errors if the `zone_variant` field is empty. + #[diplomat::rust_link(icu::timezone::ZoneVariant::standard, FnInStruct)] + #[diplomat::rust_link(icu::timezone::CustomTimeZone::zone_variant, StructField, compact)] + pub fn is_standard_time(&self) -> Result<bool, ICU4XError> { + Ok(self + .0 + .zone_variant + .ok_or(ICU4XError::TimeZoneMissingInputError)? + == ZoneVariant::standard()) + } + + /// Returns whether the `zone_variant` field is daylight time. + /// + /// Errors if the `zone_variant` field is empty. + #[diplomat::rust_link(icu::timezone::ZoneVariant::daylight, FnInStruct)] + #[diplomat::rust_link(icu::timezone::CustomTimeZone::zone_variant, StructField, compact)] + pub fn is_daylight_time(&self) -> Result<bool, ICU4XError> { + Ok(self + .0 + .zone_variant + .ok_or(ICU4XError::TimeZoneMissingInputError)? + == ZoneVariant::daylight()) + } + + /// Sets the metazone based on the time zone and the local timestamp. + #[diplomat::rust_link(icu::timezone::CustomTimeZone::maybe_calculate_metazone, FnInStruct)] + #[diplomat::rust_link( + icu::timezone::MetazoneCalculator::compute_metazone_from_time_zone, + FnInStruct, + compact + )] + #[cfg(feature = "icu_timezone")] + pub fn maybe_calculate_metazone( + &mut self, + metazone_calculator: &crate::metazone_calculator::ffi::ICU4XMetazoneCalculator, + local_datetime: &crate::datetime::ffi::ICU4XIsoDateTime, + ) { + self.0 + .maybe_calculate_metazone(&metazone_calculator.0, &local_datetime.0); + } + } +} + +impl From<CustomTimeZone> for ffi::ICU4XCustomTimeZone { + fn from(other: CustomTimeZone) -> Self { + Self(other) + } +} + +impl From<ffi::ICU4XCustomTimeZone> for CustomTimeZone { + fn from(other: ffi::ICU4XCustomTimeZone) -> Self { + other.0 + } +} |