From 32cf749b0bda916e37a212cf5186ca139f114514 Mon Sep 17 00:00:00 2001 From: "Shane F. Carr" Date: Wed, 8 Nov 2023 08:33:24 -0800 Subject: [PATCH] Add full tutorial code as a crate --- docs/tutorials/Cargo.lock | 132 ++++++++++++++++-- docs/tutorials/Cargo.toml | 1 + docs/tutorials/crates/interactive/Cargo.toml | 14 ++ .../crates/interactive/data/.gitignore | 1 + .../crates/interactive/data/README.md | 6 + .../crates/interactive/src/.gitignore | 1 + .../crates/interactive/src/bin/full_blob.rs | 86 ++++++++++++ .../interactive/src/bin/gregory_blob.rs | 87 ++++++++++++ .../crates/interactive/src/bin/intro_only.rs | 61 ++++++++ 9 files changed, 380 insertions(+), 9 deletions(-) create mode 100644 docs/tutorials/crates/interactive/Cargo.toml create mode 100644 docs/tutorials/crates/interactive/data/.gitignore create mode 100644 docs/tutorials/crates/interactive/data/README.md create mode 100644 docs/tutorials/crates/interactive/src/.gitignore create mode 100644 docs/tutorials/crates/interactive/src/bin/full_blob.rs create mode 100644 docs/tutorials/crates/interactive/src/bin/gregory_blob.rs create mode 100644 docs/tutorials/crates/interactive/src/bin/intro_only.rs diff --git a/docs/tutorials/Cargo.lock b/docs/tutorials/Cargo.lock index 03742b89f0f..c54b4b80598 100644 --- a/docs/tutorials/Cargo.lock +++ b/docs/tutorials/Cargo.lock @@ -418,6 +418,15 @@ dependencies = [ "serde", ] +[[package]] +name = "deranged" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0f32d04922c60427da6f9fef14d042d9edddef64cb9d4ce0d64d0685fbeb1fd3" +dependencies = [ + "powerfmt", +] + [[package]] name = "discard" version = "1.0.4" @@ -603,6 +612,15 @@ dependencies = [ "percent-encoding", ] +[[package]] +name = "fraction" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59a78dd758a47a7305478e0e054f9fde4e983b9f9eccda162bf7ca03b79e9d40" +dependencies = [ + "num", +] + [[package]] name = "funty" version = "2.0.0" @@ -781,7 +799,7 @@ dependencies = [ [[package]] name = "icu_collator" -version = "1.3.2" +version = "1.3.3" dependencies = [ "databake", "displaydoc", @@ -801,7 +819,7 @@ dependencies = [ [[package]] name = "icu_collator_data" -version = "1.3.2" +version = "1.3.3" [[package]] name = "icu_collections" @@ -832,18 +850,20 @@ dependencies = [ [[package]] name = "icu_compactdecimal_data" -version = "1.3.2" +version = "1.3.4" [[package]] name = "icu_datagen" -version = "1.3.2" +version = "1.3.3" dependencies = [ "clap", "crlify", "databake", "displaydoc", + "either", "elsa", "eyre", + "fraction", "icu_calendar", "icu_casemap", "icu_codepointtrie_builder", @@ -867,6 +887,7 @@ dependencies = [ "log", "memchr", "ndarray", + "num-bigint", "once_cell", "proc-macro2", "rayon", @@ -910,7 +931,7 @@ dependencies = [ [[package]] name = "icu_datetime_data" -version = "1.3.2" +version = "1.3.4" [[package]] name = "icu_decimal" @@ -929,7 +950,7 @@ dependencies = [ [[package]] name = "icu_decimal_data" -version = "1.3.2" +version = "1.3.4" [[package]] name = "icu_displaynames" @@ -946,7 +967,7 @@ dependencies = [ [[package]] name = "icu_displaynames_data" -version = "1.3.2" +version = "1.3.4" [[package]] name = "icu_list" @@ -1056,7 +1077,7 @@ dependencies = [ [[package]] name = "icu_properties_data" -version = "1.3.2" +version = "1.3.4" [[package]] name = "icu_provider" @@ -1101,6 +1122,7 @@ dependencies = [ "postcard", "serde", "writeable", + "zerotrie", "zerovec", ] @@ -1201,6 +1223,7 @@ dependencies = [ "icu_unicodeset_parse", "litemap", "serde", + "writeable", "zerovec", ] @@ -1435,6 +1458,30 @@ dependencies = [ "rawpointer", ] +[[package]] +name = "num" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b05180d69e3da0e530ba2a1dae5110317e49e3b7f3d41be227dc5f92e49ee7af" +dependencies = [ + "num-complex", + "num-integer", + "num-iter", + "num-rational", + "num-traits", +] + +[[package]] +name = "num-bigint" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "608e7659b5c3d7cba262d894801b9ec9d00de989e8a82bd4bef91d08da45cdc0" +dependencies = [ + "autocfg", + "num-integer", + "num-traits", +] + [[package]] name = "num-complex" version = "0.4.4" @@ -1454,6 +1501,28 @@ dependencies = [ "num-traits", ] +[[package]] +name = "num-iter" +version = "0.1.43" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d03e6c028c5dc5cac6e2dec0efda81fc887605bb3d884578bb6d6bf7514e252" +dependencies = [ + "autocfg", + "num-integer", + "num-traits", +] + +[[package]] +name = "num-rational" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0638a1c9d0a3c0914158145bc76cff373a75a627e6ecbfb71cbe6f453a5a19b0" +dependencies = [ + "autocfg", + "num-integer", + "num-traits", +] + [[package]] name = "num-traits" version = "0.2.16" @@ -1463,6 +1532,15 @@ dependencies = [ "autocfg", ] +[[package]] +name = "num_threads" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2819ce041d2ee131036f4fc9d6ae7ae125a3a40e97ba64d04fe799ad9dabbb44" +dependencies = [ + "libc", +] + [[package]] name = "object" version = "0.28.4" @@ -1512,6 +1590,12 @@ dependencies = [ "serde", ] +[[package]] +name = "powerfmt" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" + [[package]] name = "proc-macro-error" version = "1.0.4" @@ -2096,6 +2180,26 @@ dependencies = [ "winapi", ] +[[package]] +name = "time" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4a34ab300f2dee6e562c10a046fc05e358b29f9bf92277f30c3c8d82275f6f5" +dependencies = [ + "deranged", + "libc", + "num_threads", + "powerfmt", + "serde", + "time-core", +] + +[[package]] +name = "time-core" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3" + [[package]] name = "time-macros" version = "0.1.1" @@ -2225,6 +2329,15 @@ dependencies = [ "icu", ] +[[package]] +name = "tutorial_interactive" +version = "0.0.0" +dependencies = [ + "icu", + "icu_provider_blob", + "time 0.3.30", +] + [[package]] name = "tutorial_sync" version = "0.0.0" @@ -2249,6 +2362,7 @@ dependencies = [ "lru", "serde", "serde-aux", + "time 0.3.30", "tinystr", "writeable", ] @@ -2679,7 +2793,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "22dc83aadbdf97388de3211cb6f105374f245a3cf2a5c65a16776e7a087a8468" dependencies = [ "byteorder", - "time", + "time 0.2.27", "wasmer-types", ] diff --git a/docs/tutorials/Cargo.toml b/docs/tutorials/Cargo.toml index 11a13ab27b8..f5945c5ae69 100644 --- a/docs/tutorials/Cargo.toml +++ b/docs/tutorials/Cargo.toml @@ -11,6 +11,7 @@ members = [ "crates/custom_compiled", "crates/default", "crates/experimental", + "crates/interactive", "crates/sync", "testing", ] diff --git a/docs/tutorials/crates/interactive/Cargo.toml b/docs/tutorials/crates/interactive/Cargo.toml new file mode 100644 index 00000000000..951384b4d52 --- /dev/null +++ b/docs/tutorials/crates/interactive/Cargo.toml @@ -0,0 +1,14 @@ +# 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 ). + +[package] +name = "tutorial_interactive" +version = "0.0.0" +edition = "2021" +publish = false + +[dependencies] +icu = { version = "1.3", features = ["serde"] } +icu_provider_blob = "1.3" +time = { version = "0.3", features = ["local-offset"] } diff --git a/docs/tutorials/crates/interactive/data/.gitignore b/docs/tutorials/crates/interactive/data/.gitignore new file mode 100644 index 00000000000..d4c6615cd58 --- /dev/null +++ b/docs/tutorials/crates/interactive/data/.gitignore @@ -0,0 +1 @@ +*.blob diff --git a/docs/tutorials/crates/interactive/data/README.md b/docs/tutorials/crates/interactive/data/README.md new file mode 100644 index 00000000000..b0650c6167e --- /dev/null +++ b/docs/tutorials/crates/interactive/data/README.md @@ -0,0 +1,6 @@ +Build these data files as follows: + +``` +$ icu4x-datagen --keys all --locales ccp --format blob --out crates/interactive/data/ccp_all.blob +$ icu4x-datagen --keys-for-bin target/debug/gregory_blob --locales ccp --format blob --out crates/interactive/data/ccp_gregory.blob +``` \ No newline at end of file diff --git a/docs/tutorials/crates/interactive/src/.gitignore b/docs/tutorials/crates/interactive/src/.gitignore new file mode 100644 index 00000000000..c0094bb5ced --- /dev/null +++ b/docs/tutorials/crates/interactive/src/.gitignore @@ -0,0 +1 @@ +!bin/ diff --git a/docs/tutorials/crates/interactive/src/bin/full_blob.rs b/docs/tutorials/crates/interactive/src/bin/full_blob.rs new file mode 100644 index 00000000000..80916a81371 --- /dev/null +++ b/docs/tutorials/crates/interactive/src/bin/full_blob.rs @@ -0,0 +1,86 @@ +// 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 ). + +//! This is a demo project of an interactive app using compiled and blob data. +//! +//! For more information, see these tutorials: +//! +//! - [intro_interactive.md](../../intro_interactive.md). +//! - [data_management_interactive.md](../../data_management_interactive.md). + +use icu::locid::Locale; +use icu::calendar::{DateTime, Iso}; +use icu::datetime::options::length; +use icu::datetime::DateTimeFormatter; +use icu::locid::locale; +use icu_provider_blob::BlobDataProvider; + +const CCP_BLOB_PATH: &str = concat!(env!("CARGO_MANIFEST_DIR"), "/data/ccp_all.blob"); + +/// Helper function to create an ICU4X DateTime for the current local time +fn get_current_datetime() -> DateTime { + let current_offset_date_time = time::OffsetDateTime::now_local().unwrap(); + DateTime::try_new_iso_datetime( + current_offset_date_time.year(), + current_offset_date_time.month() as u8, + current_offset_date_time.day(), + current_offset_date_time.hour(), + current_offset_date_time.minute(), + current_offset_date_time.second(), + ) + .unwrap() +} + +fn main() { + // In the main() function: + print!("Enter your locale: "); + std::io::Write::flush(&mut std::io::stdout()).unwrap(); + let locale_str = { + let mut buf = String::new(); + std::io::stdin().read_line(&mut buf).unwrap(); + buf + }; + + // Since the string contains whitespace, we must call `.trim()`: + let locale = match locale_str.trim().parse::() { + Ok(locale) => { + println!("You entered: {locale}"); + locale + } + Err(e) => { + panic!("Error parsing locale! {e}"); + } + }; + + let iso_datetime = get_current_datetime(); + + // Create and use an ICU4X date formatter: + let datetime_formatter = if locale == locale!("ccp") { + println!("Using buffer provider"); + + let blob = std::fs::read(CCP_BLOB_PATH) + .expect("blob should read successfully") + .into(); + + let provider = + BlobDataProvider::try_new_from_blob(blob).expect("deserialization should succeed"); + + DateTimeFormatter::try_new_with_buffer_provider( + &provider, + &(&locale).into(), + Default::default(), + ) + .expect("should have data for selected locale") + } else { + // As before + DateTimeFormatter::try_new(&(&locale).into(), Default::default()) + .expect("should have data for selected locale") + }; + println!( + "Date: {}", + datetime_formatter + .format(&iso_datetime.to_any()) + .expect("date should format successfully") + ); +} diff --git a/docs/tutorials/crates/interactive/src/bin/gregory_blob.rs b/docs/tutorials/crates/interactive/src/bin/gregory_blob.rs new file mode 100644 index 00000000000..31b7a6afea7 --- /dev/null +++ b/docs/tutorials/crates/interactive/src/bin/gregory_blob.rs @@ -0,0 +1,87 @@ +// 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 ). + +//! This is a demo project of an interactive app using compiled and blob data. +//! +//! For more information, see these tutorials: +//! +//! - [intro_interactive.md](../../intro_interactive.md). +//! - [data_management_interactive.md](../../data_management_interactive.md). + +use icu::locid::Locale; +use icu::calendar::{DateTime, Iso, Gregorian}; +use icu::datetime::options::length; +use icu::datetime::TypedDateFormatter; +use icu::locid::locale; +use icu_provider_blob::BlobDataProvider; + +const CCP_BLOB_PATH: &str = concat!(env!("CARGO_MANIFEST_DIR"), "/data/ccp_gregory.blob"); + +/// Helper function to create an ICU4X DateTime for the current local time +fn get_current_datetime() -> DateTime { + let current_offset_date_time = time::OffsetDateTime::now_local().unwrap(); + DateTime::try_new_iso_datetime( + current_offset_date_time.year(), + current_offset_date_time.month() as u8, + current_offset_date_time.day(), + current_offset_date_time.hour(), + current_offset_date_time.minute(), + current_offset_date_time.second(), + ) + .unwrap() +} + +fn main() { + // In the main() function: + print!("Enter your locale: "); + std::io::Write::flush(&mut std::io::stdout()).unwrap(); + let locale_str = { + let mut buf = String::new(); + std::io::stdin().read_line(&mut buf).unwrap(); + buf + }; + + // Since the string contains whitespace, we must call `.trim()`: + let locale = match locale_str.trim().parse::() { + Ok(locale) => { + println!("You entered: {locale}"); + locale + } + Err(e) => { + panic!("Error parsing locale! {e}"); + } + }; + + let iso_datetime = get_current_datetime(); + + // Create and use an ICU4X date formatter: + let date_formatter = if locale == locale!("ccp") { + println!("Using buffer provider"); + + let blob = std::fs::read(CCP_BLOB_PATH) + .expect("blob should read successfully") + .into(); + + let provider = + BlobDataProvider::try_new_from_blob(blob).expect("deserialization should succeed"); + + TypedDateFormatter::::try_new_with_length_with_buffer_provider( + &provider, + &(&locale).into(), + length::Date::Medium, + ) + .expect("should have data for selected locale") + } else { + TypedDateFormatter::::try_new_with_length( + &(&locale).into(), + length::Date::Medium, + ) + .expect("should have data for selected locale") + }; + println!( + "Date: {}", + date_formatter + .format(&iso_datetime.to_calendar(Gregorian)) + ); +} diff --git a/docs/tutorials/crates/interactive/src/bin/intro_only.rs b/docs/tutorials/crates/interactive/src/bin/intro_only.rs new file mode 100644 index 00000000000..9f72e2ae0e8 --- /dev/null +++ b/docs/tutorials/crates/interactive/src/bin/intro_only.rs @@ -0,0 +1,61 @@ +// 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 ). + +//! This is a demo project of an interactive app using compiled and blob data. +//! +//! For more information, see these tutorials: +//! +//! - [intro_interactive.md](../../intro_interactive.md). +//! - [data_management_interactive.md](../../data_management_interactive.md). + +use icu::locid::Locale; +use icu::calendar::{Date, Iso}; +use icu::datetime::options::length; +use icu::datetime::DateFormatter; + +/// Helper function to create an ICU4X DateTime for the current local time +fn get_current_date() -> Date { + let current_offset_date_time = time::OffsetDateTime::now_local().unwrap(); + Date::try_new_iso_date( + current_offset_date_time.year(), + current_offset_date_time.month() as u8, + current_offset_date_time.day(), + ) + .unwrap() +} + +fn main() { + // In the main() function: + print!("Enter your locale: "); + std::io::Write::flush(&mut std::io::stdout()).unwrap(); + let locale_str = { + let mut buf = String::new(); + std::io::stdin().read_line(&mut buf).unwrap(); + buf + }; + + // Since the string contains whitespace, we must call `.trim()`: + let locale = match locale_str.trim().parse::() { + Ok(locale) => { + println!("You entered: {locale}"); + locale + } + Err(e) => { + panic!("Error parsing locale! {e}"); + } + }; + + let iso_date = get_current_date(); + + // Create and use an ICU4X date formatter: + let date_formatter = + DateFormatter::try_new_with_length(&(&locale).into(), length::Date::Medium) + .expect("should have data for specified locale"); + println!( + "Date: {}", + date_formatter + .format(&iso_date.to_any()) + .expect("date should format successfully") + ); +}