// 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::IsoWeekOfYear; #[diplomat::bridge] #[diplomat::abi_rename = "icu4x_{0}_mv1"] pub mod ffi { use alloc::boxed::Box; use alloc::sync::Arc; use core::fmt::Write; #[cfg(feature = "unstable")] use diplomat_runtime::DiplomatOption; use icu_calendar::Iso; use crate::unstable::calendar::ffi::Calendar; #[cfg(feature = "unstable")] use crate::unstable::errors::ffi::CalendarDateFromFieldsError; use crate::unstable::errors::ffi::{CalendarError, Rfc9557ParseError}; use tinystr::TinyAsciiStr; #[diplomat::enum_convert(icu_calendar::types::Weekday)] #[diplomat::rust_link(icu::calendar::types::Weekday, Enum)] #[non_exhaustive] pub enum Weekday { Monday = 1, Tuesday, Wednesday, Thursday, Friday, Saturday, Sunday, } #[diplomat::opaque] #[diplomat::transparent_convert] /// An ICU4X Date object capable of containing a ISO-8601 date #[diplomat::rust_link(icu::calendar::Date, Struct)] pub struct IsoDate(pub icu_calendar::Date); impl IsoDate { /// Creates a new [`IsoDate`] from the specified date. #[diplomat::rust_link(icu::calendar::Date::try_new_iso, FnInStruct)] #[diplomat::attr(supports = fallible_constructors, constructor)] pub fn create(year: i32, month: u8, day: u8) -> Result, CalendarError> { Ok(Box::new(IsoDate(icu_calendar::Date::try_new_iso( year, month, day, )?))) } /// Creates a new [`IsoDate`] from the given Rata Die #[diplomat::rust_link(icu::calendar::Date::from_rata_die, FnInStruct)] #[diplomat::attr(all(supports = named_constructors), named_constructor)] #[diplomat::demo(default_constructor)] #[diplomat::attr(demo_gen, disable)] // covered by Date pub fn from_rata_die(rd: i64) -> Box { Box::new(IsoDate(icu_calendar::Date::from_rata_die( icu_calendar::types::RataDie::new(rd), Iso, ))) } /// Creates a new [`IsoDate`] from an IXDTF string. #[diplomat::rust_link(icu::calendar::Date::try_from_str, FnInStruct)] #[diplomat::rust_link(icu::calendar::Date::try_from_utf8, FnInStruct, hidden)] #[diplomat::rust_link(icu::calendar::Date::from_str, FnInStruct, hidden)] #[diplomat::attr(all(supports = fallible_constructors, supports = named_constructors), named_constructor)] #[diplomat::attr(demo_gen, disable)] // covered by Date pub fn from_string(v: &DiplomatStr) -> Result, Rfc9557ParseError> { Ok(Box::new(IsoDate(icu_calendar::Date::try_from_utf8( v, Iso, )?))) } /// Convert this date to one in a different calendar #[diplomat::rust_link(icu::calendar::Date::to_calendar, FnInStruct)] #[diplomat::attr(demo_gen, disable)] // covered by Date pub fn to_calendar(&self, calendar: &Calendar) -> Box { Box::new(Date(self.0.to_calendar(calendar.0.clone()))) } #[diplomat::rust_link(icu::calendar::Date::to_any, FnInStruct)] #[diplomat::attr(demo_gen, disable)] // covered by Date pub fn to_any(&self) -> Box { Box::new(Date(self.0.to_any().into_atomic_ref_counted())) } /// Returns this date's Rata Die #[diplomat::rust_link(icu::calendar::Date::to_rata_die, FnInStruct)] #[diplomat::attr(auto, getter = "rata_die")] #[diplomat::attr(demo_gen, disable)] // covered by Date pub fn to_rata_die(&self) -> i64 { self.0.to_rata_die().to_i64_date() } /// Returns the 1-indexed day in the year for this date #[diplomat::rust_link(icu::calendar::Date::day_of_year, FnInStruct)] #[diplomat::attr(auto, getter)] #[diplomat::attr(demo_gen, disable)] // covered by Date pub fn day_of_year(&self) -> u16 { self.0.day_of_year().0 } /// Returns the 1-indexed day in the month for this date #[diplomat::rust_link(icu::calendar::Date::day_of_month, FnInStruct)] #[diplomat::attr(auto, getter)] #[diplomat::attr(demo_gen, disable)] // covered by Date pub fn day_of_month(&self) -> u8 { self.0.day_of_month().0 } /// Returns the day in the week for this day #[diplomat::rust_link(icu::calendar::Date::day_of_week, FnInStruct)] #[diplomat::attr(auto, getter)] #[diplomat::attr(demo_gen, disable)] // covered by Date pub fn day_of_week(&self) -> Weekday { self.0.day_of_week().into() } /// Returns the week number in this year, using week data #[diplomat::rust_link(icu::calendar::Date::week_of_year, FnInStruct)] #[cfg(feature = "calendar")] #[diplomat::attr(demo_gen, disable)] // covered by Date pub fn week_of_year(&self) -> IsoWeekOfYear { self.0.week_of_year().into() } /// Returns 1-indexed number of the month of this date in its year #[diplomat::rust_link(icu::calendar::types::MonthInfo::ordinal, StructField)] #[diplomat::rust_link(icu::calendar::Date::month, FnInStruct, compact)] #[diplomat::attr(auto, getter)] #[diplomat::attr(demo_gen, disable)] // covered by Date pub fn month(&self) -> u8 { self.0.month().ordinal } /// Returns the year number in the current era for this date /// /// For calendars without an era, returns the extended year #[diplomat::rust_link(icu::calendar::Date::year, FnInStruct)] #[diplomat::attr(auto, getter)] #[diplomat::attr(demo_gen, disable)] // covered by Date pub fn year(&self) -> i32 { self.0.extended_year() } /// Returns if the year is a leap year for this date #[diplomat::rust_link(icu::calendar::Date::is_in_leap_year, FnInStruct)] #[diplomat::attr(auto, getter)] #[diplomat::attr(demo_gen, disable)] // covered by Date pub fn is_in_leap_year(&self) -> bool { self.0.is_in_leap_year() } /// Returns the number of months in the year represented by this date #[diplomat::rust_link(icu::calendar::Date::months_in_year, FnInStruct)] #[diplomat::attr(auto, getter)] #[diplomat::attr(demo_gen, disable)] // covered by Date pub fn months_in_year(&self) -> u8 { self.0.months_in_year() } /// Returns the number of days in the month represented by this date #[diplomat::rust_link(icu::calendar::Date::days_in_month, FnInStruct)] #[diplomat::attr(auto, getter)] #[diplomat::attr(demo_gen, disable)] // covered by Date pub fn days_in_month(&self) -> u8 { self.0.days_in_month() } /// Returns the number of days in the year represented by this date #[diplomat::rust_link(icu::calendar::Date::days_in_year, FnInStruct)] #[diplomat::attr(auto, getter)] #[diplomat::attr(demo_gen, disable)] // covered by Date pub fn days_in_year(&self) -> u16 { self.0.days_in_year() } } /// 🚧 This API is experimental and may experience breaking changes outside major releases. #[diplomat::rust_link(icu::calendar::options::DateFromFieldsOptions, Struct)] #[cfg(feature = "unstable")] pub struct DateFromFieldsOptions { pub overflow: DiplomatOption, pub missing_fields_strategy: DiplomatOption, } /// 🚧 This API is experimental and may experience breaking changes outside major releases. #[diplomat::rust_link(icu::calendar::types::DateFields, Struct)] #[cfg(feature = "unstable")] pub struct DateFields<'a> { pub era: DiplomatOption<&'a DiplomatStr>, pub era_year: DiplomatOption, pub extended_year: DiplomatOption, pub month_code: DiplomatOption<&'a DiplomatStr>, pub ordinal_month: DiplomatOption, pub day: DiplomatOption, } /// 🚧 This API is experimental and may experience breaking changes outside major releases. #[diplomat::enum_convert(icu_calendar::options::Overflow, needs_wildcard)] #[diplomat::rust_link(icu::calendar::options::Overflow, Enum)] #[non_exhaustive] #[cfg(feature = "unstable")] pub enum DateOverflow { Constrain, Reject, } /// 🚧 This API is experimental and may experience breaking changes outside major releases. #[diplomat::enum_convert(icu_calendar::options::MissingFieldsStrategy, needs_wildcard)] #[diplomat::rust_link(icu::calendar::options::MissingFieldsStrategy, Enum)] #[non_exhaustive] #[cfg(feature = "unstable")] pub enum DateMissingFieldsStrategy { Reject, Ecma, } #[diplomat::opaque] #[diplomat::transparent_convert] /// An ICU4X Date object capable of containing a date for any calendar. #[diplomat::rust_link(icu::calendar::Date, Struct)] pub struct Date(pub icu_calendar::Date>); impl Date { /// Creates a new [`Date`] representing the ISO date /// given but in a given calendar #[diplomat::rust_link(icu::calendar::Date::new_from_iso, FnInStruct)] #[diplomat::attr(all(supports = fallible_constructors, supports = named_constructors), named_constructor)] #[diplomat::demo(default_constructor)] pub fn from_iso_in_calendar( iso_year: i32, iso_month: u8, iso_day: u8, calendar: &Calendar, ) -> Result, CalendarError> { let cal = calendar.0.clone(); Ok(Box::new(Date( icu_calendar::Date::try_new_iso(iso_year, iso_month, iso_day)?.to_calendar(cal), ))) } /// Creates a new [`Date`] from the given fields, which are interpreted in the given calendar system. /// /// 🚧 This API is experimental and may experience breaking changes outside major releases. #[diplomat::rust_link(icu::calendar::Date::try_from_fields, FnInStruct)] #[diplomat::attr(all(supports = fallible_constructors, supports = named_constructors), named_constructor)] #[cfg(feature = "unstable")] pub fn from_fields_in_calendar( fields: DateFields, options: DateFromFieldsOptions, calendar: &Calendar, ) -> Result, CalendarDateFromFieldsError> { let cal = calendar.0.clone(); Ok(Box::new(Date(icu_calendar::Date::try_from_fields( fields.into(), options.into(), cal, )?))) } /// Creates a new [`Date`] from the given codes, which are interpreted in the given calendar system /// /// An empty era code will treat the year as an extended year #[diplomat::rust_link(icu::calendar::Date::try_new_from_codes, FnInStruct)] #[diplomat::attr(all(supports = fallible_constructors, supports = named_constructors), named_constructor)] pub fn from_codes_in_calendar( era_code: &DiplomatStr, year: i32, month_code: &DiplomatStr, day: u8, calendar: &Calendar, ) -> Result, CalendarError> { let era = if !era_code.is_empty() { Some(core::str::from_utf8(era_code).map_err(|_| CalendarError::UnknownEra)?) } else { None }; let month = icu_calendar::types::MonthCode( TinyAsciiStr::try_from_utf8(month_code) .map_err(|_| CalendarError::UnknownMonthCode)?, ); let cal = calendar.0.clone(); Ok(Box::new(Date(icu_calendar::Date::try_new_from_codes( era, year, month, day, cal, )?))) } /// Creates a new [`Date`] from the given Rata Die #[diplomat::rust_link(icu::calendar::Date::from_rata_die, FnInStruct)] #[diplomat::attr(all(supports = named_constructors), named_constructor)] #[diplomat::demo(default_constructor)] pub fn from_rata_die(rd: i64, calendar: &Calendar) -> Result, CalendarError> { let cal = calendar.0.clone(); Ok(Box::new(Date(icu_calendar::Date::from_rata_die( icu_calendar::types::RataDie::new(rd), cal, )))) } /// Creates a new [`Date`] from an IXDTF string. #[diplomat::rust_link(icu::calendar::Date::try_from_str, FnInStruct)] #[diplomat::rust_link(icu::calendar::Date::try_from_utf8, FnInStruct, hidden)] #[diplomat::rust_link(icu::calendar::Date::from_str, FnInStruct, hidden)] #[diplomat::attr(all(supports = fallible_constructors, supports = named_constructors), named_constructor)] pub fn from_string( v: &DiplomatStr, calendar: &Calendar, ) -> Result, Rfc9557ParseError> { Ok(Box::new(Date(icu_calendar::Date::try_from_utf8( v, calendar.0.clone(), )?))) } /// Convert this date to one in a different calendar #[diplomat::rust_link(icu::calendar::Date::to_calendar, FnInStruct)] #[diplomat::rust_link(icu::calendar::Date::convert_any, FnInStruct, hidden)] pub fn to_calendar(&self, calendar: &Calendar) -> Box { Box::new(Date(self.0.to_calendar(calendar.0.clone()))) } /// Converts this date to ISO #[diplomat::rust_link(icu::calendar::Date::to_iso, FnInStruct)] pub fn to_iso(&self) -> Box { Box::new(IsoDate(self.0.to_iso())) } /// Returns this date's Rata Die #[diplomat::rust_link(icu::calendar::Date::to_rata_die, FnInStruct)] #[diplomat::attr(auto, getter = "rata_die")] pub fn to_rata_die(&self) -> i64 { self.0.to_rata_die().to_i64_date() } /// Returns the 1-indexed day in the year for this date #[diplomat::rust_link(icu::calendar::Date::day_of_year, FnInStruct)] #[diplomat::attr(auto, getter)] pub fn day_of_year(&self) -> u16 { self.0.day_of_year().0 } /// Returns the 1-indexed day in the month for this date #[diplomat::rust_link(icu::calendar::Date::day_of_month, FnInStruct)] #[diplomat::attr(auto, getter)] pub fn day_of_month(&self) -> u8 { self.0.day_of_month().0 } /// Returns the day in the week for this day #[diplomat::rust_link(icu::calendar::Date::day_of_week, FnInStruct)] #[diplomat::attr(auto, getter)] pub fn day_of_week(&self) -> Weekday { self.0.day_of_week().into() } /// Returns 1-indexed number of the month of this date in its year /// /// Note that for lunar calendars this may not lead to the same month /// having the same ordinal month across years; use month_code if you care /// about month identity. #[diplomat::rust_link(icu::calendar::Date::month, FnInStruct)] #[diplomat::rust_link(icu::calendar::types::MonthInfo::ordinal, StructField)] #[diplomat::attr(auto, getter)] pub fn ordinal_month(&self) -> u8 { self.0.month().ordinal } /// Returns the month code for this date. Typically something /// like "M01", "M02", but can be more complicated for lunar calendars. #[diplomat::rust_link(icu::calendar::types::MonthInfo::standard_code, StructField)] #[diplomat::rust_link(icu::calendar::Date::month, FnInStruct, compact)] #[diplomat::rust_link(icu::calendar::types::MonthInfo, Struct, hidden)] #[diplomat::rust_link( icu::calendar::types::MonthInfo::formatting_code, StructField, hidden )] #[diplomat::rust_link(icu::calendar::types::MonthInfo, Struct, hidden)] #[diplomat::attr(auto, getter)] pub fn month_code(&self, write: &mut diplomat_runtime::DiplomatWrite) { let code = self.0.month().standard_code; let _infallible = write.write_str(&code.0); } /// Returns the month number of this month. #[diplomat::rust_link(icu::calendar::types::MonthInfo::month_number, FnInStruct)] #[diplomat::attr(auto, getter)] pub fn month_number(&self) -> u8 { self.0.month().month_number() } /// Returns whether the month is a leap month. #[diplomat::rust_link(icu::calendar::types::MonthInfo::is_leap, FnInStruct)] #[diplomat::attr(auto, getter)] pub fn month_is_leap(&self) -> bool { self.0.month().is_leap() } /// Returns the year number in the current era for this date /// /// For calendars without an era, returns the related ISO year. #[diplomat::rust_link(icu::calendar::types::YearInfo::era_year_or_related_iso, FnInEnum)] #[diplomat::rust_link(icu::calendar::types::EraYear::year, StructField, compact)] #[diplomat::rust_link(icu::calendar::types::CyclicYear::related_iso, StructField, compact)] #[diplomat::rust_link(icu::calendar::Date::year, FnInStruct, compact)] #[diplomat::rust_link(icu::calendar::Date::era_year, FnInStruct, hidden)] #[diplomat::rust_link(icu::calendar::Date::cyclic_year, FnInStruct, hidden)] #[diplomat::rust_link(icu::calendar::types::YearInfo, Enum, hidden)] #[diplomat::rust_link(icu::calendar::types::YearInfo::era, FnInEnum, hidden)] #[diplomat::rust_link(icu::calendar::types::YearInfo::cyclic, FnInEnum, hidden)] #[diplomat::rust_link(icu::calendar::types::EraYear, Struct, hidden)] #[diplomat::rust_link(icu::calendar::types::CyclicYear, Struct, hidden)] #[diplomat::attr(auto, getter)] pub fn era_year_or_related_iso(&self) -> i32 { self.0.year().era_year_or_related_iso() } /// Returns the extended year, which can be used for /// /// This year number can be used when you need a simple numeric representation /// of the year, and can be meaningfully compared with extended years from other /// eras or used in arithmetic. #[diplomat::rust_link(icu::calendar::Date::extended_year, FnInStruct)] #[diplomat::rust_link(icu::calendar::types::YearInfo::extended_year, FnInEnum, hidden)] #[diplomat::attr(auto, getter)] pub fn extended_year(&self) -> i32 { self.0.extended_year() } /// Returns the era for this date, or an empty string #[diplomat::rust_link(icu::calendar::types::EraYear::era, StructField)] #[diplomat::rust_link(icu::calendar::Date::year, FnInStruct, compact)] #[diplomat::attr(auto, getter)] pub fn era(&self, write: &mut diplomat_runtime::DiplomatWrite) { if let Some(era) = self.0.year().era() { let _infallible = write.write_str(&era.era); } } /// Returns the number of months in the year represented by this date #[diplomat::rust_link(icu::calendar::Date::months_in_year, FnInStruct)] #[diplomat::attr(auto, getter)] pub fn months_in_year(&self) -> u8 { self.0.months_in_year() } /// Returns the number of days in the month represented by this date #[diplomat::rust_link(icu::calendar::Date::days_in_month, FnInStruct)] #[diplomat::attr(auto, getter)] pub fn days_in_month(&self) -> u8 { self.0.days_in_month() } /// Returns the number of days in the year represented by this date #[diplomat::rust_link(icu::calendar::Date::days_in_year, FnInStruct)] #[diplomat::attr(auto, getter)] pub fn days_in_year(&self) -> u16 { self.0.days_in_year() } /// Returns the [`Calendar`] object backing this date #[diplomat::rust_link(icu::calendar::Date::calendar, FnInStruct)] #[diplomat::rust_link(icu::calendar::Date::calendar_wrapper, FnInStruct, hidden)] #[diplomat::attr(auto, getter)] pub fn calendar(&self) -> Box { Box::new(Calendar(self.0.calendar_wrapper().clone())) } } #[diplomat::rust_link(icu::calendar::types::IsoWeekOfYear, Struct)] pub struct IsoWeekOfYear { pub week_number: u8, pub iso_year: i32, } } impl From for IsoWeekOfYear { fn from( icu_calendar::types::IsoWeekOfYear { week_number, iso_year, }: icu_calendar::types::IsoWeekOfYear, ) -> Self { Self { week_number, iso_year, } } } #[cfg(feature = "unstable")] impl From for icu_calendar::options::DateFromFieldsOptions { fn from(other: ffi::DateFromFieldsOptions) -> Self { let mut options = Self::default(); options.overflow = other.overflow.into_converted_option(); options.missing_fields_strategy = other.missing_fields_strategy.into_converted_option(); options } } #[cfg(feature = "unstable")] impl<'a> From> for icu_calendar::types::DateFields<'a> { fn from(other: ffi::DateFields<'a>) -> Self { let mut fields = Self::default(); fields.era = other.era.into_option(); fields.era_year = other.era_year.into(); fields.extended_year = other.extended_year.into(); fields.month_code = other.month_code.into_option(); fields.ordinal_month = other.ordinal_month.into(); fields.day = other.day.into(); fields } }