usecrate::fallback::{LocaleFallbackConfig, LocaleFallbackPriority}; usecrate::{DataError, DataErrorKind, DataLocale, DataProvider, DataProviderWithMarker}; use core::fmt; use core::marker::PhantomData; use icu_locale_core::preferences::LocalePreferences; use yoke::Yokeable; use zerovec::ule::*;
/// Trait marker for data structs. All types delivered by the data provider must be associated with /// something implementing this trait. /// /// Data markers normally generated with the [`data_marker`](crate::data_marker) macro. /// /// Also see [`DataMarker`]. /// /// Note: `DynamicDataMarker`s are quasi-const-generic compile-time objects, and as such are expected /// to be unit structs. As this is not something that can be enforced by the type system, we /// currently only have a `'static` bound on them (which is needed by a lot of our code). /// /// # Examples /// /// Manually implementing DynamicDataMarker for a custom type: /// /// ``` /// use icu_provider::prelude::*; /// use std::borrow::Cow; /// /// #[derive(yoke::Yokeable, zerofrom::ZeroFrom)] /// struct MyDataStruct<'data> { /// message: Cow<'data, str>, /// } /// /// struct MyDataStructMarker; /// /// impl DynamicDataMarker for MyDataStructMarker { /// type DataStruct = MyDataStruct<'static>; /// } /// /// // We can now use MyDataStruct with DataProvider: /// let s = MyDataStruct { /// message: Cow::Owned("Hello World".into()), /// }; /// let payload = DataPayload::<MyDataStructMarker>::from_owned(s); /// assert_eq!(payload.get().message, "Hello World"); /// ``` /// /// [`data_struct`]: crate::data_struct pubtrait DynamicDataMarker: 'static { /// A type that implements [`Yokeable`]. This should typically be the `'static` version of a /// data struct. type DataStruct: for<'a> Yokeable<'a>;
}
/// A [`DynamicDataMarker`] with a [`DataMarkerInfo`] attached. /// /// Structs implementing this trait are normally generated with the [`data_struct!`] macro. /// /// Implementing this trait enables this marker to be used with the main [`DataProvider`] trait. /// Most markers should be associated with a specific marker and should therefore implement this /// trait. /// /// [`BufferMarker`] is an example of a marker that does _not_ implement this trait. /// /// Note: `DataMarker`s are quasi-const-generic compile-time objects, and as such are expected /// to be unit structs. As this is not something that can be enforced by the type system, we /// currently only have a `'static` bound on them (which is needed by a lot of our code). /// /// [`data_struct!`]: crate::data_struct /// [`DataProvider`]: crate::DataProvider /// [`BufferMarker`]: crate::buf::BufferMarker pubtrait DataMarker: DynamicDataMarker { /// The single [`DataMarkerInfo`] associated with this marker. const INFO: DataMarkerInfo;
}
/// Extension trait for methods on [`DataMarker`] pubtrait DataMarkerExt: DataMarker + Sized { /// Binds a [`DataMarker`] to a provider supporting it. fn bind<P>(provider: P) -> DataProviderWithMarker<Self, P> where
P: DataProvider<Self>; /// Constructs a [`DataLocale`] using fallback preferences from this [`DataMarker`]. fn make_locale(locale: LocalePreferences) -> DataLocale;
}
impl<M: DataMarker + Sized> DataMarkerExt for M { fn bind<P>(provider: P) -> DataProviderWithMarker<Self, P> where
P: DataProvider<Self>,
{
DataProviderWithMarker::new(provider)
}
/// Implements `DataProvider<NeverMarker<Y>>` on a struct. /// /// For more information, see [`NeverMarker`]. /// /// # Examples /// /// ``` /// use icu_locale_core::langid; /// use icu_provider::hello_world::*; /// use icu_provider::marker::NeverMarker; /// use icu_provider::prelude::*; /// /// struct MyProvider; /// /// icu_provider::marker::impl_data_provider_never_marker!(MyProvider); /// /// let result = DataProvider::<NeverMarker<HelloWorld<'static>>>::load( /// &MyProvider, /// DataRequest { /// id: DataIdentifierBorrowed::for_locale(&langid!("und").into()), /// ..Default::default() /// }, /// ); /// /// assert!(matches!( /// result, /// Err(DataError { /// kind: DataErrorKind::MarkerNotFound, /// .. /// }) /// )); /// ``` #[doc(hidden)] // macro #[macro_export]
macro_rules! __impl_data_provider_never_marker {
($ty:path) => { impl<Y> $crate::DataProvider<$crate::marker::NeverMarker<Y>> for $ty where for<'a> Y: $crate::prelude::yoke::Yokeable<'a>,
{ fn load(
&self,
req: $crate::DataRequest,
) -> Result<$crate::DataResponse<$crate::marker::NeverMarker<Y>>, $crate::DataError>
{
Err($crate::DataErrorKind::MarkerNotFound.with_req(
<$crate::marker::NeverMarker<Y> as $crate::DataMarker>::INFO,
req,
))
}
}
};
} #[doc(inline)] pubuse __impl_data_provider_never_marker as impl_data_provider_never_marker;
/// A compact hash of a [`DataMarkerInfo`]. Useful for keys in maps. /// /// The hash will be stable over time within major releases. #[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Copy, Clone, Hash, ULE)] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] #[repr(transparent)] pubstruct DataMarkerIdHash([u8; 4]);
impl DataMarkerIdHash { /// Magic bytes to locate [`DataMarkerIdHash`]es in binaries. pubconst LEADING_TAG: &[u8] = b"tdmh";
/// Gets the hash value as a byte array. pubconstfn to_bytes(self) -> [u8; 4] { self.0
}
}
/// Const function to compute the FxHash of a byte array. /// /// FxHash is a speedy hash algorithm used within rustc. The algorithm is satisfactory for our /// use case since the strings being hashed originate from a trusted source (the ICU4X /// components), and the hashes are computed at compile time, so we can check for collisions. /// /// We could have considered a SHA or other cryptographic hash function. However, we are using /// FxHash because: /// /// 1. There is precedent for this algorithm in Rust /// 2. The algorithm is easy to implement as a const function /// 3. The amount of code is small enough that we can reasonably keep the algorithm in-tree /// 4. FxHash is designed to output 32-bit or 64-bit values, whereas SHA outputs more bits, /// such that truncation would be required in order to fit into a u32, partially reducing /// the benefit of a cryptographically secure algorithm // The indexing operations in this function have been reviewed in detail and won't panic. #[expect(clippy::indexing_slicing)] constfn fxhash_32(bytes: &[u8]) -> u32 { // This code is adapted from https://github.com/rust-lang/rustc-hash, // whose license text is reproduced below. // // Copyright 2015 The Rust Project Developers. See the COPYRIGHT // file at the top-level directory of this distribution and at // http://rust-lang.org/COPYRIGHT. // // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your // option. This file may not be copied, modified, or distributed // except according to those terms.
letmut cursor = 0; let end = bytes.len(); letmut hash = 0;
while end - cursor >= 4 { let word = u32::from_le_bytes([
bytes[cursor],
bytes[cursor + 1],
bytes[cursor + 2],
bytes[cursor + 3],
]);
hash = hash_word_32(hash, word);
cursor += 4;
}
if end - cursor >= 2 { let word = u16::from_le_bytes([bytes[cursor], bytes[cursor + 1]]);
hash = hash_word_32(hash, word as u32);
cursor += 2;
}
if end - cursor >= 1 {
hash = hash_word_32(hash, bytes[cursor] as u32);
}
hash
}
#[cfg(feature = "alloc")] impl<'a> zerovec::maps::ZeroMapKV<'a> for DataMarkerIdHash { type Container = zerovec::ZeroVec<'a, DataMarkerIdHash>; type Slice = zerovec::ZeroSlice<DataMarkerIdHash>; type GetType = <DataMarkerIdHash as AsULE>::ULE; type OwnedType = DataMarkerIdHash;
}
// Safe since the ULE type is `self`. unsafeimpl EqULE for DataMarkerIdHash {}
/// The ID of a data marker. /// /// This is generally a [`DataMarkerIdHash`]. If debug assertions or the `export` Cargo feature /// are enabled, this also contains a human-readable string for an improved `Debug` implementation. #[derive(Debug, Copy, Clone, Eq)] pubstruct DataMarkerId { #[cfg(any(feature = "export", debug_assertions))]
debug: &'static str,
hash: [u8; 8],
}
impl DataMarkerId { #[doc(hidden)] // macro use // Error is a str of the expected character class and the index where it wasn't encountered // The indexing operations in this function have been reviewed in detail and won't panic. pubconstfn from_name(name: &'static str) -> Result<Self, (&'static str, usize)> { #![allow(clippy::indexing_slicing)] if !name.as_bytes()[name.len() - 1].is_ascii_digit() { return Err(("[0-9]", name.len()));
} letmut i = name.len() - 1; while name.as_bytes()[i - 1].is_ascii_digit() {
i -= 1;
} if name.as_bytes()[i - 1] != b'V' { return Err(("V", i));
}
let magic = DataMarkerIdHash::LEADING_TAG; let hash = fxhash_32(name.as_bytes()).to_le_bytes();
/// Gets a platform-independent hash of a [`DataMarkerId`]. /// /// The hash is 4 bytes and allows for fast comparison. /// /// # Example /// /// ``` /// use icu_provider::prelude::*; /// /// icu_provider::data_marker!(FooV1, &'static str); /// /// assert_eq!(FooV1::INFO.id.hashed().to_bytes(), [198, 217, 86, 48]); /// ``` #[inline] pubconstfn hashed(self) -> DataMarkerIdHash { let [.., h1, h2, h3, h4] = self.hash;
DataMarkerIdHash([h1, h2, h3, h4])
}
/// Returns the marker name. /// /// For size reasons, this is only available with the `export` Cargo feature. #[cfg(feature = "export")] pubconstfn name(self) -> &'static str { self.debug
}
}
/// Used for loading data from a dynamic ICU4X data provider. /// /// A data marker is tightly coupled with the code that uses it to load data at runtime. /// Executables can be searched for `DataMarkerInfo` instances to produce optimized data files. /// Therefore, users should not generally create DataMarkerInfo instances; they should instead use /// the ones exported by a component. #[derive(Copy, Clone, PartialEq, Eq)] #[non_exhaustive] pubstruct DataMarkerInfo { /// The ID of this marker. pub id: DataMarkerId, /// Whether this data marker only has a single payload, not keyed by a data identifier. pub is_singleton: bool, /// Whether this data marker uses checksums for integrity purposes. pub has_checksum: bool, /// The fallback to use for this data marker. pub fallback_config: LocaleFallbackConfig, /// The attributes domain for this data marker. This can be used for filtering marker /// attributes during provider export. #[cfg(feature = "export")] pub attributes_domain: &'static str, /// Whether to create constants for each data struct in baked data. #[cfg(feature = "export")] pub expose_baked_consts: bool,
}
/// A marker for the given `DataStruct`. #[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)] pubstruct ErasedMarker<DataStruct: for<'a> Yokeable<'a>>(PhantomData<DataStruct>); impl<DataStruct: for<'a> Yokeable<'a>> DynamicDataMarker for ErasedMarker<DataStruct> { type DataStruct = DataStruct;
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.