Skip to main content

icu/
datagen.rs

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
5extern crate alloc;
6
7use alloc::collections::{BTreeMap, BTreeSet};
8use icu_provider::prelude::*;
9
10macro_rules! cb {
11    ($($marker_ty:ty:$marker:ident,)+ #[unstable] $($emarker_ty:ty:$emarker:ident,)+) => {
12        /// Parses a compiled binary and returns a list of [`DataMarkerInfo`]s that it uses *at runtime*.
13        ///
14        /// This function is intended to be used for binaries that use `BufferProvider`,
15        /// for which the compiler cannot remove unused data. Using this function on a binary that only
16        /// uses compiled data (through the `compiled_data` feature or manual baked data) will not return
17        /// any markers, as the markers only exist in the type system.
18        ///
19        /// # Example
20        ///
21        /// ```no_run
22        /// # use icu_provider::DataMarker;
23        /// # use std::path::Path;
24        /// # fn main() -> Result<(), Box<dyn std::error::Error>> {
25        /// assert_eq!(
26        ///     icu::markers_for_bin(&std::fs::read(Path::new("target/release/my-app"))?)?,
27        ///     std::collections::BTreeSet::from_iter([
28        ///         icu::list::provider::ListAndV1::INFO,
29        ///         icu::list::provider::ListOrV1::INFO,
30        ///     ]),
31        /// );
32        /// # Ok(())
33        /// # }
34        /// ```
35        pub fn markers_for_bin(bytes: &[u8]) -> Result<BTreeSet<DataMarkerInfo>, DataError> {
36            use crate as icu;
37            let lookup =
38                alloc::vec![
39                    (icu_provider::hello_world::HelloWorldV1::INFO.id.hashed().to_bytes(), Ok(icu_provider::hello_world::HelloWorldV1::INFO)),
40                    $(
41                        (<$marker_ty>::INFO.id.hashed().to_bytes(), Ok(<$marker_ty>::INFO)),
42                    )+
43                    $(
44                        #[cfg(feature = "unstable")]
45                        (<$emarker_ty>::INFO.id.hashed().to_bytes(), Ok(<$emarker_ty>::INFO)),
46                        #[cfg(not(feature = "unstable"))]
47                        (icu_provider::marker::DataMarkerId::from_name(stringify!($emarker)).unwrap().hashed().to_bytes(), Err(stringify!($emarker))),
48                    )+
49
50                ]
51                .into_iter()
52                .collect::<BTreeMap<[u8; 4],Result<DataMarkerInfo, &'static str>>>();
53
54            use memchr::memmem::*;
55
56            find_iter(bytes, icu_provider::marker::DataMarkerIdHash::LEADING_TAG)
57                .map(|tag_position| tag_position + icu_provider::marker::DataMarkerIdHash::LEADING_TAG.len())
58                .filter_map(|marker_start| bytes.get(marker_start..marker_start+4))
59                .filter_map(|p| {
60                    match lookup.get(p) {
61                        Some(Ok(marker)) => Some(Ok(*marker)),
62                        Some(Err(p)) => Some(Err(DataError::custom("This marker requires the `unstable` Cargo feature").with_display_context(p))),
63                        None => None,
64                    }
65                })
66                .collect::<Result<_, _>>()
67        }
68    }
69}
70icu_provider_registry::registry!(cb);
71
72#[test]
73fn test_markers_for_bin() {
74    assert_eq!(
75        markers_for_bin(include_bytes!("../tests/data/tutorial_buffer.wasm")).unwrap(),
76        [
77            crate::datetime::provider::names::DayPeriodNamesV1::INFO,
78            crate::datetime::provider::names::DatetimeNamesMonthGregorianV1::INFO,
79            crate::datetime::provider::names::DatetimeNamesYearGregorianV1::INFO,
80            crate::datetime::provider::semantic_skeletons::DatetimePatternsGlueV1::INFO,
81            crate::datetime::provider::semantic_skeletons::DatetimePatternsDateGregorianV1::INFO,
82            crate::datetime::provider::semantic_skeletons::DatetimePatternsTimeV1::INFO,
83            crate::decimal::provider::DecimalSymbolsV1::INFO,
84            crate::decimal::provider::DecimalDigitsV1::INFO,
85        ]
86        .into_iter()
87        .collect(),
88    );
89}