use icu_provider::prelude::*;
use std::collections::HashSet;
use std::path::Path;
macro_rules! cb {
($($marker:path = $path:literal,)+ #[experimental] $($emarker:path = $epath:literal,)+) => {
fn markers_for_bin_inner(bytes: &[u8]) -> Result<HashSet<DataMarkerInfo>, DataError> {
use std::sync::OnceLock;
use crate as icu;
static LOOKUP: OnceLock<std::collections::HashMap<&'static str, Option<DataMarkerInfo>>> = OnceLock::new();
let lookup = LOOKUP.get_or_init(|| {
[
("core/helloworld@1", Some(icu_provider::hello_world::HelloWorldV1Marker::INFO)),
$(
($path, Some(<$marker>::INFO)),
)+
$(
#[cfg(feature = "experimental")]
($epath, Some(<$emarker>::INFO)),
#[cfg(not(feature = "experimental"))]
($epath, None),
)+
]
.into_iter()
.collect()
});
use memchr::memmem::*;
const LEADING_TAG: &[u8] = icu_provider::leading_tag!().as_bytes();
const TRAILING_TAG: &[u8] = icu_provider::trailing_tag!().as_bytes();
let trailing_tag = Finder::new(TRAILING_TAG);
find_iter(bytes, LEADING_TAG)
.map(|tag_position| tag_position + LEADING_TAG.len())
.filter_map(|marker_start| bytes.get(marker_start..))
.filter_map(move |marker_fragment| {
trailing_tag
.find(marker_fragment)
.and_then(|end| marker_fragment.get(..end))
})
.map(std::str::from_utf8)
.filter_map(Result::ok)
.filter_map(|p| {
match lookup.get(p) {
Some(Some(marker)) => Some(Ok(*marker)),
Some(None) => Some(Err(DataError::custom("This marker requires the `experimental` Cargo feature").with_display_context(p))),
None => None,
}
})
.collect::<Result<_, _>>()
}
}
}
icu_provider_registry::registry!(cb);
pub fn markers_for_bin(path: &Path) -> Result<HashSet<DataMarkerInfo>, DataError> {
markers_for_bin_inner(&std::fs::read(path)?)
}
#[test]
fn test_markers_for_bin() {
let hashset =
markers_for_bin_inner(include_bytes!("../tests/data/tutorial_buffer.wasm")).unwrap();
let mut sorted = hashset.into_iter().collect::<Vec<_>>();
sorted.sort();
assert_eq!(
sorted,
&[
crate::datetime::provider::neo::DayPeriodNamesV1Marker::INFO,
crate::datetime::provider::neo::GregorianMonthNamesV1Marker::INFO,
crate::datetime::provider::neo::GregorianYearNamesV1Marker::INFO,
crate::datetime::provider::neo::GluePatternV1Marker::INFO,
crate::datetime::provider::GregorianDateNeoSkeletonPatternsV1Marker::INFO,
crate::datetime::provider::TimeNeoSkeletonPatternsV1Marker::INFO,
crate::decimal::provider::DecimalSymbolsV2Marker::INFO,
]
);
}