1 // This file is part of ICU4X. For terms of use, please see the file 2 // called LICENSE at the top level of the ICU4X source tree 3 // (online at: https://github.com/unicode-org/icu4x/blob/main/LICENSE ). 4 5 #[diplomat::bridge] 6 #[diplomat::abi_rename = "icu4x_{0}_mv1"] 7 #[diplomat::attr(auto, namespace = "icu4x")] 8 pub mod ffi { 9 use alloc::boxed::Box; 10 use alloc::sync::Arc; 11 use core::fmt::Write; 12 use icu_calendar::Iso; 13 14 use crate::calendar::ffi::Calendar; 15 use crate::errors::ffi::{CalendarError, CalendarParseError}; 16 17 use tinystr::TinyAsciiStr; 18 19 #[cfg(feature = "calendar")] 20 use crate::week::ffi::WeekCalculator; 21 22 #[diplomat::enum_convert(icu_calendar::types::Weekday)] 23 pub enum Weekday { 24 Monday = 1, 25 Tuesday, 26 Wednesday, 27 Thursday, 28 Friday, 29 Saturday, 30 Sunday, 31 } 32 #[diplomat::opaque] 33 #[diplomat::transparent_convert] 34 /// An ICU4X Date object capable of containing a ISO-8601 date 35 #[diplomat::rust_link(icu::calendar::Date, Struct)] 36 pub struct IsoDate(pub icu_calendar::Date<icu_calendar::Iso>); 37 38 impl IsoDate { 39 /// Creates a new [`IsoDate`] from the specified date and time. 40 #[diplomat::rust_link(icu::calendar::Date::try_new_iso, FnInStruct)] 41 #[diplomat::attr(supports = fallible_constructors, constructor)] create(year: i32, month: u8, day: u8) -> Result<Box<IsoDate>, CalendarError>42 pub fn create(year: i32, month: u8, day: u8) -> Result<Box<IsoDate>, CalendarError> { 43 Ok(Box::new(IsoDate(icu_calendar::Date::try_new_iso( 44 year, month, day, 45 )?))) 46 } 47 48 /// Creates a new [`IsoDate`] from an IXDTF string. 49 #[diplomat::rust_link(icu::calendar::Date::try_iso_from_str, FnInStruct)] 50 #[diplomat::rust_link(icu::calendar::Date::try_iso_from_utf8, FnInStruct, hidden)] 51 #[diplomat::rust_link(icu::calendar::Date::from_str, FnInStruct, hidden)] 52 #[diplomat::attr(all(supports = fallible_constructors, supports = named_constructors), named_constructor)] from_string(v: &DiplomatStr) -> Result<Box<IsoDate>, CalendarParseError>53 pub fn from_string(v: &DiplomatStr) -> Result<Box<IsoDate>, CalendarParseError> { 54 Ok(Box::new(IsoDate(icu_calendar::Date::try_from_utf8( 55 v, Iso, 56 )?))) 57 } 58 59 /// Convert this date to one in a different calendar 60 #[diplomat::rust_link(icu::calendar::Date::to_calendar, FnInStruct)] to_calendar(&self, calendar: &Calendar) -> Box<Date>61 pub fn to_calendar(&self, calendar: &Calendar) -> Box<Date> { 62 Box::new(Date(self.0.to_calendar(calendar.0.clone()))) 63 } 64 65 #[diplomat::rust_link(icu::calendar::Date::to_any, FnInStruct)] to_any(&self) -> Box<Date>66 pub fn to_any(&self) -> Box<Date> { 67 Box::new(Date(self.0.to_any().wrap_calendar_in_arc())) 68 } 69 70 /// Returns the 1-indexed day in the year for this date 71 #[diplomat::rust_link(icu::calendar::Date::day_of_year_info, FnInStruct)] 72 #[diplomat::attr(auto, getter)] day_of_year(&self) -> u1673 pub fn day_of_year(&self) -> u16 { 74 self.0.day_of_year_info().day_of_year 75 } 76 77 /// Returns the 1-indexed day in the month for this date 78 #[diplomat::rust_link(icu::calendar::Date::day_of_month, FnInStruct)] 79 #[diplomat::attr(auto, getter)] day_of_month(&self) -> u880 pub fn day_of_month(&self) -> u8 { 81 self.0.day_of_month().0 82 } 83 84 /// Returns the day in the week for this day 85 #[diplomat::rust_link(icu::calendar::Date::day_of_week, FnInStruct)] 86 #[diplomat::attr(auto, getter)] day_of_week(&self) -> Weekday87 pub fn day_of_week(&self) -> Weekday { 88 self.0.day_of_week().into() 89 } 90 91 /// Returns the week number in this month, 1-indexed, based on what 92 /// is considered the first day of the week (often a locale preference). 93 /// 94 /// `first_weekday` can be obtained via `first_weekday()` on [`WeekCalculator`] 95 #[diplomat::rust_link(icu::calendar::Date::week_of_month, FnInStruct)] 96 #[diplomat::rust_link( 97 icu::calendar::week::WeekCalculator::week_of_month, 98 FnInStruct, 99 hidden 100 )] week_of_month(&self, first_weekday: Weekday) -> u8101 pub fn week_of_month(&self, first_weekday: Weekday) -> u8 { 102 self.0.week_of_month(first_weekday.into()).0 103 } 104 105 /// Returns the week number in this year, using week data 106 #[diplomat::rust_link(icu::calendar::Date::week_of_year, FnInStruct)] 107 #[diplomat::rust_link( 108 icu::calendar::week::WeekCalculator::week_of_year, 109 FnInStruct, 110 hidden 111 )] 112 #[cfg(feature = "calendar")] week_of_year(&self, calculator: &WeekCalculator) -> crate::week::ffi::WeekOf113 pub fn week_of_year(&self, calculator: &WeekCalculator) -> crate::week::ffi::WeekOf { 114 self.0.week_of_year(&calculator.0).into() 115 } 116 117 /// Returns 1-indexed number of the month of this date in its year 118 #[diplomat::rust_link(icu::calendar::types::MonthInfo::ordinal, StructField)] 119 #[diplomat::rust_link(icu::calendar::Date::month, FnInStruct, compact)] 120 #[diplomat::attr(auto, getter)] month(&self) -> u8121 pub fn month(&self) -> u8 { 122 self.0.month().ordinal 123 } 124 125 /// Returns the year number in the current era for this date 126 /// 127 /// For calendars without an era, returns the extended year 128 #[diplomat::rust_link(icu::calendar::Date::year, FnInStruct)] 129 #[diplomat::attr(auto, getter)] year(&self) -> i32130 pub fn year(&self) -> i32 { 131 self.0.year().extended_year 132 } 133 134 /// Returns if the year is a leap year for this date 135 #[diplomat::rust_link(icu::calendar::Date::is_in_leap_year, FnInStruct)] 136 #[diplomat::attr(auto, getter)] is_in_leap_year(&self) -> bool137 pub fn is_in_leap_year(&self) -> bool { 138 self.0.is_in_leap_year() 139 } 140 141 /// Returns the number of months in the year represented by this date 142 #[diplomat::rust_link(icu::calendar::Date::months_in_year, FnInStruct)] 143 #[diplomat::attr(auto, getter)] months_in_year(&self) -> u8144 pub fn months_in_year(&self) -> u8 { 145 self.0.months_in_year() 146 } 147 148 /// Returns the number of days in the month represented by this date 149 #[diplomat::rust_link(icu::calendar::Date::days_in_month, FnInStruct)] 150 #[diplomat::attr(auto, getter)] days_in_month(&self) -> u8151 pub fn days_in_month(&self) -> u8 { 152 self.0.days_in_month() 153 } 154 155 /// Returns the number of days in the year represented by this date 156 #[diplomat::rust_link(icu::calendar::Date::days_in_year, FnInStruct)] 157 #[diplomat::attr(auto, getter)] days_in_year(&self) -> u16158 pub fn days_in_year(&self) -> u16 { 159 self.0.days_in_year() 160 } 161 } 162 163 #[diplomat::opaque] 164 #[diplomat::transparent_convert] 165 /// An ICU4X Date object capable of containing a date and time for any calendar. 166 #[diplomat::rust_link(icu::calendar::Date, Struct)] 167 pub struct Date(pub icu_calendar::Date<Arc<icu_calendar::AnyCalendar>>); 168 169 impl Date { 170 /// Creates a new [`Date`] representing the ISO date and time 171 /// given but in a given calendar 172 #[diplomat::rust_link(icu::calendar::Date::new_from_iso, FnInStruct)] 173 #[diplomat::attr(all(supports = fallible_constructors, supports = named_constructors), named_constructor)] 174 #[diplomat::demo(default_constructor)] from_iso_in_calendar( year: i32, month: u8, day: u8, calendar: &Calendar, ) -> Result<Box<Date>, CalendarError>175 pub fn from_iso_in_calendar( 176 year: i32, 177 month: u8, 178 day: u8, 179 calendar: &Calendar, 180 ) -> Result<Box<Date>, CalendarError> { 181 let cal = calendar.0.clone(); 182 Ok(Box::new(Date( 183 icu_calendar::Date::try_new_iso(year, month, day)?.to_calendar(cal), 184 ))) 185 } 186 187 /// Creates a new [`Date`] from the given codes, which are interpreted in the given calendar system 188 /// 189 /// An empty era code will treat the year as an extended year 190 #[diplomat::rust_link(icu::calendar::Date::try_new_from_codes, FnInStruct)] 191 #[diplomat::attr(all(supports = fallible_constructors, supports = named_constructors), named_constructor)] from_codes_in_calendar( era_code: &DiplomatStr, year: i32, month_code: &DiplomatStr, day: u8, calendar: &Calendar, ) -> Result<Box<Date>, CalendarError>192 pub fn from_codes_in_calendar( 193 era_code: &DiplomatStr, 194 year: i32, 195 month_code: &DiplomatStr, 196 day: u8, 197 calendar: &Calendar, 198 ) -> Result<Box<Date>, CalendarError> { 199 let era = if era_code.is_empty() { 200 Some(icu_calendar::types::Era( 201 TinyAsciiStr::try_from_utf8(era_code).map_err(|_| CalendarError::UnknownEra)?, 202 )) 203 } else { 204 None 205 }; 206 let month = icu_calendar::types::MonthCode( 207 TinyAsciiStr::try_from_utf8(month_code) 208 .map_err(|_| CalendarError::UnknownMonthCode)?, 209 ); 210 let cal = calendar.0.clone(); 211 Ok(Box::new(Date(icu_calendar::Date::try_new_from_codes( 212 era, year, month, day, cal, 213 )?))) 214 } 215 216 /// Creates a new [`Date`] from an IXDTF string. 217 #[diplomat::rust_link(icu::calendar::Date::try_from_str, FnInStruct)] 218 #[diplomat::rust_link(icu::calendar::Date::try_from_utf8, FnInStruct, hidden)] 219 #[diplomat::rust_link(icu::calendar::Date::from_str, FnInStruct, hidden)] 220 #[diplomat::attr(all(supports = fallible_constructors, supports = named_constructors), named_constructor)] from_string( v: &DiplomatStr, calendar: &Calendar, ) -> Result<Box<Date>, CalendarParseError>221 pub fn from_string( 222 v: &DiplomatStr, 223 calendar: &Calendar, 224 ) -> Result<Box<Date>, CalendarParseError> { 225 Ok(Box::new(Date(icu_calendar::Date::try_from_utf8( 226 v, 227 calendar.0.clone(), 228 )?))) 229 } 230 231 /// Convert this date to one in a different calendar 232 #[diplomat::rust_link(icu::calendar::Date::to_calendar, FnInStruct)] 233 #[diplomat::rust_link(icu::calendar::AnyCalendar::convert_any_date, FnInEnum, hidden)] to_calendar(&self, calendar: &Calendar) -> Box<Date>234 pub fn to_calendar(&self, calendar: &Calendar) -> Box<Date> { 235 Box::new(Date(self.0.to_calendar(calendar.0.clone()))) 236 } 237 238 /// Converts this date to ISO 239 #[diplomat::rust_link(icu::calendar::Date::to_iso, FnInStruct)] to_iso(&self) -> Box<IsoDate>240 pub fn to_iso(&self) -> Box<IsoDate> { 241 Box::new(IsoDate(self.0.to_iso())) 242 } 243 244 /// Returns the 1-indexed day in the year for this date 245 #[diplomat::rust_link(icu::calendar::Date::day_of_year_info, FnInStruct)] 246 #[diplomat::attr(auto, getter)] day_of_year(&self) -> u16247 pub fn day_of_year(&self) -> u16 { 248 self.0.day_of_year_info().day_of_year 249 } 250 251 /// Returns the 1-indexed day in the month for this date 252 #[diplomat::rust_link(icu::calendar::Date::day_of_month, FnInStruct)] 253 #[diplomat::attr(auto, getter)] day_of_month(&self) -> u8254 pub fn day_of_month(&self) -> u8 { 255 self.0.day_of_month().0 256 } 257 258 /// Returns the day in the week for this day 259 #[diplomat::rust_link(icu::calendar::Date::day_of_week, FnInStruct)] 260 #[diplomat::attr(auto, getter)] day_of_week(&self) -> Weekday261 pub fn day_of_week(&self) -> Weekday { 262 self.0.day_of_week().into() 263 } 264 265 /// Returns the week number in this month, 1-indexed, based on what 266 /// is considered the first day of the week (often a locale preference). 267 /// 268 /// `first_weekday` can be obtained via `first_weekday()` on [`WeekCalculator`] 269 #[diplomat::rust_link(icu::calendar::Date::week_of_month, FnInStruct)] 270 #[diplomat::rust_link( 271 icu::calendar::week::WeekCalculator::week_of_month, 272 FnInStruct, 273 hidden 274 )] week_of_month(&self, first_weekday: Weekday) -> u8275 pub fn week_of_month(&self, first_weekday: Weekday) -> u8 { 276 self.0.week_of_month(first_weekday.into()).0 277 } 278 279 /// Returns the week number in this year, using week data 280 #[diplomat::rust_link(icu::calendar::Date::week_of_year, FnInStruct)] 281 #[diplomat::rust_link( 282 icu::calendar::week::WeekCalculator::week_of_year, 283 FnInStruct, 284 hidden 285 )] 286 #[cfg(feature = "calendar")] week_of_year(&self, calculator: &WeekCalculator) -> crate::week::ffi::WeekOf287 pub fn week_of_year(&self, calculator: &WeekCalculator) -> crate::week::ffi::WeekOf { 288 self.0.week_of_year(&calculator.0).into() 289 } 290 291 /// Returns 1-indexed number of the month of this date in its year 292 /// 293 /// Note that for lunar calendars this may not lead to the same month 294 /// having the same ordinal month across years; use month_code if you care 295 /// about month identity. 296 #[diplomat::rust_link(icu::calendar::Date::month, FnInStruct)] 297 #[diplomat::rust_link(icu::calendar::types::MonthInfo::ordinal, StructField)] 298 #[diplomat::attr(auto, getter)] ordinal_month(&self) -> u8299 pub fn ordinal_month(&self) -> u8 { 300 self.0.month().ordinal 301 } 302 303 /// Returns the month code for this date. Typically something 304 /// like "M01", "M02", but can be more complicated for lunar calendars. 305 #[diplomat::rust_link(icu::calendar::types::MonthInfo::standard_code, StructField)] 306 #[diplomat::rust_link(icu::calendar::Date::month, FnInStruct, compact)] 307 #[diplomat::rust_link(icu::calendar::types::MonthInfo, Struct, hidden)] 308 #[diplomat::rust_link( 309 icu::calendar::types::MonthInfo::formatting_code, 310 StructField, 311 hidden 312 )] 313 #[diplomat::rust_link(icu::calendar::types::MonthInfo, Struct, hidden)] 314 #[diplomat::attr(auto, getter)] month_code(&self, write: &mut diplomat_runtime::DiplomatWrite)315 pub fn month_code(&self, write: &mut diplomat_runtime::DiplomatWrite) { 316 let code = self.0.month().standard_code; 317 let _infallible = write.write_str(&code.0); 318 } 319 320 /// Returns the month number of this month. 321 #[diplomat::rust_link(icu::calendar::types::MonthInfo::month_number, FnInStruct)] 322 #[diplomat::attr(auto, getter)] month_number(&self) -> u8323 pub fn month_number(&self) -> u8 { 324 self.0.month().month_number() 325 } 326 327 /// Returns whether the month is a leap month. 328 #[diplomat::rust_link(icu::calendar::types::MonthInfo::is_leap, FnInStruct)] 329 #[diplomat::attr(auto, getter)] month_is_leap(&self) -> bool330 pub fn month_is_leap(&self) -> bool { 331 self.0.month().is_leap() 332 } 333 334 /// Returns the year number in the current era for this date 335 /// 336 /// For calendars without an era, returns the extended year 337 #[diplomat::rust_link(icu::calendar::types::YearInfo::era_year_or_extended, FnInStruct)] 338 #[diplomat::rust_link(icu::calendar::types::EraYear::era_year, StructField, compact)] 339 #[diplomat::rust_link(icu::calendar::types::YearInfo::era_year, FnInStruct, hidden)] 340 #[diplomat::rust_link(icu::calendar::Date::year, FnInStruct, compact)] 341 #[diplomat::rust_link(icu::calendar::types::EraYear, Struct, hidden)] 342 #[diplomat::rust_link(icu::calendar::types::YearKind, Enum, hidden)] 343 #[diplomat::rust_link(icu::calendar::types::YearInfo, Struct, hidden)] 344 #[diplomat::attr(auto, getter)] year_in_era(&self) -> i32345 pub fn year_in_era(&self) -> i32 { 346 self.0.year().era_year_or_extended() 347 } 348 349 /// Returns the extended year in the Date 350 #[diplomat::rust_link(icu::calendar::types::YearInfo::extended_year, StructField)] 351 #[diplomat::rust_link(icu::calendar::types::YearInfo, StructField, hidden)] 352 #[diplomat::attr(auto, getter)] extended_year(&self) -> i32353 pub fn extended_year(&self) -> i32 { 354 self.0.year().extended_year 355 } 356 357 /// Returns the era for this date, or an empty string 358 #[diplomat::rust_link(icu::calendar::types::EraYear::standard_era, StructField)] 359 #[diplomat::rust_link(icu::calendar::types::YearInfo::standard_era, FnInStruct, hidden)] 360 #[diplomat::rust_link(icu::calendar::Date::year, FnInStruct, compact)] 361 #[diplomat::rust_link(icu::calendar::types::EraYear, Struct, hidden)] 362 #[diplomat::rust_link(icu::calendar::types::YearKind, Enum, hidden)] 363 #[diplomat::rust_link(icu::calendar::types::YearInfo, Struct, hidden)] 364 #[diplomat::rust_link(icu::calendar::types::EraYear::formatting_era, StructField, hidden)] 365 #[diplomat::rust_link(icu::calendar::types::YearInfo::formatting_era, FnInStruct, hidden)] 366 #[diplomat::attr(auto, getter)] era(&self, write: &mut diplomat_runtime::DiplomatWrite)367 pub fn era(&self, write: &mut diplomat_runtime::DiplomatWrite) { 368 if let Some(era) = self.0.year().standard_era() { 369 let _infallible = write.write_str(&era.0); 370 } 371 } 372 373 /// Returns the number of months in the year represented by this date 374 #[diplomat::rust_link(icu::calendar::Date::months_in_year, FnInStruct)] 375 #[diplomat::attr(auto, getter)] months_in_year(&self) -> u8376 pub fn months_in_year(&self) -> u8 { 377 self.0.months_in_year() 378 } 379 380 /// Returns the number of days in the month represented by this date 381 #[diplomat::rust_link(icu::calendar::Date::days_in_month, FnInStruct)] 382 #[diplomat::attr(auto, getter)] days_in_month(&self) -> u8383 pub fn days_in_month(&self) -> u8 { 384 self.0.days_in_month() 385 } 386 387 /// Returns the number of days in the year represented by this date 388 #[diplomat::rust_link(icu::calendar::Date::days_in_year, FnInStruct)] 389 #[diplomat::attr(auto, getter)] days_in_year(&self) -> u16390 pub fn days_in_year(&self) -> u16 { 391 self.0.days_in_year() 392 } 393 394 /// Returns the [`Calendar`] object backing this date 395 #[diplomat::rust_link(icu::calendar::Date::calendar, FnInStruct)] 396 #[diplomat::rust_link(icu::calendar::Date::calendar_wrapper, FnInStruct, hidden)] 397 #[diplomat::attr(auto, getter)] calendar(&self) -> Box<Calendar>398 pub fn calendar(&self) -> Box<Calendar> { 399 Box::new(Calendar(self.0.calendar_wrapper().clone())) 400 } 401 } 402 } 403