From ee2814ea79125da5f849454cb670fc33a19eac69 Mon Sep 17 00:00:00 2001 From: Robert Bastian <4706271+robertbastian@users.noreply.github.com> Date: Mon, 10 Feb 2025 16:05:56 +0100 Subject: [PATCH] no-alloc more crates (#6078) #6076 This no-allocs everything except for crates that use: * `Cow` * `ZeroMap` --- Cargo.lock | 8 ++ components/calendar/Cargo.toml | 5 +- components/calendar/src/date.rs | 6 ++ components/calendar/src/lib.rs | 1 + components/calendar/src/provider.rs | 31 ++++++- components/casemap/Cargo.toml | 8 +- components/collator/Cargo.toml | 2 +- components/collator/src/comparison.rs | 15 ++-- components/collator/src/lib.rs | 2 - components/collections/Cargo.toml | 3 +- .../src/codepointinvlist/conversions.rs | 5 +- .../src/codepointinvlist/cpinvlist.rs | 11 ++- .../collections/src/codepointinvlist/mod.rs | 11 ++- .../src/codepointinvliststringlist/mod.rs | 45 +++++++--- .../collections/src/codepointtrie/cptrie.rs | 6 ++ components/collections/src/lib.rs | 1 + components/datetime/Cargo.toml | 7 +- components/decimal/Cargo.toml | 2 +- components/experimental/Cargo.toml | 6 +- components/icu/Cargo.toml | 6 +- components/list/Cargo.toml | 4 +- components/locale/Cargo.toml | 6 +- components/locale_core/Cargo.toml | 5 +- components/locale_core/src/data.rs | 8 +- components/locale_core/src/extensions/mod.rs | 18 ++++ .../locale_core/src/extensions/other/mod.rs | 12 +++ .../locale_core/src/extensions/private/mod.rs | 10 +++ .../src/extensions/transform/mod.rs | 14 ++- .../src/extensions/transform/value.rs | 12 ++- .../src/extensions/unicode/attributes.rs | 9 ++ .../src/extensions/unicode/keywords.rs | 13 +++ .../locale_core/src/extensions/unicode/mod.rs | 8 ++ .../src/extensions/unicode/value.rs | 14 ++- components/locale_core/src/helpers.rs | 2 + components/locale_core/src/langid.rs | 25 ++++-- components/locale_core/src/lib.rs | 3 +- components/locale_core/src/locale.rs | 13 ++- components/locale_core/src/parser/langid.rs | 5 ++ components/locale_core/src/parser/locale.rs | 19 ++--- components/locale_core/src/parser/mod.rs | 12 +-- .../src/preferences/extensions/unicode/mod.rs | 1 + .../locale_core/src/preferences/locale.rs | 5 +- .../locale_core/src/shortvec/litemap.rs | 11 ++- components/locale_core/src/shortvec/mod.rs | 17 ++++ components/locale_core/src/subtags/mod.rs | 2 + .../locale_core/src/subtags/variants.rs | 3 + components/normalizer/Cargo.toml | 4 +- components/normalizer/src/lib.rs | 6 ++ components/pattern/Cargo.toml | 2 +- components/plurals/Cargo.toml | 4 +- components/properties/Cargo.toml | 1 + components/properties/src/code_point_map.rs | 10 ++- components/properties/src/lib.rs | 1 + components/properties/src/props.rs | 2 +- components/properties/src/provider.rs | 8 +- components/properties/src/script.rs | 3 + components/segmenter/Cargo.toml | 4 +- ffi/capi/Cargo.toml | 4 +- provider/adapters/Cargo.toml | 2 +- provider/baked/Cargo.toml | 2 + provider/baked/src/binary_search.rs | 6 ++ provider/baked/src/lib.rs | 2 + provider/baked/src/zerotrie.rs | 2 + provider/blob/Cargo.toml | 10 ++- provider/blob/src/blob_data_provider.rs | 8 +- provider/blob/src/blob_schema.rs | 44 ++-------- provider/blob/src/lib.rs | 1 + provider/core/Cargo.toml | 3 +- provider/core/src/data_provider.rs | 37 +++++--- provider/core/src/lib.rs | 13 ++- provider/core/src/marker.rs | 1 + provider/core/src/request.rs | 17 ++++ provider/core/src/response.rs | 18 +++- provider/icu4x-datagen/Cargo.toml | 4 +- provider/source/Cargo.toml | 2 +- tools/md-tests/Cargo.toml | 2 +- tools/noalloctest/Cargo.toml | 20 +++-- tutorials/rust.md | 2 +- tutorials/rust/buffer/Cargo.toml | 2 +- utils/potential_utf/Cargo.toml | 4 +- utils/potential_utf/src/ustr.rs | 2 +- utils/tinystr/Cargo.toml | 2 +- utils/tinystr/src/ule.rs | 4 + utils/zerovec/Cargo.toml | 5 +- utils/zerovec/src/cow.rs | 60 +++++++++---- utils/zerovec/src/hashmap/mod.rs | 2 +- utils/zerovec/src/lib.rs | 14 ++- utils/zerovec/src/ule/encode.rs | 14 +++ utils/zerovec/src/ule/mod.rs | 13 +-- utils/zerovec/src/ule/niche.rs | 6 +- utils/zerovec/src/ule/tuple.rs | 1 + utils/zerovec/src/ule/tuplevar.rs | 12 +-- utils/zerovec/src/ule/vartuple.rs | 13 ++- utils/zerovec/src/varzerovec/components.rs | 23 ++--- utils/zerovec/src/varzerovec/mod.rs | 2 + utils/zerovec/src/varzerovec/owned.rs | 19 +++-- utils/zerovec/src/varzerovec/slice.rs | 5 +- utils/zerovec/src/varzerovec/vec.rs | 20 ++++- utils/zerovec/src/yoke_impls.rs | 11 ++- utils/zerovec/src/zerofrom_impls.rs | 7 +- utils/zerovec/src/zerovec/mod.rs | 85 +++++++++++++------ utils/zerovec/src/zerovec/slice.rs | 9 +- 102 files changed, 720 insertions(+), 292 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index cc4ff151220..dcf08506d9c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2037,12 +2037,20 @@ dependencies = [ name = "noalloctest" version = "2.0.0-beta1" dependencies = [ + "icu_calendar", + "icu_collections", + "icu_locale_core", + "icu_normalizer", + "icu_properties", + "icu_provider", + "icu_provider_baked", "litemap", "potential_utf", "tinystr", "yoke", "zerofrom", "zerotrie", + "zerovec", ] [[package]] diff --git a/components/calendar/Cargo.toml b/components/calendar/Cargo.toml index eeb27132e9c..df35efa7a5b 100644 --- a/components/calendar/Cargo.toml +++ b/components/calendar/Cargo.toml @@ -23,7 +23,7 @@ all-features = true calendrical_calculations = { workspace = true } displaydoc = { workspace = true } icu_provider = { workspace = true, features = ["macros"] } -icu_locale_core = { workspace = true } +icu_locale_core = { workspace = true, features = ["alloc"]} ixdtf = { workspace = true, optional = true } tinystr = { workspace = true, features = ["alloc", "zerovec"] } zerovec = { workspace = true, features = ["derive"] } @@ -51,8 +51,9 @@ default = ["compiled_data", "ixdtf"] ixdtf = ["dep:ixdtf"] logging = ["calendrical_calculations/logging"] serde = ["dep:serde", "zerovec/serde", "tinystr/serde", "icu_provider/serde"] -datagen = ["serde", "dep:databake", "zerovec/databake", "tinystr/databake"] +datagen = ["serde", "dep:databake", "zerovec/databake", "tinystr/databake", "alloc"] compiled_data = ["dep:icu_calendar_data"] +alloc = [] [[bench]] name = "date" diff --git a/components/calendar/src/date.rs b/components/calendar/src/date.rs index 73988a7d7c7..d14d00d065e 100644 --- a/components/calendar/src/date.rs +++ b/components/calendar/src/date.rs @@ -6,7 +6,9 @@ use crate::any_calendar::{AnyCalendar, IntoAnyCalendar}; use crate::error::DateError; use crate::week::{WeekCalculator, WeekOf}; use crate::{types, Calendar, DateDuration, DateDurationUnit, Iso}; +#[cfg(feature = "alloc")] use alloc::rc::Rc; +#[cfg(feature = "alloc")] use alloc::sync::Arc; use core::fmt; use core::ops::Deref; @@ -30,6 +32,7 @@ impl AsCalendar for C { } } +#[cfg(feature = "alloc")] impl AsCalendar for Rc { type Calendar = C::Calendar; #[inline] @@ -38,6 +41,7 @@ impl AsCalendar for Rc { } } +#[cfg(feature = "alloc")] impl AsCalendar for Arc { type Calendar = C::Calendar; #[inline] @@ -358,6 +362,7 @@ impl Date { /// Wrap the calendar type in `Rc` /// /// Useful when paired with [`Self::to_any()`] to obtain a `Date>` + #[cfg(feature = "alloc")] pub fn wrap_calendar_in_rc(self) -> Date> { Date::from_raw(self.inner, Rc::new(self.calendar)) } @@ -365,6 +370,7 @@ impl Date { /// Wrap the calendar type in `Arc` /// /// Useful when paired with [`Self::to_any()`] to obtain a `Date>` + #[cfg(feature = "alloc")] pub fn wrap_calendar_in_arc(self) -> Date> { Date::from_raw(self.inner, Arc::new(self.calendar)) } diff --git a/components/calendar/src/lib.rs b/components/calendar/src/lib.rs index e22b58b2491..1e693de4281 100644 --- a/components/calendar/src/lib.rs +++ b/components/calendar/src/lib.rs @@ -89,6 +89,7 @@ )] #![warn(missing_docs)] +#[cfg(feature = "alloc")] extern crate alloc; // Make sure inherent docs go first diff --git a/components/calendar/src/provider.rs b/components/calendar/src/provider.rs index 3898570a428..021cbb493a8 100644 --- a/components/calendar/src/provider.rs +++ b/components/calendar/src/provider.rs @@ -220,9 +220,13 @@ impl serde::Serialize for WeekdaySet { S: serde::Serializer, { if serializer.is_human_readable() { - crate::week_of::WeekdaySetIterator::new(IsoWeekday::Monday, *self) - .collect::>() - .serialize(serializer) + use serde::ser::SerializeSeq; + + let mut seq = serializer.serialize_seq(None)?; + for day in crate::week_of::WeekdaySetIterator::new(IsoWeekday::Monday, *self) { + seq.serialize_element(&day)?; + } + seq.end() } else { self.0.serialize(serializer) } @@ -236,7 +240,26 @@ impl<'de> serde::Deserialize<'de> for WeekdaySet { D: serde::Deserializer<'de>, { if deserializer.is_human_readable() { - alloc::vec::Vec::::deserialize(deserializer).map(|s| Self::new(&s)) + use core::marker::PhantomData; + + struct Visitor<'de>(PhantomData<&'de ()>); + impl<'de> serde::de::Visitor<'de> for Visitor<'de> { + type Value = WeekdaySet; + fn expecting(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { + core::write!(f, "a sequence of IsoWeekdays") + } + fn visit_seq>( + self, + mut seq: A, + ) -> Result { + let mut set = WeekdaySet::new(&[]); + while let Some(day) = seq.next_element::()? { + set.0 |= day.bit_value(); + } + Ok(set) + } + } + deserializer.deserialize_seq(Visitor(PhantomData)) } else { u8::deserialize(deserializer).map(Self) } diff --git a/components/casemap/Cargo.toml b/components/casemap/Cargo.toml index 4d087fd53fd..8d761cb51f7 100644 --- a/components/casemap/Cargo.toml +++ b/components/casemap/Cargo.toml @@ -21,13 +21,13 @@ all-features = true [dependencies] displaydoc = { workspace = true } -icu_collections = { workspace = true } -icu_locale_core = { workspace = true } +icu_collections = { workspace = true, features = ["alloc"] } +icu_locale_core = { workspace = true, features = ["alloc"] } icu_properties = { workspace = true } icu_provider = { workspace = true, features = ["macros"] } -potential_utf = { workspace = true, features = ["zerovec"] } +potential_utf = { workspace = true, features = ["alloc", "zerovec"] } writeable = { workspace = true } -zerovec = { workspace = true, features = ["yoke"] } +zerovec = { workspace = true, features = ["alloc", "yoke"] } databake = { workspace = true, features = ["derive"], optional = true} serde = { workspace = true, features = ["derive", "alloc"], optional = true } diff --git a/components/collator/Cargo.toml b/components/collator/Cargo.toml index 48fc7eebe86..f606102a57f 100644 --- a/components/collator/Cargo.toml +++ b/components/collator/Cargo.toml @@ -22,7 +22,7 @@ all-features = true displaydoc = { workspace = true } icu_collections = { workspace = true } icu_normalizer = { workspace = true } -icu_locale_core = { workspace = true } +icu_locale_core = { workspace = true, features = ["alloc"] } icu_properties = { workspace = true } icu_provider = { workspace = true, features = ["macros"] } utf8_iter = { workspace = true } diff --git a/components/collator/src/comparison.rs b/components/collator/src/comparison.rs index ffe4de5515f..0ce255bcb0f 100644 --- a/components/collator/src/comparison.rs +++ b/components/collator/src/comparison.rs @@ -129,10 +129,11 @@ impl LocaleSpecificDataHolder { .unwrap_or_default(); let data_locale = CollationTailoringV1::make_locale(prefs.locale_preferences); - let id = DataIdentifierCow::from_borrowed_and_owned(marker_attributes, data_locale); - let req = DataRequest { - id: id.as_borrowed(), + id: DataIdentifierBorrowed::for_marker_attributes_and_locale( + marker_attributes, + &data_locale, + ), metadata: { let mut metadata = DataRequestMetadata::default(); metadata.silent = true; @@ -140,11 +141,11 @@ impl LocaleSpecificDataHolder { }, }; - let fallback_id = - DataIdentifierCow::from_borrowed_and_owned(Default::default(), data_locale); - let fallback_req = DataRequest { - id: fallback_id.as_borrowed(), + id: DataIdentifierBorrowed::for_marker_attributes_and_locale( + Default::default(), + &data_locale, + ), ..Default::default() }; diff --git a/components/collator/src/lib.rs b/components/collator/src/lib.rs index edfd03bcf3d..96f20564dcd 100644 --- a/components/collator/src/lib.rs +++ b/components/collator/src/lib.rs @@ -317,8 +317,6 @@ mod elements; mod options; pub mod provider; -extern crate alloc; - pub use comparison::Collator; pub use comparison::CollatorBorrowed; pub use comparison::CollatorPreferences; diff --git a/components/collections/Cargo.toml b/components/collections/Cargo.toml index 45e436243c9..9205365a477 100644 --- a/components/collections/Cargo.toml +++ b/components/collections/Cargo.toml @@ -44,8 +44,9 @@ toml = { workspace = true } criterion = { workspace = true } [features] -serde = ["dep:serde", "zerovec/serde", "potential_utf/serde"] +serde = ["dep:serde", "zerovec/serde", "potential_utf/serde", "alloc"] databake = ["dep:databake", "zerovec/databake"] +alloc = ["zerovec/alloc"] [lib] bench = false # This option is required for Benchmark CI diff --git a/components/collections/src/codepointinvlist/conversions.rs b/components/collections/src/codepointinvlist/conversions.rs index 3cd25e37ac5..9e4cb380c7b 100644 --- a/components/collections/src/codepointinvlist/conversions.rs +++ b/components/collections/src/codepointinvlist/conversions.rs @@ -2,15 +2,16 @@ // called LICENSE at the top level of the ICU4X source tree // (online at: https://github.com/unicode-org/icu4x/blob/main/LICENSE ). +use core::iter::FromIterator; use core::{ convert::TryFrom, - iter::FromIterator, ops::{Range, RangeBounds, RangeFrom, RangeFull, RangeInclusive, RangeTo, RangeToInclusive}, }; use super::RangeError; use crate::codepointinvlist::utils::deconstruct_range; -use crate::codepointinvlist::{CodePointInversionList, CodePointInversionListBuilder}; +use crate::codepointinvlist::CodePointInversionList; +use crate::codepointinvlist::CodePointInversionListBuilder; use potential_utf::PotentialCodePoint; use zerovec::ZeroVec; diff --git a/components/collections/src/codepointinvlist/cpinvlist.rs b/components/collections/src/codepointinvlist/cpinvlist.rs index c160571aaca..e3f132aaf90 100644 --- a/components/collections/src/codepointinvlist/cpinvlist.rs +++ b/components/collections/src/codepointinvlist/cpinvlist.rs @@ -6,6 +6,7 @@ use alloc::format; #[cfg(feature = "serde")] use alloc::string::String; +#[cfg(feature = "alloc")] use alloc::vec::Vec; use core::{char, ops::RangeBounds, ops::RangeInclusive}; use potential_utf::PotentialCodePoint; @@ -33,6 +34,7 @@ const ALL_VEC: ZeroVec = zerovec!(PotentialCodePoint; Potent #[zerovec::skip_derive(Ord)] #[zerovec::derive(Debug)] #[derive(Debug, Eq, PartialEq, Clone, Yokeable, ZeroFrom)] +#[cfg_attr(not(feature = "alloc"), zerovec::skip_derive(ZeroMapKV, ToOwned))] pub struct CodePointInversionList<'data> { // If we wanted to use an array to keep the memory on the stack, there is an unsafe nightly feature // https://doc.rust-lang.org/nightly/core/array/trait.FixedSizeArray.html @@ -231,7 +233,10 @@ impl<'data> CodePointInversionList<'data> { .sum::(); Ok(Self { inv_list, size }) } else { - Err(InvalidSetError(inv_list.to_vec())) + Err(InvalidSetError( + #[cfg(feature = "alloc")] + inv_list.to_vec(), + )) } } @@ -274,6 +279,7 @@ impl<'data> CodePointInversionList<'data> { /// /// assert!(!lists.iter().any(|set| set.contains32(0x40000))); /// ``` + #[cfg(feature = "alloc")] pub fn try_from_u32_inversion_list_slice(inv_list: &[u32]) -> Result { let inv_list_zv: ZeroVec = inv_list .iter() @@ -284,6 +290,7 @@ impl<'data> CodePointInversionList<'data> { } /// Attempts to convert this list into a fully-owned one. No-op if already fully owned + #[cfg(feature = "alloc")] pub fn into_owned(self) -> CodePointInversionList<'static> { CodePointInversionList { inv_list: self.inv_list.into_owned(), @@ -292,6 +299,7 @@ impl<'data> CodePointInversionList<'data> { } /// Returns an owned inversion list representing the current [`CodePointInversionList`] + #[cfg(feature = "alloc")] pub fn get_inversion_list_vec(&self) -> Vec { self.as_inversion_list().iter().map(u32::from).collect() } @@ -353,6 +361,7 @@ impl<'data> CodePointInversionList<'data> { /// Returns the inversion list as a slice /// /// Public only to the crate, not exposed to public + #[cfg(feature = "alloc")] pub(crate) fn as_inversion_list(&self) -> &ZeroVec { &self.inv_list } diff --git a/components/collections/src/codepointinvlist/mod.rs b/components/collections/src/codepointinvlist/mod.rs index 211b72e80a2..be4986a301d 100644 --- a/components/collections/src/codepointinvlist/mod.rs +++ b/components/collections/src/codepointinvlist/mod.rs @@ -55,14 +55,15 @@ extern crate alloc; +#[cfg(feature = "alloc")] #[macro_use] mod builder; +#[cfg(feature = "alloc")] mod conversions; mod cpinvlist; mod utils; -use alloc::vec::Vec; - +#[cfg(feature = "alloc")] pub use builder::CodePointInversionListBuilder; pub use cpinvlist::CodePointInversionList; pub use cpinvlist::CodePointInversionListULE; @@ -70,8 +71,10 @@ use displaydoc::Display; #[derive(Display, Debug)] /// A CodePointInversionList was constructed with an invalid inversion list -#[displaydoc("Invalid set: {0:?}")] -pub struct InvalidSetError(pub Vec); +#[cfg_attr(feature = "alloc", displaydoc("Invalid set: {0:?}"))] +pub struct InvalidSetError( + #[cfg(feature = "alloc")] pub alloc::vec::Vec, +); /// A CodePointInversionList was constructed from an invalid range #[derive(Display, Debug)] diff --git a/components/collections/src/codepointinvliststringlist/mod.rs b/components/collections/src/codepointinvliststringlist/mod.rs index d4a0c5e3ccf..2562cc5bc69 100644 --- a/components/collections/src/codepointinvliststringlist/mod.rs +++ b/components/collections/src/codepointinvliststringlist/mod.rs @@ -9,10 +9,12 @@ //! //! It is an implementation of the existing [ICU4C UnicodeSet API](https://unicode-org.github.io/icu-docs/apidoc/released/icu4c/classicu_1_1UnicodeSet.html). -use crate::codepointinvlist::{ - CodePointInversionList, CodePointInversionListBuilder, CodePointInversionListULE, -}; +#[cfg(feature = "alloc")] +use crate::codepointinvlist::CodePointInversionListBuilder; +use crate::codepointinvlist::{CodePointInversionList, CodePointInversionListULE}; +#[cfg(feature = "alloc")] use alloc::string::{String, ToString}; +#[cfg(feature = "alloc")] use alloc::vec::Vec; use displaydoc::Display; use yoke::Yokeable; @@ -27,6 +29,7 @@ use zerovec::{VarZeroSlice, VarZeroVec}; #[zerovec::skip_derive(Ord)] #[zerovec::derive(Debug)] #[derive(Debug, Eq, PartialEq, Clone, Yokeable, ZeroFrom)] +#[cfg_attr(not(feature = "alloc"), zerovec::skip_derive(ZeroMapKV, ToOwned))] // Valid to auto-derive Deserialize because the invariants are weakly held #[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))] #[cfg_attr(feature = "serde", zerovec::derive(Serialize, Deserialize, Debug))] @@ -79,16 +82,27 @@ impl<'data> CodePointInversionListAndStringList<'data> { let mut it = str_list.iter(); if let Some(mut x) = it.next() { if x.len() == 1 { - return Err(InvalidStringList::InvalidStringLength(x.to_string())); + return Err(InvalidStringList::InvalidStringLength( + #[cfg(feature = "alloc")] + x.to_string(), + )); } for y in it { if x.len() == 1 { - return Err(InvalidStringList::InvalidStringLength(x.to_string())); + return Err(InvalidStringList::InvalidStringLength( + #[cfg(feature = "alloc")] + x.to_string(), + )); } else if x == y { - return Err(InvalidStringList::StringListNotUnique(x.to_string())); + return Err(InvalidStringList::StringListNotUnique( + #[cfg(feature = "alloc")] + x.to_string(), + )); } else if x > y { return Err(InvalidStringList::StringListNotSorted( + #[cfg(feature = "alloc")] x.to_string(), + #[cfg(feature = "alloc")] y.to_string(), )); } @@ -216,6 +230,7 @@ impl<'data> CodePointInversionListAndStringList<'data> { } } +#[cfg(feature = "alloc")] impl<'a> FromIterator<&'a str> for CodePointInversionListAndStringList<'_> { fn from_iter(it: I) -> Self where @@ -253,14 +268,20 @@ impl<'a> FromIterator<&'a str> for CodePointInversionListAndStringList<'_> { #[derive(Display, Debug)] pub enum InvalidStringList { /// A string in the string list had an invalid length - #[displaydoc("Invalid string length for string: {0}")] - InvalidStringLength(String), + #[cfg_attr(feature = "alloc", displaydoc("Invalid string length for string: {0}"))] + InvalidStringLength(#[cfg(feature = "alloc")] String), /// A string in the string list appears more than once - #[displaydoc("String list has duplicate: {0}")] - StringListNotUnique(String), + #[cfg_attr(feature = "alloc", displaydoc("String list has duplicate: {0}"))] + StringListNotUnique(#[cfg(feature = "alloc")] String), /// Two strings in the string list compare to each other opposite of sorted order - #[displaydoc("Strings in string list not in sorted order: ({0}, {1})")] - StringListNotSorted(String, String), + #[cfg_attr( + feature = "alloc", + displaydoc("Strings in string list not in sorted order: ({0}, {1})") + )] + StringListNotSorted( + #[cfg(feature = "alloc")] String, + #[cfg(feature = "alloc")] String, + ), } #[cfg(test)] diff --git a/components/collections/src/codepointtrie/cptrie.rs b/components/collections/src/codepointtrie/cptrie.rs index 4354be10109..9229766282c 100644 --- a/components/collections/src/codepointtrie/cptrie.rs +++ b/components/collections/src/codepointtrie/cptrie.rs @@ -5,16 +5,19 @@ use crate::codepointtrie::error::Error; use crate::codepointtrie::impl_const::*; +#[cfg(feature = "alloc")] use crate::codepointinvlist::CodePointInversionList; use core::char::CharTryFromError; use core::convert::Infallible; use core::convert::TryFrom; use core::fmt::Display; +#[cfg(feature = "alloc")] use core::iter::FromIterator; use core::num::TryFromIntError; use core::ops::RangeInclusive; use yoke::Yokeable; use zerofrom::ZeroFrom; +#[cfg(feature = "alloc")] use zerovec::ule::UleError; use zerovec::ZeroVec; @@ -482,6 +485,7 @@ impl<'trie, T: TrieValue> CodePointTrie<'trie, T> { /// /// assert_eq!(planes_trie_i8.get32(0x30000), 3); /// ``` + #[cfg(feature = "alloc")] pub fn try_into_converted

(self) -> Result, UleError> where P: TrieValue, @@ -522,6 +526,7 @@ impl<'trie, T: TrieValue> CodePointTrie<'trie, T> { /// /// assert_eq!(planes_trie_u16.get32(0x30000), 3); /// ``` + #[cfg(feature = "alloc")] pub fn try_alloc_map_value( &self, mut f: impl FnMut(T) -> Result, @@ -1018,6 +1023,7 @@ impl<'trie, T: TrieValue> CodePointTrie<'trie, T> { /// assert!(sip.contains32(end)); /// assert!(!sip.contains32(end + 1)); /// ``` + #[cfg(feature = "alloc")] pub fn get_set_for_value(&self, value: T) -> CodePointInversionList<'static> { let value_ranges = self.iter_ranges_for_value(value); CodePointInversionList::from_iter(value_ranges) diff --git a/components/collections/src/lib.rs b/components/collections/src/lib.rs index 6904b847ae8..a20545d0887 100644 --- a/components/collections/src/lib.rs +++ b/components/collections/src/lib.rs @@ -33,6 +33,7 @@ )] #![warn(missing_docs)] +#[cfg(feature = "alloc")] extern crate alloc; pub mod char16trie; diff --git a/components/datetime/Cargo.toml b/components/datetime/Cargo.toml index f1b8b3af7ed..9a1d6e7e171 100644 --- a/components/datetime/Cargo.toml +++ b/components/datetime/Cargo.toml @@ -32,9 +32,9 @@ icu_provider = { workspace = true, features = ["macros"] } icu_timezone = { workspace = true } smallvec = { workspace = true } tinystr = { workspace = true, features = ["alloc", "zerovec"] } -potential_utf = { workspace = true, features = ["zerovec"] } +potential_utf = { workspace = true, features = ["alloc", "zerovec"] } writeable = { workspace = true } -zerovec = { workspace = true, features = ["yoke"] } +zerovec = { workspace = true, features = ["alloc", "yoke"] } serde = { workspace = true, features = ["derive", "alloc"], optional = true } databake = { workspace = true, features = ["derive"], optional = true} @@ -49,7 +49,7 @@ icu = { path = "../../components/icu", default-features = false } icu_benchmark_macros = { path = "../../tools/benchmark/macros" } icu_calendar = { path = "../calendar", features = ["ixdtf"] } icu_provider_adapters = { path = "../../provider/adapters" } -icu_provider_blob = { path = "../../provider/blob" } +icu_provider_blob = { path = "../../provider/blob", features = ["alloc"] } icu_timezone = { path = "../timezone", features = ["ixdtf"] } litemap = { path = "../../utils/litemap" } @@ -69,6 +69,7 @@ serde = [ "icu_decimal/serde", "icu_pattern/serde", "icu_plurals/serde", + "icu_provider/alloc", "icu_provider/serde", "icu_timezone/serde", "litemap?/serde", diff --git a/components/decimal/Cargo.toml b/components/decimal/Cargo.toml index ef90c23e75b..7f4c323902e 100644 --- a/components/decimal/Cargo.toml +++ b/components/decimal/Cargo.toml @@ -22,7 +22,7 @@ all-features = true [dependencies] displaydoc = { workspace = true } fixed_decimal = { workspace = true } -icu_provider = { workspace = true, features = ["macros"] } +icu_provider = { workspace = true, features = ["alloc", "macros"] } writeable = { workspace = true } zerovec = { workspace = true } databake = { workspace = true, features = ["derive"], optional = true} diff --git a/components/experimental/Cargo.toml b/components/experimental/Cargo.toml index 1fc73a455b6..4c677474cd2 100644 --- a/components/experimental/Cargo.toml +++ b/components/experimental/Cargo.toml @@ -31,9 +31,9 @@ icu_locale_core = { workspace = true } icu_decimal = { workspace = true } icu_list = { workspace = true } icu_locale = { workspace = true } -icu_normalizer = { workspace = true } +icu_normalizer = { workspace = true, features = ["alloc"] } icu_plurals = { workspace = true } -icu_properties = { workspace = true } +icu_properties = { workspace = true, features = ["alloc"] } databake = { workspace = true, optional = true, features = ["derive"] } either = { workspace = true } @@ -73,7 +73,7 @@ default = ["compiled_data"] compiled_data = ["dep:icu_experimental_data", "icu_decimal/compiled_data", "icu_list/compiled_data", "icu_plurals/compiled_data", "icu_properties/compiled_data", "icu_normalizer/compiled_data"] datagen = ["serde", "dep:databake", "zerovec/databake", "zerotrie/databake", "tinystr/databake", "icu_collections/databake", "log", "icu_pattern/databake", "icu_plurals/datagen", "icu_pattern/alloc"] ryu = ["fixed_decimal/ryu"] -serde = ["dep:serde", "zerovec/serde", "potential_utf/serde", "tinystr/serde", "icu_collections/serde", "icu_decimal/serde", "icu_list/serde", "icu_pattern/serde", "icu_plurals/serde", "icu_provider/serde", "zerotrie/serde", "icu_normalizer/serde"] +serde = ["dep:serde", "zerovec/serde", "potential_utf/serde", "tinystr/serde", "icu_collections/serde", "icu_decimal/serde", "icu_list/serde", "icu_pattern/serde", "icu_plurals/serde", "icu_provider/alloc", "icu_provider/serde", "zerotrie/serde", "icu_normalizer/serde"] [[bench]] name = "transliterate" diff --git a/components/icu/Cargo.toml b/components/icu/Cargo.toml index 9f6be562774..e165918a7d2 100644 --- a/components/icu/Cargo.toml +++ b/components/icu/Cargo.toml @@ -20,7 +20,7 @@ version.workspace = true all-features = true [dependencies] -icu_calendar = { workspace = true } +icu_calendar = { workspace = true, features = ["alloc"] } icu_casemap = { workspace = true } icu_collator = { workspace = true } icu_collections = { workspace = true } @@ -30,7 +30,7 @@ icu_list = { workspace = true } icu_locale = { workspace = true } icu_normalizer = { workspace = true } icu_plurals = { workspace = true } -icu_properties = { workspace = true } +icu_properties = { workspace = true, features = ["alloc"] } icu_segmenter = { workspace = true } icu_timezone = { workspace = true } icu_experimental = { workspace = true, optional = true } @@ -46,7 +46,7 @@ icu_provider = { workspace = true } [dev-dependencies] icu_datetime = { path = "../../components/datetime", features = ["serde"] } icu_provider_adapters = { path = "../../provider/adapters", features = ["serde"] } -icu_provider_blob = { path = "../../provider/blob" } +icu_provider_blob = { path = "../../provider/blob", features = ["alloc"] } writeable = { path = "../../utils/writeable" } jiff = "0.1" diff --git a/components/list/Cargo.toml b/components/list/Cargo.toml index d33b3dc1660..9a8d50ba72f 100644 --- a/components/list/Cargo.toml +++ b/components/list/Cargo.toml @@ -20,7 +20,7 @@ all-features = true [dependencies] displaydoc = { workspace = true } -icu_provider = { workspace = true } +icu_provider = { workspace = true, features = ["alloc"] } regex-automata = { workspace = true, features = ["dfa-search"] } writeable = { workspace = true } @@ -39,7 +39,7 @@ serde_json = { workspace = true } [features] default = ["compiled_data"] -serde = ["dep:serde", "icu_provider/serde"] +serde = ["dep:serde", "icu_provider/serde", "icu_provider/alloc"] serde_human = ["serde", "regex-automata/dfa-build", "regex-automata/syntax"] datagen = ["serde", "dep:databake", "regex-automata/dfa-build", "regex-automata/syntax"] compiled_data = ["dep:icu_list_data"] diff --git a/components/locale/Cargo.toml b/components/locale/Cargo.toml index d58b4db5799..c25eddf5f7c 100644 --- a/components/locale/Cargo.toml +++ b/components/locale/Cargo.toml @@ -25,12 +25,12 @@ all-features = true [dependencies] databake = { workspace = true, optional = true, features = ["derive"] } displaydoc = { workspace = true } -icu_locale_core = { workspace = true, features = ["zerovec"] } +icu_locale_core = { workspace = true, features = ["alloc", "zerovec"] } icu_provider = { workspace = true, features = ["macros"] } serde = { workspace = true, features = ["derive", "alloc"], optional = true } tinystr = { workspace = true, features = ["alloc", "zerovec"] } -potential_utf = { workspace = true, features = ["zerovec"] } -zerovec = { workspace = true, features = ["yoke"] } +potential_utf = { workspace = true, features = ["alloc", "zerovec"] } +zerovec = { workspace = true, features = ["alloc", "yoke"] } icu_collections = { workspace = true } diff --git a/components/locale_core/Cargo.toml b/components/locale_core/Cargo.toml index 4a0c26954d4..52332b74f90 100644 --- a/components/locale_core/Cargo.toml +++ b/components/locale_core/Cargo.toml @@ -45,9 +45,10 @@ serde_json = { workspace = true } criterion = { workspace = true } [features] -databake = ["dep:databake"] -serde = ["dep:serde", "tinystr/serde"] +databake = ["dep:databake", "alloc"] +serde = ["dep:serde", "tinystr/serde", "alloc"] zerovec = ["dep:zerovec", "tinystr/zerovec"] +alloc = [] [lib] bench = false # This option is required for Benchmark CI diff --git a/components/locale_core/src/data.rs b/components/locale_core/src/data.rs index 0d9768835e5..3369a07b459 100644 --- a/components/locale_core/src/data.rs +++ b/components/locale_core/src/data.rs @@ -4,11 +4,14 @@ use crate::extensions::unicode as unicode_ext; use crate::subtags::{Language, Region, Script, Subtag, Variant}; -use crate::{LanguageIdentifier, Locale, ParseError}; +#[cfg(feature = "alloc")] +use crate::ParseError; +use crate::{LanguageIdentifier, Locale}; use core::cmp::Ordering; use core::default::Default; use core::fmt; use core::hash::Hash; +#[cfg(feature = "alloc")] use core::str::FromStr; /// A locale type optimized for use in fallbacking and the ICU4X data pipeline. @@ -126,6 +129,7 @@ impl From<&Locale> for DataLocale { } } +#[cfg(feature = "alloc")] impl FromStr for DataLocale { type Err = ParseError; #[inline] @@ -137,11 +141,13 @@ impl FromStr for DataLocale { impl DataLocale { #[inline] /// Parses a [`DataLocale`]. + #[cfg(feature = "alloc")] pub fn try_from_str(s: &str) -> Result { Self::try_from_utf8(s.as_bytes()) } /// Parses a [`DataLocale`] from a UTF-8 byte slice. + #[cfg(feature = "alloc")] pub fn try_from_utf8(code_units: &[u8]) -> Result { let locale = Locale::try_from_utf8(code_units)?; if locale.id.variants.len() > 1 diff --git a/components/locale_core/src/extensions/mod.rs b/components/locale_core/src/extensions/mod.rs index c1bb48a375f..1893ad7349e 100644 --- a/components/locale_core/src/extensions/mod.rs +++ b/components/locale_core/src/extensions/mod.rs @@ -64,9 +64,11 @@ use private::{Private, PRIVATE_EXT_CHAR}; use transform::{Transform, TRANSFORM_EXT_CHAR}; use unicode::{Unicode, UNICODE_EXT_CHAR}; +#[cfg(feature = "alloc")] use alloc::vec::Vec; use crate::parser::ParseError; +#[cfg(feature = "alloc")] use crate::parser::SubtagIterator; use crate::subtags; @@ -85,6 +87,7 @@ pub enum ExtensionType { } impl ExtensionType { + #[allow(dead_code)] pub(crate) const fn try_from_byte_slice(key: &[u8]) -> Result { if let [b] = key { Self::try_from_byte(*b) @@ -126,7 +129,13 @@ pub struct Extensions { /// A sequence of any other extensions that are present in the locale identifier but are not formally /// [defined](https://unicode.org/reports/tr35/) and represented explicitly as [`Unicode`], [`Transform`], /// and [`Private`] are. + #[cfg(feature = "alloc")] pub other: Vec, + /// A sequence of any other extensions that are present in the locale identifier but are not formally + /// [defined](https://unicode.org/reports/tr35/) and represented explicitly as [`Unicode`], [`Transform`], + /// and [`Private`] are. + #[cfg(not(feature = "alloc"))] + pub other: &'static [Other], } impl Extensions { @@ -145,7 +154,10 @@ impl Extensions { unicode: Unicode::new(), transform: Transform::new(), private: Private::new(), + #[cfg(feature = "alloc")] other: Vec::new(), + #[cfg(not(feature = "alloc"))] + other: &[], } } @@ -157,7 +169,10 @@ impl Extensions { unicode, transform: Transform::new(), private: Private::new(), + #[cfg(feature = "alloc")] other: Vec::new(), + #[cfg(not(feature = "alloc"))] + other: &[], } } @@ -250,10 +265,12 @@ impl Extensions { if !predicate(ExtensionType::Private) { self.private.clear(); } + #[cfg(feature = "alloc")] self.other .retain(|o| predicate(ExtensionType::Other(o.get_ext_byte()))); } + #[cfg(feature = "alloc")] pub(crate) fn try_from_iter(iter: &mut SubtagIterator) -> Result { let mut unicode = None; let mut transform = None; @@ -343,6 +360,7 @@ impl Extensions { } } +#[cfg(feature = "alloc")] impl_writeable_for_each_subtag_str_no_test!(Extensions); #[test] diff --git a/components/locale_core/src/extensions/other/mod.rs b/components/locale_core/src/extensions/other/mod.rs index 4a27efcbe7b..050b379c6da 100644 --- a/components/locale_core/src/extensions/other/mod.rs +++ b/components/locale_core/src/extensions/other/mod.rs @@ -19,13 +19,18 @@ //! let mut loc: Locale = "en-US-a-foo-faa".parse().expect("Parsing failed."); //! ``` +#[cfg(feature = "alloc")] use core::str::FromStr; +#[cfg(feature = "alloc")] use super::ExtensionType; +#[cfg(feature = "alloc")] use crate::parser::ParseError; +#[cfg(feature = "alloc")] use crate::parser::SubtagIterator; use crate::shortvec::ShortBoxSlice; use crate::subtags::Subtag; +#[cfg(feature = "alloc")] use alloc::vec::Vec; /// A list of [`Other Use Extensions`] as defined in [`Unicode Locale @@ -60,11 +65,13 @@ impl Other { /// A constructor which takes a str slice, parses it and /// produces a well-formed [`Other`]. #[inline] + #[cfg(feature = "alloc")] pub fn try_from_str(s: &str) -> Result { Self::try_from_utf8(s.as_bytes()) } /// See [`Self::try_from_str`] + #[cfg(feature = "alloc")] pub fn try_from_utf8(code_units: &[u8]) -> Result { let mut iter = SubtagIterator::new(code_units); @@ -94,16 +101,19 @@ impl Other { /// let other = Other::from_vec_unchecked(b'a', vec![subtag1, subtag2]); /// assert_eq!(&other.to_string(), "a-foo-bar"); /// ``` + #[cfg(feature = "alloc")] pub fn from_vec_unchecked(ext: u8, keys: Vec) -> Self { Self::from_short_slice_unchecked(ext, keys.into()) } + #[allow(dead_code)] pub(crate) fn from_short_slice_unchecked(ext: u8, keys: ShortBoxSlice) -> Self { assert!(ext.is_ascii_alphabetic()); // Safety invariant upheld here: ext checked as ASCII above Self { ext, keys } } + #[cfg(feature = "alloc")] pub(crate) fn try_from_iter(ext: u8, iter: &mut SubtagIterator) -> Result { debug_assert!(matches!( ExtensionType::try_from_byte(ext), @@ -190,6 +200,7 @@ impl Other { } } +#[cfg(feature = "alloc")] impl FromStr for Other { type Err = ParseError; @@ -226,6 +237,7 @@ impl writeable::Writeable for Other { result } + #[cfg(feature = "alloc")] fn write_to_string(&self) -> alloc::borrow::Cow { if self.keys.is_empty() { return alloc::borrow::Cow::Borrowed(""); diff --git a/components/locale_core/src/extensions/private/mod.rs b/components/locale_core/src/extensions/private/mod.rs index 0e686cbe9bb..ee9852921af 100644 --- a/components/locale_core/src/extensions/private/mod.rs +++ b/components/locale_core/src/extensions/private/mod.rs @@ -29,15 +29,20 @@ mod other; +#[cfg(feature = "alloc")] use alloc::vec::Vec; use core::ops::Deref; +#[cfg(feature = "alloc")] use core::str::FromStr; #[doc(inline)] pub use other::{subtag, Subtag}; +#[cfg(feature = "alloc")] use super::ExtensionType; +#[cfg(feature = "alloc")] use crate::parser::ParseError; +#[cfg(feature = "alloc")] use crate::parser::SubtagIterator; use crate::shortvec::ShortBoxSlice; @@ -85,11 +90,13 @@ impl Private { /// A constructor which takes a str slice, parses it and /// produces a well-formed [`Private`]. #[inline] + #[cfg(feature = "alloc")] pub fn try_from_str(s: &str) -> Result { Self::try_from_utf8(s.as_bytes()) } /// See [`Self::try_from_str`] + #[cfg(feature = "alloc")] pub fn try_from_utf8(code_units: &[u8]) -> Result { let mut iter = SubtagIterator::new(code_units); @@ -114,6 +121,7 @@ impl Private { /// let private = Private::from_vec_unchecked(vec![subtag1, subtag2]); /// assert_eq!(&private.to_string(), "x-foo-bar"); /// ``` + #[cfg(feature = "alloc")] pub fn from_vec_unchecked(input: Vec) -> Self { Self(input.into()) } @@ -155,6 +163,7 @@ impl Private { self.0.clear(); } + #[cfg(feature = "alloc")] pub(crate) fn try_from_iter(iter: &mut SubtagIterator) -> Result { let keys = iter .map(Subtag::try_from_utf8) @@ -181,6 +190,7 @@ impl Private { } } +#[cfg(feature = "alloc")] impl FromStr for Private { type Err = ParseError; diff --git a/components/locale_core/src/extensions/transform/mod.rs b/components/locale_core/src/extensions/transform/mod.rs index b4541e7be02..8f3094f1bf2 100644 --- a/components/locale_core/src/extensions/transform/mod.rs +++ b/components/locale_core/src/extensions/transform/mod.rs @@ -35,6 +35,7 @@ mod key; mod value; use core::cmp::Ordering; +#[cfg(feature = "alloc")] use core::str::FromStr; pub use fields::Fields; @@ -42,12 +43,19 @@ pub use fields::Fields; pub use key::{key, Key}; pub use value::Value; +#[cfg(feature = "alloc")] use super::ExtensionType; +#[cfg(feature = "alloc")] use crate::parser::SubtagIterator; +#[cfg(feature = "alloc")] use crate::parser::{parse_language_identifier_from_iter, ParseError, ParserMode}; +#[cfg(feature = "alloc")] use crate::shortvec::ShortBoxSlice; -use crate::subtags::{self, Language}; +use crate::subtags; +#[cfg(feature = "alloc")] +use crate::subtags::Language; use crate::LanguageIdentifier; +#[cfg(feature = "alloc")] use litemap::LiteMap; pub(crate) const TRANSFORM_EXT_CHAR: char = 't'; @@ -110,11 +118,13 @@ impl Transform { /// A constructor which takes a str slice, parses it and /// produces a well-formed [`Transform`]. #[inline] + #[cfg(feature = "alloc")] pub fn try_from_str(s: &str) -> Result { Self::try_from_utf8(s.as_bytes()) } /// See [`Self::try_from_str`] + #[cfg(feature = "alloc")] pub fn try_from_utf8(code_units: &[u8]) -> Result { let mut iter = SubtagIterator::new(code_units); @@ -182,6 +192,7 @@ impl Transform { self.as_tuple().cmp(&other.as_tuple()) } + #[cfg(feature = "alloc")] pub(crate) fn try_from_iter(iter: &mut SubtagIterator) -> Result { let mut tlang = None; let mut tfields = LiteMap::new(); @@ -259,6 +270,7 @@ impl Transform { } } +#[cfg(feature = "alloc")] impl FromStr for Transform { type Err = ParseError; diff --git a/components/locale_core/src/extensions/transform/value.rs b/components/locale_core/src/extensions/transform/value.rs index 4d5936937e1..3a54f739dd1 100644 --- a/components/locale_core/src/extensions/transform/value.rs +++ b/components/locale_core/src/extensions/transform/value.rs @@ -2,10 +2,13 @@ // called LICENSE at the top level of the ICU4X source tree // (online at: https://github.com/unicode-org/icu4x/blob/main/LICENSE ). -use crate::parser::{ParseError, SubtagIterator}; +use crate::parser::ParseError; +#[cfg(feature = "alloc")] +use crate::parser::SubtagIterator; use crate::shortvec::ShortBoxSlice; use crate::subtags::{subtag, Subtag}; use core::ops::RangeInclusive; +#[cfg(feature = "alloc")] use core::str::FromStr; /// A value used in a list of [`Fields`](super::Fields). @@ -29,6 +32,7 @@ use core::str::FromStr; #[derive(Debug, PartialEq, Eq, Clone, Hash, PartialOrd, Ord, Default)] pub struct Value(ShortBoxSlice); +#[allow(dead_code)] const TYPE_LENGTH: RangeInclusive = 3..=8; const TRUE_TVALUE: Subtag = subtag!("true"); @@ -44,11 +48,13 @@ impl Value { /// let value = Value::try_from_str("hybrid").expect("Parsing failed."); /// ``` #[inline] + #[cfg(feature = "alloc")] pub fn try_from_str(s: &str) -> Result { Self::try_from_utf8(s.as_bytes()) } /// See [`Self::try_from_str`] + #[cfg(feature = "alloc")] pub fn try_from_utf8(code_units: &[u8]) -> Result { let mut v = ShortBoxSlice::default(); let mut has_value = false; @@ -70,14 +76,17 @@ impl Value { Ok(Self(v)) } + #[allow(dead_code)] pub(crate) fn from_short_slice_unchecked(input: ShortBoxSlice) -> Self { Self(input) } + #[allow(dead_code)] pub(crate) fn is_type_subtag(t: &[u8]) -> bool { TYPE_LENGTH.contains(&t.len()) && t.iter().all(u8::is_ascii_alphanumeric) } + #[allow(dead_code)] pub(crate) fn parse_subtag(t: &[u8]) -> Result, ParseError> { if !TYPE_LENGTH.contains(&t.len()) { return Err(ParseError::InvalidExtension); @@ -106,6 +115,7 @@ impl Value { } } +#[cfg(feature = "alloc")] impl FromStr for Value { type Err = ParseError; diff --git a/components/locale_core/src/extensions/unicode/attributes.rs b/components/locale_core/src/extensions/unicode/attributes.rs index 3ef583a7553..7ca0fecfcfc 100644 --- a/components/locale_core/src/extensions/unicode/attributes.rs +++ b/components/locale_core/src/extensions/unicode/attributes.rs @@ -4,11 +4,15 @@ use super::Attribute; +#[cfg(feature = "alloc")] use crate::parser::SubtagIterator; use crate::shortvec::ShortBoxSlice; +#[cfg(feature = "alloc")] use crate::ParseError; +#[cfg(feature = "alloc")] use alloc::vec::Vec; use core::ops::Deref; +#[cfg(feature = "alloc")] use core::str::FromStr; /// A set of [`Attribute`] elements as defined in [`Unicode Extension Attributes`]. @@ -54,11 +58,13 @@ impl Attributes { /// A constructor which takes a str slice, parses it and /// produces a well-formed [`Attributes`]. #[inline] + #[cfg(feature = "alloc")] pub fn try_from_str(s: &str) -> Result { Self::try_from_utf8(s.as_bytes()) } /// See [`Self::try_from_str`] + #[cfg(feature = "alloc")] pub fn try_from_utf8(code_units: &[u8]) -> Result { let mut iter = SubtagIterator::new(code_units); Self::try_from_iter(&mut iter) @@ -84,6 +90,7 @@ impl Attributes { /// Notice: For performance- and memory-constrained environments, it is recommended /// for the caller to use [`binary_search`](slice::binary_search) instead of [`sort`](slice::sort) /// and [`dedup`](Vec::dedup()). + #[cfg(feature = "alloc")] pub fn from_vec_unchecked(input: Vec) -> Self { Self(input.into()) } @@ -113,6 +120,7 @@ impl Attributes { core::mem::take(self) } + #[cfg(feature = "alloc")] pub(crate) fn try_from_iter(iter: &mut SubtagIterator) -> Result { let mut attributes = ShortBoxSlice::new(); @@ -137,6 +145,7 @@ impl Attributes { } } +#[cfg(feature = "alloc")] impl FromStr for Attributes { type Err = ParseError; diff --git a/components/locale_core/src/extensions/unicode/keywords.rs b/components/locale_core/src/extensions/unicode/keywords.rs index fd2689b500c..192674fdc6c 100644 --- a/components/locale_core/src/extensions/unicode/keywords.rs +++ b/components/locale_core/src/extensions/unicode/keywords.rs @@ -4,13 +4,17 @@ use core::borrow::Borrow; use core::cmp::Ordering; +#[cfg(feature = "alloc")] use core::iter::FromIterator; +#[cfg(feature = "alloc")] use core::str::FromStr; use litemap::LiteMap; use super::Key; use super::Value; +#[cfg(feature = "alloc")] use crate::parser::ParseError; +#[cfg(feature = "alloc")] use crate::parser::SubtagIterator; use crate::shortvec::ShortBoxSlice; @@ -93,11 +97,13 @@ impl Keywords { /// A constructor which takes a str slice, parses it and /// produces a well-formed [`Keywords`]. #[inline] + #[cfg(feature = "alloc")] pub fn try_from_str(s: &str) -> Result { Self::try_from_utf8(s.as_bytes()) } /// See [`Self::try_from_str`] + #[cfg(feature = "alloc")] pub fn try_from_utf8(code_units: &[u8]) -> Result { let mut iter = SubtagIterator::new(code_units); Self::try_from_iter(&mut iter) @@ -183,6 +189,7 @@ impl Keywords { /// } /// assert_eq!(keywords.get(&key!("ca")), Some(&value!("gregory"))); /// ``` + #[cfg(feature = "alloc")] pub fn get_mut(&mut self, key: &Q) -> Option<&mut Value> where Key: Borrow, @@ -211,6 +218,7 @@ impl Keywords { /// assert_eq!(old_value, Some(value!("buddhist"))); /// assert_eq!(loc, "und-u-hello-ca-japanese-hc-h12".parse().unwrap()); /// ``` + #[cfg(feature = "alloc")] pub fn set(&mut self, key: Key, value: Value) -> Option { self.0.insert(key, value) } @@ -229,6 +237,7 @@ impl Keywords { /// loc.extensions.unicode.keywords.remove(key!("ca")); /// assert_eq!(loc, "und-u-hello-hc-h12".parse().unwrap()); /// ``` + #[cfg(feature = "alloc")] pub fn remove>(&mut self, key: Q) -> Option { self.0.remove(key.borrow()) } @@ -272,6 +281,7 @@ impl Keywords { /// .retain_by_key(|&k| k == key!("ms")); /// assert_eq!(loc, Locale::default()); /// ``` + #[cfg(feature = "alloc")] pub fn retain_by_key(&mut self, mut predicate: F) where F: FnMut(&Key) -> bool, @@ -314,6 +324,7 @@ impl Keywords { writeable::cmp_utf8(self, other) } + #[cfg(feature = "alloc")] pub(crate) fn try_from_iter(iter: &mut SubtagIterator) -> Result { let mut keywords = LiteMap::new(); @@ -376,12 +387,14 @@ impl From>> for Keywords { } } +#[cfg(feature = "alloc")] impl FromIterator<(Key, Value)> for Keywords { fn from_iter>(iter: I) -> Self { LiteMap::from_iter(iter).into() } } +#[cfg(feature = "alloc")] impl FromStr for Keywords { type Err = ParseError; diff --git a/components/locale_core/src/extensions/unicode/mod.rs b/components/locale_core/src/extensions/unicode/mod.rs index dae54f9167d..f51593548ba 100644 --- a/components/locale_core/src/extensions/unicode/mod.rs +++ b/components/locale_core/src/extensions/unicode/mod.rs @@ -34,6 +34,7 @@ mod subdivision; mod value; use core::cmp::Ordering; +#[cfg(feature = "alloc")] use core::str::FromStr; #[doc(inline)] @@ -47,8 +48,11 @@ pub use subdivision::{subdivision_suffix, SubdivisionId, SubdivisionSuffix}; #[doc(inline)] pub use value::{value, Value}; +#[cfg(feature = "alloc")] use super::ExtensionType; +#[cfg(feature = "alloc")] use crate::parser::ParseError; +#[cfg(feature = "alloc")] use crate::parser::SubtagIterator; pub(crate) const UNICODE_EXT_CHAR: char = 'u'; @@ -112,11 +116,13 @@ impl Unicode { /// A constructor which takes a str slice, parses it and /// produces a well-formed [`Unicode`]. #[inline] + #[cfg(feature = "alloc")] pub fn try_from_str(s: &str) -> Result { Self::try_from_utf8(s.as_bytes()) } /// See [`Self::try_from_str`] + #[cfg(feature = "alloc")] pub fn try_from_utf8(code_units: &[u8]) -> Result { let mut iter = SubtagIterator::new(code_units); @@ -175,6 +181,7 @@ impl Unicode { self.as_tuple().cmp(&other.as_tuple()) } + #[cfg(feature = "alloc")] pub(crate) fn try_from_iter(iter: &mut SubtagIterator) -> Result { let attributes = Attributes::try_from_iter(iter)?; let keywords = Keywords::try_from_iter(iter)?; @@ -205,6 +212,7 @@ impl Unicode { } } +#[cfg(feature = "alloc")] impl FromStr for Unicode { type Err = ParseError; diff --git a/components/locale_core/src/extensions/unicode/value.rs b/components/locale_core/src/extensions/unicode/value.rs index 818659909a3..5f0856af606 100644 --- a/components/locale_core/src/extensions/unicode/value.rs +++ b/components/locale_core/src/extensions/unicode/value.rs @@ -2,10 +2,14 @@ // called LICENSE at the top level of the ICU4X source tree // (online at: https://github.com/unicode-org/icu4x/blob/main/LICENSE ). -use crate::parser::{ParseError, SubtagIterator}; +use crate::parser::ParseError; +#[cfg(feature = "alloc")] +use crate::parser::SubtagIterator; use crate::shortvec::{ShortBoxSlice, ShortBoxSliceIntoIter}; use crate::subtags::{subtag, Subtag}; +#[cfg(feature = "alloc")] use alloc::vec::Vec; +#[cfg(feature = "alloc")] use core::str::FromStr; /// A value used in a list of [`Keywords`](super::Keywords). @@ -48,11 +52,13 @@ impl Value { /// Value::try_from_str("buddhist").expect("Parsing failed."); /// ``` #[inline] + #[cfg(feature = "alloc")] pub fn try_from_str(s: &str) -> Result { Self::try_from_utf8(s.as_bytes()) } /// See [`Self::try_from_str`] + #[cfg(feature = "alloc")] pub fn try_from_utf8(code_units: &[u8]) -> Result { let mut v = ShortBoxSlice::new(); @@ -122,6 +128,7 @@ impl Value { /// v.push_subtag(subtag!("bar")); /// assert_eq!(v, "foo-bar"); /// ``` + #[cfg(feature = "alloc")] pub fn push_subtag(&mut self, subtag: Subtag) { self.0.push(subtag); } @@ -240,10 +247,12 @@ impl Value { /// Notice: For performance- and memory-constrained environments, it is recommended /// for the caller to use [`binary_search`](slice::binary_search) instead of [`sort`](slice::sort) /// and [`dedup`](Vec::dedup()). + #[cfg(feature = "alloc")] pub fn from_vec_unchecked(input: Vec) -> Self { Self(input.into()) } + #[allow(dead_code)] pub(crate) fn from_short_slice_unchecked(input: ShortBoxSlice) -> Self { Self(input) } @@ -274,12 +283,14 @@ impl IntoIterator for Value { } } +#[cfg(feature = "alloc")] impl FromIterator for Value { fn from_iter>(iter: T) -> Self { Self(ShortBoxSlice::from_iter(iter)) } } +#[cfg(feature = "alloc")] impl Extend for Value { fn extend>(&mut self, iter: T) { for i in iter { @@ -288,6 +299,7 @@ impl Extend for Value { } } +#[cfg(feature = "alloc")] impl FromStr for Value { type Err = ParseError; diff --git a/components/locale_core/src/helpers.rs b/components/locale_core/src/helpers.rs index 67cc5f6797e..dc235769b11 100644 --- a/components/locale_core/src/helpers.rs +++ b/components/locale_core/src/helpers.rs @@ -158,6 +158,7 @@ macro_rules! impl_tinystr_subtag { writeable::LengthHint::exact(self.0.len()) } #[inline] + #[cfg(feature = "alloc")] fn write_to_string(&self) -> alloc::borrow::Cow { alloc::borrow::Cow::Borrowed(self.0.as_str()) } @@ -362,6 +363,7 @@ macro_rules! impl_writeable_for_each_subtag_str_no_test { } $( + #[cfg(feature = "alloc")] fn write_to_string(&self) -> alloc::borrow::Cow { #[allow(clippy::unwrap_used)] // impl_writeable_for_subtag_list's $borrow uses unwrap let $self = self; diff --git a/components/locale_core/src/langid.rs b/components/locale_core/src/langid.rs index 50142fd8b1e..d331cd41eb1 100644 --- a/components/locale_core/src/langid.rs +++ b/components/locale_core/src/langid.rs @@ -3,13 +3,13 @@ // (online at: https://github.com/unicode-org/icu4x/blob/main/LICENSE ). use core::cmp::Ordering; +#[cfg(feature = "alloc")] use core::str::FromStr; -use crate::parser::{ - parse_language_identifier, parse_language_identifier_with_single_variant, ParseError, - ParserMode, SubtagIterator, -}; +use crate::parser; use crate::subtags; +use crate::ParseError; +#[cfg(feature = "alloc")] use alloc::borrow::Cow; /// A core struct representing a [`Unicode BCP47 Language Identifier`]. @@ -100,13 +100,15 @@ impl LanguageIdentifier { /// LanguageIdentifier::try_from_str("en-US").expect("Parsing failed"); /// ``` #[inline] + #[cfg(feature = "alloc")] pub fn try_from_str(s: &str) -> Result { Self::try_from_utf8(s.as_bytes()) } /// See [`Self::try_from_str`] + #[cfg(feature = "alloc")] pub fn try_from_utf8(code_units: &[u8]) -> Result { - parse_language_identifier(code_units, ParserMode::LanguageIdentifier) + crate::parser::parse_language_identifier(code_units, parser::ParserMode::LanguageIdentifier) } #[doc(hidden)] // macro use @@ -124,7 +126,10 @@ impl LanguageIdentifier { ), ParseError, > { - parse_language_identifier_with_single_variant(code_units, ParserMode::LanguageIdentifier) + crate::parser::parse_language_identifier_with_single_variant( + code_units, + parser::ParserMode::LanguageIdentifier, + ) } /// A constructor which takes a utf8 slice which may contain extension keys, @@ -143,8 +148,9 @@ impl LanguageIdentifier { /// /// This method should be used for input that may be a locale identifier. /// All extensions will be lost. + #[cfg(feature = "alloc")] pub fn try_from_locale_bytes(v: &[u8]) -> Result { - parse_language_identifier(v, ParserMode::Locale) + parser::parse_language_identifier(v, parser::ParserMode::Locale) } /// Const-friendly version of [`Default::default`]. @@ -179,6 +185,7 @@ impl LanguageIdentifier { /// Ok("pl-Latn-PL") /// ); /// ``` + #[cfg(feature = "alloc")] pub fn normalize_utf8(input: &[u8]) -> Result, ParseError> { let lang_id = Self::try_from_utf8(input)?; Ok(writeable::to_string_or_borrow(&lang_id, input)) @@ -198,6 +205,7 @@ impl LanguageIdentifier { /// Ok("pl-Latn-PL") /// ); /// ``` + #[cfg(feature = "alloc")] pub fn normalize(input: &str) -> Result, ParseError> { Self::normalize_utf8(input.as_bytes()) } @@ -380,7 +388,7 @@ impl LanguageIdentifier { }; } - let mut iter = SubtagIterator::new(other.as_bytes()); + let mut iter = parser::SubtagIterator::new(other.as_bytes()); if !subtag_matches!(subtags::Language, iter, self.language) { return false; } @@ -494,6 +502,7 @@ impl core::fmt::Debug for LanguageIdentifier { } } +#[cfg(feature = "alloc")] impl FromStr for LanguageIdentifier { type Err = ParseError; diff --git a/components/locale_core/src/lib.rs b/components/locale_core/src/lib.rs index 5d7b1a63f14..8e8a130411c 100644 --- a/components/locale_core/src/lib.rs +++ b/components/locale_core/src/lib.rs @@ -65,6 +65,7 @@ )] #![warn(missing_docs)] +#[cfg(feature = "alloc")] extern crate alloc; #[macro_use] @@ -80,7 +81,7 @@ mod shortvec; pub use data::DataLocale; pub use langid::LanguageIdentifier; pub use locale::Locale; -pub use parser::errors::ParseError; +pub use parser::ParseError; pub mod extensions; #[macro_use] diff --git a/components/locale_core/src/locale.rs b/components/locale_core/src/locale.rs index 303f0166e71..1dca4f14e73 100644 --- a/components/locale_core/src/locale.rs +++ b/components/locale_core/src/locale.rs @@ -2,14 +2,13 @@ // called LICENSE at the top level of the ICU4X source tree // (online at: https://github.com/unicode-org/icu4x/blob/main/LICENSE ). -use crate::parser::{ - parse_locale, parse_locale_with_single_variant_single_keyword_unicode_keyword_extension, - ParseError, ParserMode, SubtagIterator, -}; +use crate::parser::*; use crate::subtags::Subtag; use crate::{extensions, subtags, LanguageIdentifier}; +#[cfg(feature = "alloc")] use alloc::borrow::Cow; use core::cmp::Ordering; +#[cfg(feature = "alloc")] use core::str::FromStr; /// A core struct representing a [`Unicode Locale Identifier`]. @@ -133,11 +132,13 @@ impl Locale { /// Locale::try_from_str("en-US-u-hc-h12").unwrap(); /// ``` #[inline] + #[cfg(feature = "alloc")] pub fn try_from_str(s: &str) -> Result { Self::try_from_utf8(s.as_bytes()) } /// See [`Self::try_from_str`] + #[cfg(feature = "alloc")] pub fn try_from_utf8(code_units: &[u8]) -> Result { parse_locale(code_units) } @@ -164,6 +165,7 @@ impl Locale { /// Ok("pl-Latn-PL-u-hc-h12") /// ); /// ``` + #[cfg(feature = "alloc")] pub fn normalize_utf8(input: &[u8]) -> Result, ParseError> { let locale = Self::try_from_utf8(input)?; Ok(writeable::to_string_or_borrow(&locale, input)) @@ -183,6 +185,7 @@ impl Locale { /// Ok("pl-Latn-PL-u-hc-h12") /// ); /// ``` + #[cfg(feature = "alloc")] pub fn normalize(input: &str) -> Result, ParseError> { Self::normalize_utf8(input.as_bytes()) } @@ -378,6 +381,7 @@ impl Locale { /// assert!(a.parse::().unwrap().normalizing_eq(a)); /// } /// ``` + #[cfg(feature = "alloc")] pub fn normalizing_eq(&self, other: &str) -> bool { macro_rules! subtag_matches { ($T:ty, $iter:ident, $expected:expr) => { @@ -452,6 +456,7 @@ impl Locale { } } +#[cfg(feature = "alloc")] impl FromStr for Locale { type Err = ParseError; diff --git a/components/locale_core/src/parser/langid.rs b/components/locale_core/src/parser/langid.rs index 68f77ca6274..48b6159f5e7 100644 --- a/components/locale_core/src/parser/langid.rs +++ b/components/locale_core/src/parser/langid.rs @@ -6,8 +6,10 @@ pub use super::errors::ParseError; use crate::extensions::unicode::{Attribute, Key, Value}; use crate::extensions::ExtensionType; use crate::parser::SubtagIterator; +#[cfg(feature = "alloc")] use crate::shortvec::ShortBoxSlice; use crate::subtags::Subtag; +#[cfg(feature = "alloc")] use crate::LanguageIdentifier; use crate::{extensions, subtags}; @@ -15,6 +17,7 @@ use crate::{extensions, subtags}; pub enum ParserMode { LanguageIdentifier, Locale, + #[allow(dead_code)] Partial, } @@ -25,6 +28,7 @@ enum ParserPosition { Variant, } +#[cfg(feature = "alloc")] pub fn parse_language_identifier_from_iter( iter: &mut SubtagIterator, mode: ParserMode, @@ -99,6 +103,7 @@ pub fn parse_language_identifier_from_iter( }) } +#[cfg(feature = "alloc")] pub fn parse_language_identifier( t: &[u8], mode: ParserMode, diff --git a/components/locale_core/src/parser/locale.rs b/components/locale_core/src/parser/locale.rs index b1de3c422ce..e9794cdb842 100644 --- a/components/locale_core/src/parser/locale.rs +++ b/components/locale_core/src/parser/locale.rs @@ -2,24 +2,23 @@ // called LICENSE at the top level of the ICU4X source tree // (online at: https://github.com/unicode-org/icu4x/blob/main/LICENSE ). -use crate::extensions::{self, Extensions}; -use crate::parser::errors::ParseError; -use crate::parser::{parse_language_identifier_from_iter, ParserMode, SubtagIterator}; -use crate::{ - subtags::{self, Subtag}, - Locale, -}; +use crate::extensions; +use crate::parser::{ParseError, ParserMode, SubtagIterator}; +use crate::subtags::{self, Subtag}; +#[cfg(feature = "alloc")] +use crate::Locale; use super::parse_locale_with_single_variant_single_keyword_unicode_extension_from_iter; +#[cfg(feature = "alloc")] pub fn parse_locale(t: &[u8]) -> Result { let mut iter = SubtagIterator::new(t); - let id = parse_language_identifier_from_iter(&mut iter, ParserMode::Locale)?; + let id = super::parse_language_identifier_from_iter(&mut iter, ParserMode::Locale)?; let extensions = if iter.peek().is_some() { - Extensions::try_from_iter(&mut iter)? + extensions::Extensions::try_from_iter(&mut iter)? } else { - Extensions::default() + extensions::Extensions::default() }; Ok(Locale { id, extensions }) } diff --git a/components/locale_core/src/parser/mod.rs b/components/locale_core/src/parser/mod.rs index c2b171849c8..8ef5c6a4d84 100644 --- a/components/locale_core/src/parser/mod.rs +++ b/components/locale_core/src/parser/mod.rs @@ -7,15 +7,9 @@ mod langid; mod locale; pub use errors::ParseError; -pub use langid::{ - parse_language_identifier, parse_language_identifier_from_iter, - parse_language_identifier_with_single_variant, - parse_locale_with_single_variant_single_keyword_unicode_extension_from_iter, ParserMode, -}; - -pub use locale::{ - parse_locale, parse_locale_with_single_variant_single_keyword_unicode_keyword_extension, -}; +pub use langid::*; + +pub use locale::*; // Safety-usable invariant: returns a prefix of `slice` const fn skip_before_separator(slice: &[u8]) -> &[u8] { diff --git a/components/locale_core/src/preferences/extensions/unicode/mod.rs b/components/locale_core/src/preferences/extensions/unicode/mod.rs index 370a4382dc5..33a20e1567d 100644 --- a/components/locale_core/src/preferences/extensions/unicode/mod.rs +++ b/components/locale_core/src/preferences/extensions/unicode/mod.rs @@ -11,6 +11,7 @@ //! //! [`Locale`]: crate::Locale pub mod errors; +#[cfg(feature = "alloc")] pub mod keywords; mod macros; #[doc(inline)] diff --git a/components/locale_core/src/preferences/locale.rs b/components/locale_core/src/preferences/locale.rs index e4f7ba8dd2e..2aa8b53af4a 100644 --- a/components/locale_core/src/preferences/locale.rs +++ b/components/locale_core/src/preferences/locale.rs @@ -2,7 +2,9 @@ // called LICENSE at the top level of the ICU4X source tree // (online at: https://github.com/unicode-org/icu4x/blob/main/LICENSE ). -use crate::subtags::{Language, Region, Script, Subtag, Variant, Variants}; +#[cfg(feature = "alloc")] +use crate::subtags::Variants; +use crate::subtags::{Language, Region, Script, Subtag, Variant}; use crate::DataLocale; /// The structure storing locale subtags used in preferences. @@ -97,6 +99,7 @@ impl From<&crate::LanguageIdentifier> for LocalePreferences { } } +#[cfg(feature = "alloc")] impl From for crate::Locale { fn from(prefs: LocalePreferences) -> Self { Self { diff --git a/components/locale_core/src/shortvec/litemap.rs b/components/locale_core/src/shortvec/litemap.rs index 7c53c344867..7488e2a1d1c 100644 --- a/components/locale_core/src/shortvec/litemap.rs +++ b/components/locale_core/src/shortvec/litemap.rs @@ -4,8 +4,8 @@ use super::ShortBoxSlice; use super::ShortBoxSliceInner; +#[cfg(feature = "alloc")] use super::ShortBoxSliceIntoIter; -use alloc::vec::Vec; use litemap::store::*; impl StoreConstEmpty for ShortBoxSlice<(K, V)> { @@ -34,6 +34,7 @@ impl Store for ShortBoxSlice<(K, V)> { use ShortBoxSliceInner::*; match self.0 { ZeroOne(ref v) => v.as_ref(), + #[cfg(feature = "alloc")] Multi(ref v) => v.last(), } .map(|elt| (&elt.0, &elt.1)) @@ -48,13 +49,14 @@ impl Store for ShortBoxSlice<(K, V)> { } } +#[cfg(feature = "alloc")] impl StoreFromIterable for ShortBoxSlice<(K, V)> { fn lm_sort_from_iter>(iter: I) -> Self { - let v: Vec<(K, V)> = Vec::lm_sort_from_iter(iter); - v.into() + alloc::vec::Vec::lm_sort_from_iter(iter).into() } } +#[cfg(feature = "alloc")] impl StoreMut for ShortBoxSlice<(K, V)> { fn lm_with_capacity(_capacity: usize) -> Self { ShortBoxSlice::new() @@ -99,8 +101,10 @@ impl<'a, K: 'a, V: 'a> StoreIterable<'a, K, V> for ShortBoxSlice<(K, V)> { } } +#[cfg(feature = "alloc")] impl StoreFromIterator for ShortBoxSlice<(K, V)> {} +#[cfg(feature = "alloc")] impl<'a, K: 'a, V: 'a> StoreIterableMut<'a, K, V> for ShortBoxSlice<(K, V)> { type KeyValueIterMut = core::iter::Map< core::slice::IterMut<'a, (K, V)>, @@ -114,6 +118,7 @@ impl<'a, K: 'a, V: 'a> StoreIterableMut<'a, K, V> for ShortBoxSlice<(K, V)> { } } +#[cfg(feature = "alloc")] impl StoreIntoIterator for ShortBoxSlice<(K, V)> { type KeyValueIntoIter = ShortBoxSliceIntoIter<(K, V)>; diff --git a/components/locale_core/src/shortvec/mod.rs b/components/locale_core/src/shortvec/mod.rs index 205ac908720..0fddd7c38f3 100644 --- a/components/locale_core/src/shortvec/mod.rs +++ b/components/locale_core/src/shortvec/mod.rs @@ -41,8 +41,11 @@ mod litemap; +#[cfg(feature = "alloc")] use alloc::boxed::Box; +#[cfg(feature = "alloc")] use alloc::vec; +#[cfg(feature = "alloc")] use alloc::vec::Vec; use core::ops::Deref; use core::ops::DerefMut; @@ -52,6 +55,7 @@ use core::ops::DerefMut; #[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)] pub(crate) enum ShortBoxSliceInner { ZeroOne(Option), + #[cfg(feature = "alloc")] Multi(Box<[T]>), } @@ -92,6 +96,7 @@ impl ShortBoxSlice { /// Pushes an element onto this [`ShortBoxSlice`]. /// /// Reallocs if more than 1 item is already in the collection. + #[cfg(feature = "alloc")] pub fn push(&mut self, item: T) { use ShortBoxSliceInner::*; self.0 = match core::mem::replace(&mut self.0, ZeroOne(None)) { @@ -135,6 +140,7 @@ impl ShortBoxSlice { match self.0 { ZeroOne(None) => 0, ZeroOne(_) => 1, + #[cfg(feature = "alloc")] Multi(ref v) => v.len(), } } @@ -149,6 +155,7 @@ impl ShortBoxSlice { /// Inserts an element at the specified index into the collection. /// /// Reallocs if more than 1 item is already in the collection. + #[cfg(feature = "alloc")] pub fn insert(&mut self, index: usize, elt: T) { use ShortBoxSliceInner::*; assert!( @@ -191,6 +198,7 @@ impl ShortBoxSlice { let (replaced, removed_item) = match core::mem::replace(&mut self.0, ZeroOne(None)) { ZeroOne(None) => unreachable!(), ZeroOne(Some(v)) => (ZeroOne(None), v), + #[cfg(feature = "alloc")] Multi(v) => { let mut v = v.into_vec(); let removed_item = v.remove(index); @@ -215,6 +223,7 @@ impl ShortBoxSlice { } /// Retains only the elements specified by the predicate. + #[allow(dead_code)] pub fn retain(&mut self, mut f: F) where F: FnMut(&T) -> bool, @@ -223,6 +232,7 @@ impl ShortBoxSlice { match core::mem::take(&mut self.0) { ZeroOne(Some(one)) if f(&one) => self.0 = ZeroOne(Some(one)), ZeroOne(_) => self.0 = ZeroOne(None), + #[cfg(feature = "alloc")] Multi(slice) => { let mut vec = slice.into_vec(); vec.retain(f); @@ -240,6 +250,7 @@ impl Deref for ShortBoxSlice { match self.0 { ZeroOne(None) => &[], ZeroOne(Some(ref v)) => core::slice::from_ref(v), + #[cfg(feature = "alloc")] Multi(ref v) => v, } } @@ -251,11 +262,13 @@ impl DerefMut for ShortBoxSlice { match self.0 { ZeroOne(None) => &mut [], ZeroOne(Some(ref mut v)) => core::slice::from_mut(v), + #[cfg(feature = "alloc")] Multi(ref mut v) => v, } } } +#[cfg(feature = "alloc")] impl From> for ShortBoxSlice { fn from(v: Vec) -> Self { use ShortBoxSliceInner::*; @@ -268,6 +281,7 @@ impl From> for ShortBoxSlice { } } +#[cfg(feature = "alloc")] impl FromIterator for ShortBoxSlice { fn from_iter>(iter: I) -> Self { use ShortBoxSliceInner::*; @@ -293,6 +307,7 @@ pub struct ShortBoxSliceIntoIter(ShortBoxSliceIntoIterInner); #[derive(Debug)] pub(crate) enum ShortBoxSliceIntoIterInner { ZeroOne(Option), + #[cfg(feature = "alloc")] Multi(alloc::vec::IntoIter), } @@ -302,6 +317,7 @@ impl Iterator for ShortBoxSliceIntoIter { use ShortBoxSliceIntoIterInner::*; match &mut self.0 { ZeroOne(option) => option.take(), + #[cfg(feature = "alloc")] Multi(into_iter) => into_iter.next(), } } @@ -318,6 +334,7 @@ impl IntoIterator for ShortBoxSlice { } // TODO: Use a boxed slice IntoIter impl when available: // + #[cfg(feature = "alloc")] ShortBoxSliceInner::Multi(boxed_slice) => ShortBoxSliceIntoIter( ShortBoxSliceIntoIterInner::Multi(boxed_slice.into_vec().into_iter()), ), diff --git a/components/locale_core/src/subtags/mod.rs b/components/locale_core/src/subtags/mod.rs index 854ccd3613f..4c26627a901 100644 --- a/components/locale_core/src/subtags/mod.rs +++ b/components/locale_core/src/subtags/mod.rs @@ -93,6 +93,7 @@ impl_tinystr_subtag!( #[allow(clippy::len_without_is_empty)] impl Subtag { + #[allow(dead_code)] pub(crate) const fn valid_key(v: &[u8]) -> bool { 2 <= v.len() && v.len() <= 8 } @@ -120,6 +121,7 @@ impl Subtag { self.0 } + #[allow(dead_code)] pub(crate) fn to_ascii_lowercase(self) -> Self { Self(self.0.to_ascii_lowercase()) } diff --git a/components/locale_core/src/subtags/variants.rs b/components/locale_core/src/subtags/variants.rs index 4852e564776..9fc0138a6c1 100644 --- a/components/locale_core/src/subtags/variants.rs +++ b/components/locale_core/src/subtags/variants.rs @@ -5,6 +5,7 @@ use super::Variant; use crate::shortvec::ShortBoxSlice; +#[cfg(feature = "alloc")] use alloc::vec::Vec; use core::ops::Deref; @@ -76,10 +77,12 @@ impl Variants { /// Notice: For performance- and memory-constrained environments, it is recommended /// for the caller to use [`binary_search`](slice::binary_search) instead of [`sort`](slice::sort) /// and [`dedup`](Vec::dedup()). + #[cfg(feature = "alloc")] pub fn from_vec_unchecked(input: Vec) -> Self { Self(input.into()) } + #[cfg(feature = "alloc")] pub(crate) fn from_short_slice_unchecked(input: ShortBoxSlice) -> Self { Self(input) } diff --git a/components/normalizer/Cargo.toml b/components/normalizer/Cargo.toml index a3035cf8f9b..4cbca8022dd 100644 --- a/components/normalizer/Cargo.toml +++ b/components/normalizer/Cargo.toml @@ -55,7 +55,7 @@ datagen = ["serde", "dep:databake", "icu_properties", "icu_collections/databake" experimental = [] compiled_data = ["dep:icu_normalizer_data", "icu_properties?/compiled_data"] icu_properties = ["dep:icu_properties"] - +alloc = [] # For dealing with UTF16 strings utf16_iter = ["dep:utf16_iter", "write16"] # For dealing with potentially ill-formed UTF8 strings @@ -64,4 +64,4 @@ utf8_iter = ["dep:utf8_iter"] [[bench]] name = "bench" harness = false -required_features = ["utf16_iter", "utf8_iter"] \ No newline at end of file +required-features = ["utf16_iter", "utf8_iter"] \ No newline at end of file diff --git a/components/normalizer/src/lib.rs b/components/normalizer/src/lib.rs index 0212b869794..a69cb729418 100644 --- a/components/normalizer/src/lib.rs +++ b/components/normalizer/src/lib.rs @@ -58,6 +58,7 @@ //! assert!(!nfd.is_normalized("ä")); //! ``` +#[cfg(feature = "alloc")] extern crate alloc; // We don't depend on icu_properties to minimize deps, but we want to be able @@ -84,7 +85,9 @@ use crate::provider::CanonicalDecompositionDataV2; use crate::provider::CompatibilityDecompositionDataV2; use crate::provider::DecompositionData; use crate::provider::Uts46DecompositionDataV2; +#[cfg(feature = "alloc")] use alloc::borrow::Cow; +#[cfg(feature = "alloc")] use alloc::string::String; use core::char::REPLACEMENT_CHARACTER; use icu_collections::char16trie::Char16Trie; @@ -1438,6 +1441,7 @@ macro_rules! decomposing_normalize_to { macro_rules! normalizer_methods { () => { /// Normalize a string slice into a `Cow<'a, str>`. + #[cfg(feature = "alloc")] pub fn normalize<'a>(&self, text: &'a str) -> Cow<'a, str> { let (head, tail) = self.split_normalized(text); if tail.is_empty() { @@ -1481,6 +1485,7 @@ macro_rules! normalizer_methods { /// /// ✨ *Enabled with the `utf16_iter` Cargo feature.* #[cfg(feature = "utf16_iter")] + #[cfg(feature = "alloc")] pub fn normalize_utf16<'a>(&self, text: &'a [u16]) -> Cow<'a, [u16]> { let (head, tail) = self.split_normalized_utf16(text); if tail.is_empty() { @@ -1534,6 +1539,7 @@ macro_rules! normalizer_methods { /// /// ✨ *Enabled with the `utf8_iter` Cargo feature.* #[cfg(feature = "utf8_iter")] + #[cfg(feature = "alloc")] pub fn normalize_utf8<'a>(&self, text: &'a [u8]) -> Cow<'a, str> { let (head, tail) = self.split_normalized_utf8(text); if tail.is_empty() { diff --git a/components/pattern/Cargo.toml b/components/pattern/Cargo.toml index c576dd91e9c..218fde50e7f 100644 --- a/components/pattern/Cargo.toml +++ b/components/pattern/Cargo.toml @@ -39,7 +39,7 @@ postcard = { workspace = true, features = ["use-std"] } [features] default = [] -alloc = [] +alloc = ["zerovec?/alloc"] databake = ["dep:databake"] litemap = ["dep:litemap"] serde = ["alloc", "dep:serde"] diff --git a/components/plurals/Cargo.toml b/components/plurals/Cargo.toml index 0a9c35f7537..99a1f0c2b13 100644 --- a/components/plurals/Cargo.toml +++ b/components/plurals/Cargo.toml @@ -22,8 +22,8 @@ all-features = true [dependencies] displaydoc = { workspace = true } fixed_decimal = { workspace = true } -icu_provider = { workspace = true, features = ["macros"] } -zerovec = { workspace = true, features = ["yoke"] } +icu_provider = { workspace = true, features = ["alloc", "macros"] } +zerovec = { workspace = true, features = ["alloc", "yoke"] } databake = { workspace = true, features = ["derive"], optional = true} serde = { workspace = true, features = ["derive", "alloc"], optional = true } diff --git a/components/properties/Cargo.toml b/components/properties/Cargo.toml index a1c1b034257..f682610bb05 100644 --- a/components/properties/Cargo.toml +++ b/components/properties/Cargo.toml @@ -43,3 +43,4 @@ serde = ["dep:serde", "icu_locale_core/serde", "potential_utf/serde", "zerovec/s datagen = ["serde", "dep:databake", "potential_utf/databake", "zerovec/databake", "icu_collections/databake", "icu_locale_core/databake", "zerotrie/databake"] unicode_bidi = [ "dep:unicode-bidi" ] compiled_data = ["dep:icu_properties_data"] +alloc = ["zerovec/alloc", "icu_collections/alloc"] \ No newline at end of file diff --git a/components/properties/src/code_point_map.rs b/components/properties/src/code_point_map.rs index 7bc137c7abf..2855ed892e8 100644 --- a/components/properties/src/code_point_map.rs +++ b/components/properties/src/code_point_map.rs @@ -2,14 +2,15 @@ // called LICENSE at the top level of the ICU4X source tree // (online at: https://github.com/unicode-org/icu4x/blob/main/LICENSE ). +#[cfg(feature = "alloc")] +use crate::code_point_set::CodePointSetData; use crate::props::GeneralCategory; +use crate::props::GeneralCategoryGroup; use crate::provider::*; -use crate::{code_point_set::CodePointSetData, props::GeneralCategoryGroup}; use core::ops::RangeInclusive; use icu_collections::codepointtrie::{CodePointMapRange, CodePointTrie, TrieValue}; use icu_provider::marker::ErasedMarker; use icu_provider::prelude::*; -use zerovec::ule::UleError; /// A wrapper around code point map data. /// @@ -85,7 +86,8 @@ impl CodePointMapData { /// assert_eq!(gc.get('木'), GeneralCategory::OtherLetter as u8); // U+6728 /// assert_eq!(gc.get('🎃'), GeneralCategory::OtherSymbol as u8); // U+1F383 JACK-O-LANTERN /// ``` - pub fn try_into_converted

(self) -> Result, UleError> + #[cfg(feature = "alloc")] + pub fn try_into_converted

(self) -> Result, zerovec::ule::UleError> where P: TrieValue, { @@ -186,6 +188,7 @@ impl<'a, T: TrieValue> CodePointMapDataBorrowed<'a, T> { /// assert!(other_letter_set.contains('木')); // U+6728 /// assert!(!other_letter_set.contains('🎃')); // U+1F383 JACK-O-LANTERN /// ``` + #[cfg(feature = "alloc")] pub fn get_set_for_value(self, value: T) -> CodePointSetData { let set = self.map.get_set_for_value(value); CodePointSetData::from_code_point_inversion_list(set) @@ -263,6 +266,7 @@ impl<'a, T: TrieValue> CodePointMapDataBorrowed<'a, T> { impl CodePointMapDataBorrowed<'_, GeneralCategory> { /// TODO + #[cfg(feature = "alloc")] pub fn get_set_for_value_group(self, value: GeneralCategoryGroup) -> crate::CodePointSetData { let matching_gc_ranges = self .iter_ranges() diff --git a/components/properties/src/lib.rs b/components/properties/src/lib.rs index 3913dd85f2d..e980b2fbfce 100644 --- a/components/properties/src/lib.rs +++ b/components/properties/src/lib.rs @@ -68,6 +68,7 @@ )] #![warn(missing_docs)] +#[cfg(feature = "alloc")] extern crate alloc; mod code_point_set; diff --git a/components/properties/src/props.rs b/components/properties/src/props.rs index d61f06e71e6..e625e4d61d9 100644 --- a/components/properties/src/props.rs +++ b/components/properties/src/props.rs @@ -3004,7 +3004,7 @@ make_emoji_set! { #[cfg(test)] mod test_enumerated_property_completeness { use super::*; - use alloc::collections::BTreeMap; + use std::collections::BTreeMap; fn check_enum<'a, T: NamedEnumeratedProperty>( lookup: &crate::provider::names::PropertyValueNameToEnumMap<'static>, diff --git a/components/properties/src/provider.rs b/components/properties/src/provider.rs index c2547332a8a..9e444e712c5 100644 --- a/components/properties/src/provider.rs +++ b/components/properties/src/provider.rs @@ -45,7 +45,7 @@ use icu_collections::codepointinvliststringlist::CodePointInversionListAndString use icu_collections::codepointtrie::{CodePointMapRange, CodePointTrie, TrieValue}; use icu_provider::prelude::*; use zerofrom::ZeroFrom; -use zerovec::{ule::UleError, VarZeroVec, ZeroSlice}; +use zerovec::{VarZeroVec, ZeroSlice}; #[cfg(feature = "compiled_data")] #[derive(Debug)] @@ -528,7 +528,10 @@ impl<'data, T: TrieValue> PropertyCodePointMap<'data, T> { } #[inline] - pub(crate) fn try_into_converted

(self) -> Result, UleError> + #[cfg(feature = "alloc")] + pub(crate) fn try_into_converted

( + self, + ) -> Result, zerovec::ule::UleError> where P: TrieValue, { @@ -540,6 +543,7 @@ impl<'data, T: TrieValue> PropertyCodePointMap<'data, T> { } #[inline] + #[cfg(feature = "alloc")] pub(crate) fn get_set_for_value(&self, value: T) -> CodePointInversionList<'static> { match *self { Self::CodePointTrie(ref t) => t.get_set_for_value(value), diff --git a/components/properties/src/script.rs b/components/properties/src/script.rs index 9799549eb6c..59c6167dfac 100644 --- a/components/properties/src/script.rs +++ b/components/properties/src/script.rs @@ -8,8 +8,10 @@ use crate::props::Script; use crate::provider::*; +#[cfg(feature = "alloc")] use core::iter::FromIterator; use core::ops::RangeInclusive; +#[cfg(feature = "alloc")] use icu_collections::codepointinvlist::CodePointInversionList; use icu_provider::prelude::*; use zerovec::{ule::AsULE, ZeroSlice}; @@ -641,6 +643,7 @@ impl<'a> ScriptWithExtensionsBorrowed<'a> { /// assert!(syriac.contains('\u{1DFA}')); // COMBINING DOT BELOW LEFT /// assert!(!syriac.contains('\u{1DFB}')); // COMBINING DELETION MARK /// ``` + #[cfg(feature = "alloc")] pub fn get_script_extensions_set(self, script: Script) -> CodePointInversionList<'a> { CodePointInversionList::from_iter(self.get_script_extensions_ranges(script)) } diff --git a/components/segmenter/Cargo.toml b/components/segmenter/Cargo.toml index 381256bd558..9d33390f6d8 100644 --- a/components/segmenter/Cargo.toml +++ b/components/segmenter/Cargo.toml @@ -25,11 +25,11 @@ icu_collections = { workspace = true } icu_locale_core = { workspace = true } icu_provider = { workspace = true, features = ["macros"] } utf8_iter = { workspace = true } -zerovec = { workspace = true, features = ["yoke"] } +zerovec = { workspace = true, features = ["alloc", "yoke"] } databake = { workspace = true, optional = true, features = ["derive"] } serde = { workspace = true, features = ["derive", "alloc"], optional = true } -potential_utf = { workspace = true, features = ["zerovec"] } +potential_utf = { workspace = true, features = ["alloc", "zerovec"] } core_maths = { workspace = true, optional = true } diff --git a/ffi/capi/Cargo.toml b/ffi/capi/Cargo.toml index 901c6f25253..d4dccb0fab4 100644 --- a/ffi/capi/Cargo.toml +++ b/ffi/capi/Cargo.toml @@ -129,7 +129,7 @@ diplomat-runtime = { workspace = true } # Optional ICU4X components and their dependent utils fixed_decimal = { workspace = true, features = ["ryu"] , optional = true } -icu_calendar = { workspace = true, features = ["ixdtf"], optional = true } +icu_calendar = { workspace = true, features = ["alloc", "ixdtf"], optional = true } icu_casemap = { workspace = true, optional = true } icu_collator = { workspace = true, optional = true } icu_collections = { workspace = true, optional = true } @@ -139,7 +139,7 @@ icu_list = { workspace = true, optional = true } icu_locale = { workspace = true, optional = true } icu_normalizer = { workspace = true, optional = true } icu_plurals = { workspace = true, optional = true } -icu_properties = { workspace = true, features = ["unicode_bidi"], optional = true } +icu_properties = { workspace = true, features = ["alloc", "unicode_bidi"], optional = true } icu_segmenter = { workspace = true, features = ["auto"], optional = true } icu_timezone = { workspace = true, features = ["ixdtf"], optional = true } icu_experimental = { workspace = true, optional = true } diff --git a/provider/adapters/Cargo.toml b/provider/adapters/Cargo.toml index a75075b27d4..62ac6ad97b0 100644 --- a/provider/adapters/Cargo.toml +++ b/provider/adapters/Cargo.toml @@ -18,7 +18,7 @@ version.workspace = true [dependencies] icu_locale = { workspace = true } -icu_provider = { workspace = true, features = ["macros"] } +icu_provider = { workspace = true, features = ["macros", "alloc"] } tinystr = { workspace = true, features = ["zerovec"] } zerovec = { workspace = true, features = ["yoke"] } diff --git a/provider/baked/Cargo.toml b/provider/baked/Cargo.toml index c99d89dd407..509021931a7 100644 --- a/provider/baked/Cargo.toml +++ b/provider/baked/Cargo.toml @@ -42,4 +42,6 @@ export = [ "dep:proc-macro2", "icu_provider/export", "zerotrie/databake", + "alloc", ] +alloc = ["icu_provider/alloc"] \ No newline at end of file diff --git a/provider/baked/src/binary_search.rs b/provider/baked/src/binary_search.rs index 468bf3887b2..c0280b3a68b 100644 --- a/provider/baked/src/binary_search.rs +++ b/provider/baked/src/binary_search.rs @@ -139,10 +139,12 @@ impl super::DataStore for Data { .ok() } + #[cfg(feature = "alloc")] type IterReturn = core::iter::Map< core::slice::Iter<'static, (K::Type, &'static M::DataStruct)>, fn(&'static (K::Type, &'static M::DataStruct)) -> DataIdentifierCow<'static>, >; + #[cfg(feature = "alloc")] fn iter(&self) -> Self::IterReturn { self.0.iter().map(|&(k, _)| K::to_id(k)) } @@ -152,6 +154,7 @@ pub trait BinarySearchKey: 'static { type Type: Ord + Copy + 'static; fn cmp(k: Self::Type, id: DataIdentifierBorrowed) -> core::cmp::Ordering; + #[cfg(feature = "alloc")] fn to_id(k: Self::Type) -> DataIdentifierCow<'static>; } @@ -164,6 +167,7 @@ impl BinarySearchKey for Locale { id.locale.strict_cmp(locale.as_bytes()).reverse() } + #[cfg(feature = "alloc")] fn to_id(locale: Self::Type) -> DataIdentifierCow<'static> { DataIdentifierCow::from_locale(locale.parse().unwrap()) } @@ -178,6 +182,7 @@ impl BinarySearchKey for Attributes { attributes.cmp(id.marker_attributes) } + #[cfg(feature = "alloc")] fn to_id(attributes: Self::Type) -> DataIdentifierCow<'static> { DataIdentifierCow::from_marker_attributes(DataMarkerAttributes::from_str_or_panic( attributes, @@ -196,6 +201,7 @@ impl BinarySearchKey for AttributesAndLocale { .then_with(|| id.locale.strict_cmp(locale.as_bytes()).reverse()) } + #[cfg(feature = "alloc")] fn to_id((attributes, locale): Self::Type) -> DataIdentifierCow<'static> { DataIdentifierCow::from_borrowed_and_owned( DataMarkerAttributes::from_str_or_panic(attributes), diff --git a/provider/baked/src/lib.rs b/provider/baked/src/lib.rs index ddf0d4aaf00..d1f6207d707 100644 --- a/provider/baked/src/lib.rs +++ b/provider/baked/src/lib.rs @@ -23,6 +23,8 @@ pub trait DataStore { attributes_prefix_match: bool, ) -> Option<&'static M::DataStruct>; + #[cfg(feature = "alloc")] type IterReturn: Iterator>; + #[cfg(feature = "alloc")] fn iter(&'static self) -> Self::IterReturn; } diff --git a/provider/baked/src/zerotrie.rs b/provider/baked/src/zerotrie.rs index 464906ddd71..31068455122 100644 --- a/provider/baked/src/zerotrie.rs +++ b/provider/baked/src/zerotrie.rs @@ -103,10 +103,12 @@ impl super::DataStore for Data { .map(|i| unsafe { self.values.get_unchecked(i) }) } + #[cfg(feature = "alloc")] type IterReturn = core::iter::FilterMap< zerotrie::ZeroTrieStringIterator<'static>, fn((alloc::string::String, usize)) -> Option>, >; + #[cfg(feature = "alloc")] fn iter(&'static self) -> Self::IterReturn { #![allow(unused_imports)] use alloc::borrow::ToOwned; diff --git a/provider/blob/Cargo.toml b/provider/blob/Cargo.toml index c852c2257eb..cd09c3dd965 100644 --- a/provider/blob/Cargo.toml +++ b/provider/blob/Cargo.toml @@ -21,11 +21,11 @@ all-features = true [dependencies] icu_provider = { workspace = true, features = ["deserialize_postcard_1", "serde"] } -postcard = { workspace = true, features = ["alloc"] } -serde = { workspace = true, features = ["alloc"] } +postcard = { workspace = true } +serde = { workspace = true } writeable = {workspace = true } zerovec = { workspace = true, features = ["serde", "yoke"] } -zerotrie = { workspace = true, features = ["serde", "zerovec", "alloc"] } +zerotrie = { workspace = true, features = ["serde", "zerovec"] } log = { workspace = true, optional = true } @@ -34,7 +34,7 @@ databake = { path = "../../utils/databake" } icu_provider_export = { path = "../../provider/export" } icu_locale = { path = "../../components/locale", default-features = false, features = ["compiled_data"] } icu_locale_core = { path = "../../components/locale_core", default-features = false, features = ["serde"] } -icu_provider = { path = "../../provider/core", features = ["macros"] } +icu_provider = { path = "../../provider/core", features = ["macros", "alloc"] } icu_provider_adapters = { path = "../../provider/adapters", default-features = false } twox-hash = { workspace = true } @@ -45,7 +45,9 @@ criterion = { workspace = true } export = [ "icu_provider/export", "log", + "alloc", ] +alloc = ["icu_provider/alloc", "postcard/alloc", "zerotrie/alloc", "serde/alloc"] [lib] bench = false # This option is required for Benchmark CI diff --git a/provider/blob/src/blob_data_provider.rs b/provider/blob/src/blob_data_provider.rs index 13d706f5a85..3010102f53f 100644 --- a/provider/blob/src/blob_data_provider.rs +++ b/provider/blob/src/blob_data_provider.rs @@ -3,8 +3,6 @@ // (online at: https://github.com/unicode-org/icu4x/blob/main/LICENSE ). use crate::blob_schema::BlobSchema; -use alloc::boxed::Box; -use alloc::collections::BTreeSet; use icu_provider::buf::BufferFormat; use icu_provider::prelude::*; use icu_provider::Cart; @@ -96,7 +94,8 @@ impl core::fmt::Debug for BlobDataProvider { impl BlobDataProvider { /// Create a [`BlobDataProvider`] from a blob of ICU4X data. - pub fn try_new_from_blob(blob: Box<[u8]>) -> Result { + #[cfg(feature = "alloc")] + pub fn try_new_from_blob(blob: alloc::boxed::Box<[u8]>) -> Result { Ok(Self { data: Cart::try_make_yoke(blob, |bytes| { BlobSchema::deserialize_and_check(&mut postcard::Deserializer::from_bytes(bytes)) @@ -152,11 +151,12 @@ impl DynamicDryDataProvider for BlobDataProvider { } } +#[cfg(feature = "alloc")] impl IterableDynamicDataProvider for BlobDataProvider { fn iter_ids_for_marker( &self, marker: DataMarkerInfo, - ) -> Result, DataError> { + ) -> Result, DataError> { self.data.get().iter_ids(marker) } } diff --git a/provider/blob/src/blob_schema.rs b/provider/blob/src/blob_schema.rs index beb8862798b..cc347ffcedd 100644 --- a/provider/blob/src/blob_schema.rs +++ b/provider/blob/src/blob_schema.rs @@ -2,15 +2,12 @@ // called LICENSE at the top level of the ICU4X source tree // (online at: https://github.com/unicode-org/icu4x/blob/main/LICENSE ). -use alloc::boxed::Box; -use alloc::collections::BTreeSet; use core::fmt::Write; use icu_provider::{marker::DataMarkerIdHash, prelude::*}; use serde::Deserialize; use writeable::Writeable; use zerotrie::ZeroTrieSimpleAscii; -use zerovec::maps::ZeroMapKV; -use zerovec::vecs::{Index16, Index32, VarZeroSlice, VarZeroVec, VarZeroVecFormat, ZeroSlice}; +use zerovec::vecs::{Index16, Index32, VarZeroSlice, VarZeroVecFormat, ZeroSlice}; /// A versioned Serde schema for ICU4X data blobs. #[derive(serde::Deserialize, yoke::Yokeable)] @@ -55,10 +52,11 @@ impl<'data> BlobSchema<'data> { } } + #[cfg(feature = "alloc")] pub fn iter_ids( &self, marker: DataMarkerInfo, - ) -> Result, DataError> { + ) -> Result, DataError> { match self { BlobSchema::V001(..) | BlobSchema::V002(..) | BlobSchema::V002Bigger(..) => { unreachable!("Unreachable blob schema") @@ -184,10 +182,11 @@ impl<'data, LocaleVecFormat: VarZeroVecFormat> BlobSchemaV1<'data, LocaleVecForm .and_then(|cs| Some(u64::from_le_bytes(self.buffers.get(cs)?.try_into().ok()?))) } + #[cfg(feature = "alloc")] pub fn iter_ids( &self, marker: DataMarkerInfo, - ) -> Result, DataError> { + ) -> Result, DataError> { let marker_index = self .markers .binary_search(&marker.id.hashed()) @@ -242,36 +241,3 @@ impl<'data, LocaleVecFormat: VarZeroVecFormat> BlobSchemaV1<'data, LocaleVecForm debug_assert!(seen_max); } } - -/// This type lets us use a u32-index-format VarZeroVec with the ZeroMap2dBorrowed. -/// -/// Eventually we will have a FormatSelector type that lets us do `ZeroMap, V>` -/// (https://github.com/unicode-org/icu4x/issues/2312) -/// -/// IndexU32Borrowed isn't actually important; it's just more convenient to use make_varule to get the -/// full suite of traits instead of `#[derive(VarULE)]`. (With `#[derive(VarULE)]` we would have to manually -/// define a Serialize implementation, and that would be gnarly) -/// https://github.com/unicode-org/icu4x/issues/2310 tracks being able to do this with derive(ULE) -#[zerovec::make_varule(Index32U8)] -#[zerovec::derive(Debug)] -#[zerovec::skip_derive(ZeroMapKV)] -#[derive(Eq, PartialEq, Ord, PartialOrd, Debug, serde::Deserialize)] -#[zerovec::derive(Deserialize)] -#[cfg_attr(feature = "export", derive(serde::Serialize))] -#[cfg_attr(feature = "export", zerovec::derive(Serialize))] -pub(crate) struct Index32U8Borrowed<'a>( - #[cfg_attr(feature = "export", serde(borrow))] pub &'a [u8], -); - -impl<'a> ZeroMapKV<'a> for Index32U8 { - type Container = VarZeroVec<'a, Index32U8, Index32>; - type Slice = VarZeroSlice; - type GetType = Index32U8; - type OwnedType = Box; -} - -impl Index32U8 { - // Safety: Index32U8 is a transparent DST wrapper around `[u8]`, so a transmute is fine - #[allow(dead_code)] - pub(crate) const SENTINEL: &'static Self = unsafe { &*(&[] as *const [u8] as *const Self) }; -} diff --git a/provider/blob/src/lib.rs b/provider/blob/src/lib.rs index db4e3d631dc..b26b59bdf0b 100644 --- a/provider/blob/src/lib.rs +++ b/provider/blob/src/lib.rs @@ -32,6 +32,7 @@ )] #![warn(missing_docs)] +#[cfg(feature = "alloc")] extern crate alloc; mod blob_data_provider; diff --git a/provider/core/Cargo.toml b/provider/core/Cargo.toml index 55040b3ad59..25cb97975b6 100644 --- a/provider/core/Cargo.toml +++ b/provider/core/Cargo.toml @@ -55,7 +55,8 @@ icu_provider_adapters = { path = "../adapters", default-features = false } criterion = { workspace = true } [features] -std = [] +std = ["alloc"] +alloc = ["icu_locale_core/alloc", "zerovec/alloc"] sync = [] macros = ["dep:icu_provider_macros"] # Enable logging of additional context of data errors diff --git a/provider/core/src/data_provider.rs b/provider/core/src/data_provider.rs index de01eb0eba3..ae7d2a72224 100644 --- a/provider/core/src/data_provider.rs +++ b/provider/core/src/data_provider.rs @@ -2,7 +2,6 @@ // called LICENSE at the top level of the ICU4X source tree // (online at: https://github.com/unicode-org/icu4x/blob/main/LICENSE ). -use alloc::{boxed::Box, collections::BTreeSet}; use core::marker::PhantomData; use yoke::Yokeable; @@ -31,7 +30,8 @@ where } } -impl DataProvider for Box

+#[cfg(feature = "alloc")] +impl DataProvider for alloc::boxed::Box

where M: DataMarker, P: DataProvider + ?Sized, @@ -42,6 +42,7 @@ where } } +#[cfg(feature = "alloc")] impl DataProvider for alloc::rc::Rc

where M: DataMarker, @@ -54,6 +55,7 @@ where } #[cfg(target_has_atomic = "ptr")] +#[cfg(feature = "alloc")] impl DataProvider for alloc::sync::Arc

where M: DataMarker, @@ -89,7 +91,8 @@ where } } -impl DryDataProvider for Box

+#[cfg(feature = "alloc")] +impl DryDataProvider for alloc::boxed::Box

where M: DataMarker, P: DryDataProvider + ?Sized, @@ -100,6 +103,7 @@ where } } +#[cfg(feature = "alloc")] impl DryDataProvider for alloc::rc::Rc

where M: DataMarker, @@ -112,6 +116,7 @@ where } #[cfg(target_has_atomic = "ptr")] +#[cfg(feature = "alloc")] impl DryDataProvider for alloc::sync::Arc

where M: DataMarker, @@ -127,9 +132,10 @@ where /// /// The provider is not allowed to return `Ok` for requests that were not returned by `iter_ids`, /// and must not fail with a [`DataErrorKind::IdentifierNotFound`] for requests that were returned. +#[cfg(feature = "alloc")] pub trait IterableDataProvider: DataProvider { /// Returns a set of [`DataIdentifierCow`]. - fn iter_ids(&self) -> Result, DataError>; + fn iter_ids(&self) -> Result, DataError>; } /// A data provider that loads data for a specific data type. @@ -165,7 +171,8 @@ where } } -impl DynamicDataProvider for Box

+#[cfg(feature = "alloc")] +impl DynamicDataProvider for alloc::boxed::Box

where M: DynamicDataMarker, P: DynamicDataProvider + ?Sized, @@ -180,6 +187,7 @@ where } } +#[cfg(feature = "alloc")] impl DynamicDataProvider for alloc::rc::Rc

where M: DynamicDataMarker, @@ -196,6 +204,7 @@ where } #[cfg(target_has_atomic = "ptr")] +#[cfg(feature = "alloc")] impl DynamicDataProvider for alloc::sync::Arc

where M: DynamicDataMarker, @@ -243,7 +252,8 @@ where } } -impl DynamicDryDataProvider for Box

+#[cfg(feature = "alloc")] +impl DynamicDryDataProvider for alloc::boxed::Box

where M: DynamicDataMarker, P: DynamicDryDataProvider + ?Sized, @@ -258,6 +268,7 @@ where } } +#[cfg(feature = "alloc")] impl DynamicDryDataProvider for alloc::rc::Rc

where M: DynamicDataMarker, @@ -274,6 +285,7 @@ where } #[cfg(target_has_atomic = "ptr")] +#[cfg(feature = "alloc")] impl DynamicDryDataProvider for alloc::sync::Arc

where M: DynamicDataMarker, @@ -293,15 +305,17 @@ where /// /// The provider is not allowed to return `Ok` for requests that were not returned by `iter_ids`, /// and must not fail with a [`DataErrorKind::IdentifierNotFound`] for requests that were returned. +#[cfg(feature = "alloc")] pub trait IterableDynamicDataProvider: DynamicDataProvider { /// Given a [`DataMarkerInfo`], returns a set of [`DataIdentifierCow`]. fn iter_ids_for_marker( &self, marker: DataMarkerInfo, - ) -> Result, DataError>; + ) -> Result, DataError>; } -impl IterableDynamicDataProvider for Box

+#[cfg(feature = "alloc")] +impl IterableDynamicDataProvider for alloc::boxed::Box

where M: DynamicDataMarker, P: IterableDynamicDataProvider + ?Sized, @@ -309,7 +323,7 @@ where fn iter_ids_for_marker( &self, marker: DataMarkerInfo, - ) -> Result, DataError> { + ) -> Result, DataError> { (**self).iter_ids_for_marker(marker) } } @@ -350,7 +364,8 @@ where } } -impl BoundDataProvider for Box

+#[cfg(feature = "alloc")] +impl BoundDataProvider for alloc::boxed::Box

where M: DynamicDataMarker, P: BoundDataProvider + ?Sized, @@ -365,6 +380,7 @@ where } } +#[cfg(feature = "alloc")] impl BoundDataProvider for alloc::rc::Rc

where M: DynamicDataMarker, @@ -381,6 +397,7 @@ where } #[cfg(target_has_atomic = "ptr")] +#[cfg(feature = "alloc")] impl BoundDataProvider for alloc::sync::Arc

where M: DynamicDataMarker, diff --git a/provider/core/src/lib.rs b/provider/core/src/lib.rs index 34f56667782..2d6653bb5fb 100644 --- a/provider/core/src/lib.rs +++ b/provider/core/src/lib.rs @@ -94,6 +94,7 @@ )] #![warn(missing_docs)] +#[cfg(feature = "alloc")] extern crate alloc; pub mod buf; @@ -101,18 +102,21 @@ pub mod constructors; pub mod dynutil; #[cfg(feature = "export")] pub mod export; +#[cfg(feature = "alloc")] pub mod hello_world; // TODO: put this in a separate crate -#[cfg(feature = "serde")] +#[cfg(all(feature = "serde", feature = "alloc"))] #[doc(hidden)] pub mod serde_borrow_de_utils; mod data_provider; pub use data_provider::{ BoundDataProvider, DataProvider, DataProviderWithMarker, DryDataProvider, DynamicDataProvider, - DynamicDryDataProvider, IterableDataProvider, IterableDynamicDataProvider, + DynamicDryDataProvider, }; +#[cfg(feature = "alloc")] +pub use data_provider::{IterableDataProvider, IterableDynamicDataProvider}; mod error; pub use error::{DataError, DataErrorKind, ResultDataError}; @@ -154,9 +158,10 @@ pub mod prelude { data_marker, marker::DataMarkerExt, BoundDataProvider, DataError, DataErrorKind, DataLocale, DataMarker, DataMarkerAttributes, DataMarkerInfo, DataPayload, DataProvider, DataRequest, DataRequestMetadata, DataResponse, DataResponseMetadata, DryDataProvider, - DynamicDataMarker, DynamicDataProvider, DynamicDryDataProvider, IterableDataProvider, - IterableDynamicDataProvider, ResultDataError, + DynamicDataMarker, DynamicDataProvider, DynamicDryDataProvider, ResultDataError, }; + #[cfg(feature = "alloc")] + pub use crate::{IterableDataProvider, IterableDynamicDataProvider}; #[doc(no_inline)] pub use icu_locale_core; diff --git a/provider/core/src/marker.rs b/provider/core/src/marker.rs index 97594ff90fa..e6daaff66c1 100644 --- a/provider/core/src/marker.rs +++ b/provider/core/src/marker.rs @@ -304,6 +304,7 @@ const fn fxhash_32(bytes: &[u8]) -> u32 { hash } +#[cfg(feature = "alloc")] impl<'a> zerovec::maps::ZeroMapKV<'a> for DataMarkerIdHash { type Container = zerovec::ZeroVec<'a, DataMarkerIdHash>; type Slice = zerovec::ZeroSlice; diff --git a/provider/core/src/request.rs b/provider/core/src/request.rs index 6dcdc0aee6a..364843bd9df 100644 --- a/provider/core/src/request.rs +++ b/provider/core/src/request.rs @@ -2,16 +2,22 @@ // called LICENSE at the top level of the ICU4X source tree // (online at: https://github.com/unicode-org/icu4x/blob/main/LICENSE ). +#[cfg(feature = "alloc")] use alloc::borrow::Cow; +#[cfg(feature = "alloc")] use alloc::borrow::ToOwned; +#[cfg(feature = "alloc")] use alloc::boxed::Box; +#[cfg(feature = "alloc")] use alloc::string::String; +#[cfg(feature = "alloc")] use core::cmp::Ordering; use core::default::Default; use core::fmt; use core::fmt::Debug; use core::hash::Hash; use core::ops::Deref; +#[cfg(feature = "alloc")] use zerovec::ule::VarULE; pub use icu_locale_core::DataLocale; @@ -89,6 +95,7 @@ impl<'a> DataIdentifierBorrowed<'a> { } /// Converts this [`DataIdentifierBorrowed`] into a [`DataIdentifierCow<'static>`]. + #[cfg(feature = "alloc")] pub fn into_owned(self) -> DataIdentifierCow<'static> { DataIdentifierCow { marker_attributes: Cow::Owned(self.marker_attributes.to_owned()), @@ -97,6 +104,7 @@ impl<'a> DataIdentifierBorrowed<'a> { } /// Borrows this [`DataIdentifierBorrowed`] as a [`DataIdentifierCow<'a>`]. + #[cfg(feature = "alloc")] pub fn as_cow(self) -> DataIdentifierCow<'a> { DataIdentifierCow { marker_attributes: Cow::Borrowed(self.marker_attributes), @@ -110,6 +118,7 @@ impl<'a> DataIdentifierBorrowed<'a> { /// It is a wrapper around a [`DataLocale`] and a [`DataMarkerAttributes`]. #[derive(Debug, PartialEq, Eq, Hash, Clone)] #[non_exhaustive] +#[cfg(feature = "alloc")] pub struct DataIdentifierCow<'a> { /// Marker-specific request attributes pub marker_attributes: Cow<'a, DataMarkerAttributes>, @@ -117,12 +126,14 @@ pub struct DataIdentifierCow<'a> { pub locale: DataLocale, } +#[cfg(feature = "alloc")] impl PartialOrd for DataIdentifierCow<'_> { fn partial_cmp(&self, other: &Self) -> Option { Some(self.cmp(other)) } } +#[cfg(feature = "alloc")] impl Ord for DataIdentifierCow<'_> { fn cmp(&self, other: &Self) -> Ordering { self.marker_attributes @@ -131,6 +142,7 @@ impl Ord for DataIdentifierCow<'_> { } } +#[cfg(feature = "alloc")] impl fmt::Display for DataIdentifierCow<'_> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fmt::Display::fmt(&self.locale, f)?; @@ -141,6 +153,7 @@ impl fmt::Display for DataIdentifierCow<'_> { } } +#[cfg(feature = "alloc")] impl<'a> DataIdentifierCow<'a> { /// Borrows this [`DataIdentifierCow`] as a [`DataIdentifierBorrowed<'a>`]. pub fn as_borrowed(&'a self) -> DataIdentifierBorrowed<'a> { @@ -175,6 +188,7 @@ impl<'a> DataIdentifierCow<'a> { } /// Creates a [`DataIdentifierCow`] from an owned [`DataMarkerAttributes`] and an owned [`DataLocale`]. + #[cfg(feature = "alloc")] pub fn from_owned(marker_attributes: Box, locale: DataLocale) -> Self { Self { marker_attributes: Cow::Owned(marker_attributes), @@ -199,6 +213,7 @@ impl<'a> DataIdentifierCow<'a> { } } +#[cfg(feature = "alloc")] impl Default for DataIdentifierCow<'_> { fn default() -> Self { Self { @@ -295,6 +310,7 @@ impl DataMarkerAttributes { /// Creates an owned [`DataMarkerAttributes`] from an owned string. /// /// Returns an error if the string contains characters other than `[a-zA-Z0-9_\-]`. + #[cfg(feature = "alloc")] pub fn try_from_string(s: String) -> Result, AttributeParseError> { let Ok(()) = Self::validate(s.as_bytes()) else { return Err(AttributeParseError); @@ -326,6 +342,7 @@ impl DataMarkerAttributes { } } +#[cfg(feature = "alloc")] impl ToOwned for DataMarkerAttributes { type Owned = Box; fn to_owned(&self) -> Self::Owned { diff --git a/provider/core/src/response.rs b/provider/core/src/response.rs index 1d1599a8f2f..7b212ce686a 100644 --- a/provider/core/src/response.rs +++ b/provider/core/src/response.rs @@ -6,16 +6,20 @@ use crate::buf::BufferMarker; use crate::DataError; use crate::DataLocale; use crate::DynamicDataMarker; +#[cfg(feature = "alloc")] use alloc::boxed::Box; use core::fmt::Debug; use core::marker::PhantomData; +#[cfg(feature = "alloc")] use core::ops::Deref; use yoke::cartable_ptr::CartableOptionPointer; use yoke::trait_hack::YokeTraitHack; use yoke::*; +#[cfg(feature = "alloc")] #[cfg(not(feature = "sync"))] use alloc::rc::Rc as SelectedRc; +#[cfg(feature = "alloc")] #[cfg(feature = "sync")] use alloc::sync::Arc as SelectedRc; @@ -173,11 +177,18 @@ pub(crate) enum DataPayloadOrInnerInner { /// it to a [`DataPayload`] with [`DataPayload::from_yoked_buffer`]. #[derive(Clone, Debug)] #[allow(clippy::redundant_allocation)] // false positive, it's cheaper to wrap an existing Box in an Rc than to reallocate a huge Rc -pub struct Cart(CartInner); +pub struct Cart(#[allow(dead_code)] CartInner); /// The actual cart type (private typedef). +#[cfg(feature = "alloc")] pub(crate) type CartInner = SelectedRc>; +#[cfg(not(feature = "alloc"))] +pub(crate) type CartInner = &'static (); +// Safety: Rc, Arc, and () are CloneableCart, and our impl delegates. +unsafe impl yoke::CloneableCart for Cart {} + +#[cfg(feature = "alloc")] impl Deref for Cart { type Target = Box<[u8]>; fn deref(&self) -> &Self::Target { @@ -185,11 +196,11 @@ impl Deref for Cart { } } // Safety: both Rc and Arc are StableDeref, and our impl delegates. +#[cfg(feature = "alloc")] unsafe impl stable_deref_trait::StableDeref for Cart {} -// Safety: both Rc and Arc are CloneableCart, and our impl delegates. -unsafe impl yoke::CloneableCart for Cart {} impl Cart { + #[cfg(feature = "alloc")] /// Creates a `Yoke>` from owned bytes by applying `f`. pub fn try_make_yoke(cart: Box<[u8]>, f: F) -> Result>, E> where @@ -904,6 +915,7 @@ where impl DataPayload { /// Converts an owned byte buffer into a `DataPayload`. + #[cfg(feature = "alloc")] pub fn from_owned_buffer(buffer: Box<[u8]>) -> Self { let yoke = Yoke::attach_to_cart(SelectedRc::new(buffer), |b| &**b) .wrap_cart_in_option() diff --git a/provider/icu4x-datagen/Cargo.toml b/provider/icu4x-datagen/Cargo.toml index 9172de2a53e..d8dec531c31 100644 --- a/provider/icu4x-datagen/Cargo.toml +++ b/provider/icu4x-datagen/Cargo.toml @@ -23,7 +23,7 @@ icu_provider_export = { workspace = true, features = ["rayon"] } icu_provider_source = { workspace = true, optional = true } icu_provider_registry = { workspace = true } -icu_provider_blob = { workspace = true, features = ["export"], optional = true } +icu_provider_blob = { workspace = true, features = ["alloc"], optional = true } clap = { workspace = true, features = ["derive"] } eyre = { workspace = true } @@ -35,7 +35,7 @@ default = ["use_wasm", "networking", "fs_exporter", "blob_exporter", "baked_expo provider = ["dep:icu_provider_source"] baked_exporter = ["icu_provider_export/baked_exporter"] blob_exporter = ["icu_provider_export/blob_exporter"] -blob_input = ["dep:icu_provider_blob", "icu/datagen", "icu_provider/export"] +blob_input = ["dep:icu_provider_blob", "icu/datagen"] fs_exporter = ["icu_provider_export/fs_exporter"] # Use wasm for building codepointtries use_wasm = ["icu_provider_source?/use_wasm"] diff --git a/provider/source/Cargo.toml b/provider/source/Cargo.toml index a8fc2ef9ff2..4e3c9ac505f 100644 --- a/provider/source/Cargo.toml +++ b/provider/source/Cargo.toml @@ -47,7 +47,7 @@ tinystr = { workspace = true, features = ["alloc", "serde", "zerovec"] } potential_utf = { workspace = true } writeable = { workspace = true } zerotrie = { workspace = true, features = ["alloc"] } -zerovec = { workspace = true, features = ["serde", "yoke"] } +zerovec = { workspace = true, features = ["serde", "yoke", "alloc"] } # External dependencies displaydoc = { workspace = true } diff --git a/tools/md-tests/Cargo.toml b/tools/md-tests/Cargo.toml index 3384f3def39..9e70584bb40 100644 --- a/tools/md-tests/Cargo.toml +++ b/tools/md-tests/Cargo.toml @@ -14,7 +14,7 @@ icu_provider_export = { workspace = true, features = ["blob_exporter"] } icu_provider_source = { workspace = true, features = ["networking"] } icu_provider = { workspace = true, features = ["deserialize_json"] } icu_provider_adapters = { workspace = true, features = ["serde", "export"] } -icu_provider_blob = { workspace = true } +icu_provider_blob = { workspace = true, features = ["alloc"] } icu_provider_fs = { workspace = true } databake = { workspace = true, features = ["derive"] } diff --git a/tools/noalloctest/Cargo.toml b/tools/noalloctest/Cargo.toml index bccd4d37f7d..40037bb3592 100644 --- a/tools/noalloctest/Cargo.toml +++ b/tools/noalloctest/Cargo.toml @@ -20,12 +20,20 @@ publish = false [dependencies] # Dependencies that should be no-alloc should go here -tinystr = {workspace = true, default-features = false} -zerofrom = {workspace = true, default-features = false} -yoke = {workspace = true, default-features = false} -zerotrie = {workspace = true, default-features = false} -potential_utf = {workspace = true, default-features = false} -litemap = {workspace = true, default-features = false} +icu_calendar = { workspace = true } +icu_collections = { workspace = true } +icu_locale_core = { workspace = true } +icu_normalizer = { workspace = true } +icu_properties = { workspace = true } +icu_provider = { workspace = true } +icu_provider_baked = { workspace = true } +litemap = { workspace = true } +potential_utf = { workspace = true } +tinystr = { workspace = true } +yoke = { workspace = true } +zerofrom = { workspace = true } +zerotrie = { workspace = true } +zerovec = { workspace = true } [lints.rust] unexpected_cfgs = { level = "warn", check-cfg = ['cfg(icu4x_noalloctest)'] } diff --git a/tutorials/rust.md b/tutorials/rust.md index 0c1d0e17507..897afde865d 100644 --- a/tutorials/rust.md +++ b/tutorials/rust.md @@ -47,7 +47,7 @@ If you wish to generate your own data in blob format and pass it into ICU4X, ena ```toml [dependencies] icu = { version = "2.0.0-beta1", features = ["serde"] } -icu_provider_blob = "2.0.0-beta1" +icu_provider_blob = {version = "2.0.0-beta1", features = ["alloc"] } ``` To learn about building ICU4X data, including whether to check in the data blob file to your repository, see [data_management.md](./data_management.md). diff --git a/tutorials/rust/buffer/Cargo.toml b/tutorials/rust/buffer/Cargo.toml index 8244269ea60..945dec9a22e 100644 --- a/tutorials/rust/buffer/Cargo.toml +++ b/tutorials/rust/buffer/Cargo.toml @@ -13,4 +13,4 @@ publish = false [dependencies] icu = { version = "2.0.0-beta1", features = ["serde"] } -icu_provider_blob = "2.0.0-beta1" +icu_provider_blob = {version = "2.0.0-beta1", features = ["alloc"] } diff --git a/utils/potential_utf/Cargo.toml b/utils/potential_utf/Cargo.toml index ac47e731a29..39ca29330ad 100644 --- a/utils/potential_utf/Cargo.toml +++ b/utils/potential_utf/Cargo.toml @@ -26,8 +26,8 @@ serde_json = { workspace = true } bincode = { workspace = true } [features] -alloc = ["serde?/alloc"] +alloc = ["serde?/alloc", "zerovec?/alloc"] databake = ["dep:databake"] serde = ["dep:serde"] writeable = ["dep:writeable", "alloc"] -zerovec = ["dep:zerovec", "alloc"] +zerovec = ["dep:zerovec"] diff --git a/utils/potential_utf/src/ustr.rs b/utils/potential_utf/src/ustr.rs index c98d3a0fd0f..216f629b568 100644 --- a/utils/potential_utf/src/ustr.rs +++ b/utils/potential_utf/src/ustr.rs @@ -157,7 +157,7 @@ impl Deref for PotentialUtf8 { } /// This impl requires enabling the optional `zerovec` Cargo feature -#[cfg(feature = "zerovec")] +#[cfg(all(feature = "zerovec", feature = "alloc"))] impl<'a> zerovec::maps::ZeroMapKV<'a> for PotentialUtf8 { type Container = zerovec::VarZeroVec<'a, PotentialUtf8>; type Slice = zerovec::VarZeroSlice; diff --git a/utils/tinystr/Cargo.toml b/utils/tinystr/Cargo.toml index 0826c6654a4..8905b8d4a3b 100644 --- a/utils/tinystr/Cargo.toml +++ b/utils/tinystr/Cargo.toml @@ -40,7 +40,7 @@ criterion = { workspace = true } [features] default = ["alloc"] -alloc = [] +alloc = ["zerovec?/alloc"] zerovec = ["dep:zerovec"] databake = ["dep:databake"] serde = ["dep:serde"] diff --git a/utils/tinystr/src/ule.rs b/utils/tinystr/src/ule.rs index c6b8782f746..0dd10ff7d07 100644 --- a/utils/tinystr/src/ule.rs +++ b/utils/tinystr/src/ule.rs @@ -3,8 +3,10 @@ // (online at: https://github.com/unicode-org/icu4x/blob/main/LICENSE ). use crate::{TinyAsciiStr, UnvalidatedTinyAsciiStr}; +#[cfg(feature = "alloc")] use zerovec::maps::ZeroMapKV; use zerovec::ule::*; +#[cfg(feature = "alloc")] use zerovec::{ZeroSlice, ZeroVec}; // Safety (based on the safety checklist on the ULE trait): @@ -50,6 +52,7 @@ impl AsULE for TinyAsciiStr { } } +#[cfg(feature = "alloc")] impl<'a, const N: usize> ZeroMapKV<'a> for TinyAsciiStr { type Container = ZeroVec<'a, TinyAsciiStr>; type Slice = ZeroSlice>; @@ -90,6 +93,7 @@ impl AsULE for UnvalidatedTinyAsciiStr { } } +#[cfg(feature = "alloc")] impl<'a, const N: usize> ZeroMapKV<'a> for UnvalidatedTinyAsciiStr { type Container = ZeroVec<'a, UnvalidatedTinyAsciiStr>; type Slice = ZeroSlice>; diff --git a/utils/zerovec/Cargo.toml b/utils/zerovec/Cargo.toml index eef6d40c27c..be12c69f77c 100644 --- a/utils/zerovec/Cargo.toml +++ b/utils/zerovec/Cargo.toml @@ -54,10 +54,11 @@ criterion = { workspace = true } [features] derive = ["dep:zerovec-derive"] -hashmap = ["dep:twox-hash"] +hashmap = ["dep:twox-hash", "alloc"] yoke = ["dep:yoke"] -serde = ["dep:serde"] +serde = ["dep:serde", "alloc"] databake = ["dep:databake"] +alloc = [] [package.metadata.cargo-all-features] # We have tons of features here, limit the amount of tests we run diff --git a/utils/zerovec/src/cow.rs b/utils/zerovec/src/cow.rs index 7b90f2c4681..bf7ec5453e8 100644 --- a/utils/zerovec/src/cow.rs +++ b/utils/zerovec/src/cow.rs @@ -3,9 +3,11 @@ // (online at: https://github.com/unicode-org/icu4x/blob/main/LICENSE ). use crate::ule::{EncodeAsVarULE, UleError, VarULE}; +#[cfg(feature = "alloc")] use alloc::boxed::Box; use core::fmt; use core::marker::PhantomData; +#[cfg(feature = "alloc")] use core::mem::ManuallyDrop; use core::ops::Deref; use core::ptr::NonNull; @@ -40,8 +42,11 @@ pub struct VarZeroCow<'a, V: ?Sized> { /// The slice may NOT have the lifetime of `'a`. buf: NonNull<[u8]>, /// The buffer is `Box<[u8]>` if true + #[cfg(feature = "alloc")] owned: bool, - _phantom: PhantomData<(&'a V, Box)>, + marker1: PhantomData<&'a V>, + #[cfg(feature = "alloc")] + marker2: PhantomData, } // This is mostly just a `Cow<[u8]>`, safe to implement Send and Sync on @@ -50,33 +55,38 @@ unsafe impl<'a, V: ?Sized> Sync for VarZeroCow<'a, V> {} impl<'a, V: ?Sized> Clone for VarZeroCow<'a, V> { fn clone(&self) -> Self { + #[cfg(feature = "alloc")] if self.is_owned() { // This clones the box let b: Box<[u8]> = self.as_bytes().into(); let b = ManuallyDrop::new(b); let buf: NonNull<[u8]> = (&**b).into(); - Self { + return Self { // Invariants upheld: // 1 & 2: The bytes came from `self` so they're a valid value and byte slice // 3: This is owned (we cloned it), so we set owned to true. buf, owned: true, - _phantom: PhantomData, - } - } else { - // Unfortunately we can't just use `new_borrowed(self.deref())` since the lifetime is shorter - Self { - // Invariants upheld: - // 1 & 2: The bytes came from `self` so they're a valid value and byte slice - // 3: This is borrowed (we're sharing a borrow), so we set owned to false. - buf: self.buf, - owned: false, - _phantom: PhantomData, - } + marker1: PhantomData, + marker2: PhantomData, + }; + } + // Unfortunately we can't just use `new_borrowed(self.deref())` since the lifetime is shorter + Self { + // Invariants upheld: + // 1 & 2: The bytes came from `self` so they're a valid value and byte slice + // 3: This is borrowed (we're sharing a borrow), so we set owned to false. + buf: self.buf, + #[cfg(feature = "alloc")] + owned: false, + marker1: PhantomData, + #[cfg(feature = "alloc")] + marker2: PhantomData, } } } +#[cfg(feature = "alloc")] impl<'a, V: ?Sized> Drop for VarZeroCow<'a, V> { fn drop(&mut self) { if self.owned { @@ -97,6 +107,7 @@ impl<'a, V: VarULE + ?Sized> VarZeroCow<'a, V> { } /// Construct from an owned slice. Errors if the slice doesn't represent a valid `V` + #[cfg(feature = "alloc")] pub fn parse_owned_bytes(bytes: Box<[u8]>) -> Result { V::validate_bytes(&bytes)?; let bytes = ManuallyDrop::new(bytes); @@ -107,7 +118,8 @@ impl<'a, V: VarULE + ?Sized> VarZeroCow<'a, V> { // 3: This is owned, so we set owned to true. buf, owned: true, - _phantom: PhantomData, + marker1: PhantomData, + marker2: PhantomData, }) } @@ -126,8 +138,11 @@ impl<'a, V: VarULE + ?Sized> VarZeroCow<'a, V> { // 1 & 2: Passed upstream to caller // 3: This is borrowed, so we set owned to false. buf, + #[cfg(feature = "alloc")] owned: false, - _phantom: PhantomData, + marker1: PhantomData, + #[cfg(feature = "alloc")] + marker2: PhantomData, } } } @@ -135,6 +150,7 @@ impl<'a, V: VarULE + ?Sized> VarZeroCow<'a, V> { /// Construct this from an [`EncodeAsVarULE`] version of the contained type /// /// Will always construct an owned version + #[cfg(feature = "alloc")] pub fn from_encodeable>(encodeable: &E) -> Self { let b = crate::ule::encode_varule_to_box(encodeable); Self::new_owned(b) @@ -149,6 +165,7 @@ impl<'a, V: VarULE + ?Sized> VarZeroCow<'a, V> { } /// Construct a new borrowed version of this + #[cfg(feature = "alloc")] pub fn new_owned(val: Box) -> Self { let val = ManuallyDrop::new(val); let buf: NonNull<[u8]> = val.as_bytes().into(); @@ -157,8 +174,11 @@ impl<'a, V: VarULE + ?Sized> VarZeroCow<'a, V> { // 1 & 2: The bytes came from `val` so they're a valid value and byte slice // 3: This is owned, so we set owned to true. buf, + #[cfg(feature = "alloc")] owned: true, - _phantom: PhantomData, + marker1: PhantomData, + #[cfg(feature = "alloc")] + marker2: PhantomData, } } } @@ -166,7 +186,10 @@ impl<'a, V: VarULE + ?Sized> VarZeroCow<'a, V> { impl<'a, V: ?Sized> VarZeroCow<'a, V> { /// Whether or not this is owned pub fn is_owned(&self) -> bool { - self.owned + #[cfg(feature = "alloc")] + return self.owned; + #[cfg(not(feature = "alloc"))] + return false; } /// Get the byte representation of this type @@ -194,6 +217,7 @@ impl<'a, V: VarULE + ?Sized> From<&'a V> for VarZeroCow<'a, V> { } } +#[cfg(feature = "alloc")] impl<'a, V: VarULE + ?Sized> From> for VarZeroCow<'a, V> { fn from(other: Box) -> Self { Self::new_owned(other) diff --git a/utils/zerovec/src/hashmap/mod.rs b/utils/zerovec/src/hashmap/mod.rs index 5838eed3017..1900aa11ebd 100644 --- a/utils/zerovec/src/hashmap/mod.rs +++ b/utils/zerovec/src/hashmap/mod.rs @@ -4,8 +4,8 @@ use crate::map::{MutableZeroVecLike, ZeroMapKV, ZeroVecLike}; use crate::ZeroVec; -use alloc::borrow::Borrow; use alloc::vec::Vec; +use core::borrow::Borrow; use core::hash::Hash; pub mod algorithms; diff --git a/utils/zerovec/src/lib.rs b/utils/zerovec/src/lib.rs index 632287ecb11..c621a75d677 100644 --- a/utils/zerovec/src/lib.rs +++ b/utils/zerovec/src/lib.rs @@ -212,12 +212,15 @@ // is better here. #![allow(clippy::needless_lifetimes)] +#[cfg(feature = "alloc")] extern crate alloc; mod cow; #[cfg(feature = "hashmap")] pub mod hashmap; +#[cfg(feature = "alloc")] mod map; +#[cfg(feature = "alloc")] mod map2d; #[cfg(test)] pub mod samples; @@ -234,7 +237,9 @@ mod zerofrom_impls; pub use crate::cow::VarZeroCow; #[cfg(feature = "hashmap")] pub use crate::hashmap::ZeroHashMap; +#[cfg(feature = "alloc")] pub use crate::map::map::ZeroMap; +#[cfg(feature = "alloc")] pub use crate::map2d::map::ZeroMap2d; pub use crate::varzerovec::{slice::VarZeroSlice, vec::VarZeroVec}; pub use crate::zerovec::{ZeroSlice, ZeroVec}; @@ -243,13 +248,16 @@ pub use crate::zerovec::{ZeroSlice, ZeroVec}; pub mod __zerovec_internal_reexport { pub use zerofrom::ZeroFrom; + #[cfg(feature = "alloc")] pub use alloc::borrow; + #[cfg(feature = "alloc")] pub use alloc::boxed; #[cfg(feature = "serde")] pub use serde; } +#[cfg(feature = "alloc")] pub mod maps { //! This module contains additional utility types and traits for working with //! [`ZeroMap`] and [`ZeroMap2d`]. See their docs for more details on the general purpose @@ -295,9 +303,9 @@ pub mod vecs { #[doc(no_inline)] pub use crate::varzerovec::{VarZeroSlice, VarZeroVec}; - pub use crate::varzerovec::{ - Index16, Index32, Index8, VarZeroSliceIter, VarZeroVecFormat, VarZeroVecOwned, - }; + #[cfg(feature = "alloc")] + pub use crate::varzerovec::VarZeroVecOwned; + pub use crate::varzerovec::{Index16, Index32, Index8, VarZeroSliceIter, VarZeroVecFormat}; pub type VarZeroVec16<'a, T> = VarZeroVec<'a, T, Index16>; pub type VarZeroVec32<'a, T> = VarZeroVec<'a, T, Index32>; diff --git a/utils/zerovec/src/ule/encode.rs b/utils/zerovec/src/ule/encode.rs index fa73518ea10..a3515ff061a 100644 --- a/utils/zerovec/src/ule/encode.rs +++ b/utils/zerovec/src/ule/encode.rs @@ -5,10 +5,15 @@ use crate::ule::*; use crate::varzerovec::VarZeroVecFormat; use crate::{VarZeroSlice, VarZeroVec, ZeroSlice, ZeroVec}; +#[cfg(feature = "alloc")] use alloc::borrow::{Cow, ToOwned}; +#[cfg(feature = "alloc")] use alloc::boxed::Box; +#[cfg(feature = "alloc")] use alloc::string::String; +#[cfg(feature = "alloc")] use alloc::{vec, vec::Vec}; +#[cfg(feature = "alloc")] use core::mem; /// Allows types to be encoded as VarULEs. This is highly useful for implementing VarULE on @@ -81,6 +86,7 @@ pub unsafe trait EncodeAsVarULE { /// Given an [`EncodeAsVarULE`] type `S`, encode it into a `Box` /// /// This is primarily useful for generating `Deserialize` impls for VarULE types +#[cfg(feature = "alloc")] pub fn encode_varule_to_box + ?Sized, T: VarULE + ?Sized>(x: &S) -> Box { // zero-fill the vector to avoid uninitialized data UB let mut vec: Vec = vec![0; x.encode_var_ule_len()]; @@ -114,6 +120,7 @@ unsafe impl EncodeAsVarULE for &'_ &'_ T { } } +#[cfg(feature = "alloc")] unsafe impl EncodeAsVarULE for Cow<'_, T> where T: ToOwned, @@ -123,24 +130,28 @@ where } } +#[cfg(feature = "alloc")] unsafe impl EncodeAsVarULE for Box { fn encode_var_ule_as_slices(&self, cb: impl FnOnce(&[&[u8]]) -> R) -> R { cb(&[T::as_bytes(self)]) } } +#[cfg(feature = "alloc")] unsafe impl EncodeAsVarULE for &'_ Box { fn encode_var_ule_as_slices(&self, cb: impl FnOnce(&[&[u8]]) -> R) -> R { cb(&[T::as_bytes(self)]) } } +#[cfg(feature = "alloc")] unsafe impl EncodeAsVarULE for String { fn encode_var_ule_as_slices(&self, cb: impl FnOnce(&[&[u8]]) -> R) -> R { cb(&[self.as_bytes()]) } } +#[cfg(feature = "alloc")] unsafe impl EncodeAsVarULE for &'_ String { fn encode_var_ule_as_slices(&self, cb: impl FnOnce(&[&[u8]]) -> R) -> R { cb(&[self.as_bytes()]) @@ -149,6 +160,7 @@ unsafe impl EncodeAsVarULE for &'_ String { // Note: This impl could technically use `T: AsULE`, but we want users to prefer `ZeroSlice` // for cases where T is not a ULE. Therefore, we can use the more efficient `memcpy` impl here. +#[cfg(feature = "alloc")] unsafe impl EncodeAsVarULE<[T]> for Vec where T: ULE, @@ -183,6 +195,7 @@ where } } +#[cfg(feature = "alloc")] unsafe impl EncodeAsVarULE> for Vec where T: AsULE + 'static, @@ -244,6 +257,7 @@ where } } +#[cfg(feature = "alloc")] unsafe impl EncodeAsVarULE> for Vec where T: VarULE + ?Sized, diff --git a/utils/zerovec/src/ule/mod.rs b/utils/zerovec/src/ule/mod.rs index 1803a81e4ca..bcc3428333f 100644 --- a/utils/zerovec/src/ule/mod.rs +++ b/utils/zerovec/src/ule/mod.rs @@ -27,15 +27,14 @@ pub mod tuple; pub mod tuplevar; pub mod vartuple; pub use chars::CharULE; -pub use encode::{encode_varule_to_box, EncodeAsVarULE}; +#[cfg(feature = "alloc")] +pub use encode::encode_varule_to_box; +pub use encode::EncodeAsVarULE; pub use multi::MultiFieldsULE; pub use niche::{NicheBytes, NichedOption, NichedOptionULE}; pub use option::{OptionULE, OptionVarULE}; pub use plain::RawBytesULE; -use alloc::alloc::Layout; -use alloc::borrow::ToOwned; -use alloc::boxed::Box; use core::{any, fmt, mem, slice}; /// Fixed-width, byte-aligned data that can be cast to and from a little-endian byte slice. @@ -358,7 +357,11 @@ pub unsafe trait VarULE: 'static { /// Allocate on the heap as a `Box` #[inline] - fn to_boxed(&self) -> Box { + #[cfg(feature = "alloc")] + fn to_boxed(&self) -> alloc::boxed::Box { + use alloc::borrow::ToOwned; + use alloc::boxed::Box; + use core::alloc::Layout; let bytesvec = self.as_bytes().to_owned().into_boxed_slice(); let bytesvec = mem::ManuallyDrop::new(bytesvec); unsafe { diff --git a/utils/zerovec/src/ule/niche.rs b/utils/zerovec/src/ule/niche.rs index 466f92e649d..35b3c407900 100644 --- a/utils/zerovec/src/ule/niche.rs +++ b/utils/zerovec/src/ule/niche.rs @@ -4,7 +4,10 @@ use core::{marker::Copy, mem::size_of}; -use crate::{map::ZeroMapKV, ZeroSlice, ZeroVec}; +#[cfg(feature = "alloc")] +use crate::map::ZeroMapKV; +#[cfg(feature = "alloc")] +use crate::{ZeroSlice, ZeroVec}; use super::{AsULE, ULE}; @@ -182,6 +185,7 @@ where } } +#[cfg(feature = "alloc")] impl<'a, T: AsULE + 'static, const N: usize> ZeroMapKV<'a> for NichedOption where T::ULE: NicheBytes, diff --git a/utils/zerovec/src/ule/tuple.rs b/utils/zerovec/src/ule/tuple.rs index cb7a710e393..0aba71c55c7 100644 --- a/utils/zerovec/src/ule/tuple.rs +++ b/utils/zerovec/src/ule/tuple.rs @@ -117,6 +117,7 @@ macro_rules! tuple_ule { impl<$($t: ULE),+> Copy for $name<$($t),+> {} + #[cfg(feature = "alloc")] impl<'a, $($t: Ord + AsULE + 'static),+> crate::map::ZeroMapKV<'a> for ($($t),+) { type Container = crate::ZeroVec<'a, ($($t),+)>; type Slice = crate::ZeroSlice<($($t),+)>; diff --git a/utils/zerovec/src/ule/tuplevar.rs b/utils/zerovec/src/ule/tuplevar.rs index 9863e974167..2f20f75a79b 100644 --- a/utils/zerovec/src/ule/tuplevar.rs +++ b/utils/zerovec/src/ule/tuplevar.rs @@ -13,7 +13,6 @@ use super::*; use crate::varzerovec::{Index16, VarZeroVecFormat}; -use alloc::borrow::ToOwned; use core::fmt; use core::marker::PhantomData; use core::mem; @@ -160,8 +159,9 @@ macro_rules! tuple_varule { } } - impl<$($T: VarULE + ?Sized,)+ Format: VarZeroVecFormat> ToOwned for $name<$($T,)+ Format> { - type Owned = Box; + #[cfg(feature = "alloc")] + impl<$($T: VarULE + ?Sized,)+ Format: VarZeroVecFormat> alloc::borrow::ToOwned for $name<$($T,)+ Format> { + type Owned = alloc::boxed::Box; fn to_owned(&self) -> Self::Owned { encode_varule_to_box(self) } @@ -200,14 +200,14 @@ macro_rules! tuple_varule { } #[cfg(feature = "serde")] - impl<'de, $($T: VarULE + ?Sized,)+ Format> serde::Deserialize<'de> for Box<$name<$($T,)+ Format>> + impl<'de, $($T: VarULE + ?Sized,)+ Format> serde::Deserialize<'de> for alloc::boxed::Box<$name<$($T,)+ Format>> where // This impl should be present on almost all deserializable VarULE types - $( Box<$T>: serde::Deserialize<'de>,)+ + $( alloc::boxed::Box<$T>: serde::Deserialize<'de>,)+ Format: VarZeroVecFormat { fn deserialize(deserializer: Des) -> Result where Des: serde::Deserializer<'de> { if deserializer.is_human_readable() { - let this = <( $(Box<$T>),+) as serde::Deserialize>::deserialize(deserializer)?; + let this = <( $(alloc::boxed::Box<$T>),+) as serde::Deserialize>::deserialize(deserializer)?; let this_ref = ( $(&*this.$i),+ ); diff --git a/utils/zerovec/src/ule/vartuple.rs b/utils/zerovec/src/ule/vartuple.rs index 16f14763229..7bccd1c84c3 100644 --- a/utils/zerovec/src/ule/vartuple.rs +++ b/utils/zerovec/src/ule/vartuple.rs @@ -49,8 +49,6 @@ //! assert_eq!(&employees_vzv.get(1).unwrap().variable, "John Doe"); //! ``` -use alloc::borrow::ToOwned; -use alloc::boxed::Box; use core::mem::{size_of, transmute_copy}; use zerofrom::ZeroFrom; @@ -178,12 +176,13 @@ where } } -impl ToOwned for VarTupleULE +#[cfg(feature = "alloc")] +impl alloc::borrow::ToOwned for VarTupleULE where A: AsULE + 'static, V: VarULE + ?Sized, { - type Owned = Box; + type Owned = alloc::boxed::Box; fn to_owned(&self) -> Self::Owned { crate::ule::encode_varule_to_box(self) } @@ -250,19 +249,19 @@ where } #[cfg(feature = "serde")] -impl<'de, A, V> serde::Deserialize<'de> for Box> +impl<'de, A, V> serde::Deserialize<'de> for alloc::boxed::Box> where A: AsULE + 'static, V: VarULE + ?Sized, A: serde::Deserialize<'de>, - Box: serde::Deserialize<'de>, + alloc::boxed::Box: serde::Deserialize<'de>, { fn deserialize(deserializer: Des) -> Result where Des: serde::Deserializer<'de>, { if deserializer.is_human_readable() { - let this = VarTuple::>::deserialize(deserializer)?; + let this = VarTuple::>::deserialize(deserializer)?; Ok(crate::ule::encode_varule_to_box(&this)) } else { // This branch should usually not be hit, since Cow-like use cases will hit the Deserialize impl for &'a TupleNVarULE instead. diff --git a/utils/zerovec/src/varzerovec/components.rs b/utils/zerovec/src/varzerovec/components.rs index e40046fe839..d5ff8c114df 100644 --- a/utils/zerovec/src/varzerovec/components.rs +++ b/utils/zerovec/src/varzerovec/components.rs @@ -4,10 +4,6 @@ use super::VarZeroVecFormatError; use crate::ule::*; -use alloc::boxed::Box; -use alloc::format; -use alloc::string::String; -use alloc::vec::Vec; use core::cmp::Ordering; use core::convert::TryFrom; use core::marker::PhantomData; @@ -65,6 +61,7 @@ pub unsafe trait IntegerULE: ULE { /// Safety: Should always convert a buffer into an array of Self with the correct length #[doc(hidden)] + #[cfg(feature = "alloc")] fn iule_from_bytes_unchecked_mut(bytes: &mut [u8]) -> &mut [Self]; } @@ -123,6 +120,7 @@ unsafe impl IntegerULE for u8 { u8::try_from(u).ok() } #[inline] + #[cfg(feature = "alloc")] fn iule_from_bytes_unchecked_mut(bytes: &mut [u8]) -> &mut [Self] { bytes } @@ -142,6 +140,7 @@ unsafe impl IntegerULE for RawBytesULE<2> { u16::try_from(u).ok().map(u16::to_unaligned) } #[inline] + #[cfg(feature = "alloc")] fn iule_from_bytes_unchecked_mut(bytes: &mut [u8]) -> &mut [Self] { Self::from_bytes_unchecked_mut(bytes) } @@ -161,6 +160,7 @@ unsafe impl IntegerULE for RawBytesULE<4> { u32::try_from(u).ok().map(u32::to_unaligned) } #[inline] + #[cfg(feature = "alloc")] fn iule_from_bytes_unchecked_mut(bytes: &mut [u8]) -> &mut [Self] { Self::from_bytes_unchecked_mut(bytes) } @@ -478,7 +478,8 @@ impl<'a, T: VarULE + ?Sized, F: VarZeroVecFormat> VarZeroVecComponents<'a, T, F> VarZeroSliceIter::new(self) } - pub fn to_vec(self) -> Vec> { + #[cfg(feature = "alloc")] + pub fn to_vec(self) -> alloc::vec::Vec> { self.iter().map(T::to_boxed).collect() } @@ -489,14 +490,15 @@ impl<'a, T: VarULE + ?Sized, F: VarZeroVecFormat> VarZeroVecComponents<'a, T, F> // Dump a debuggable representation of this type #[allow(unused)] // useful for debugging - pub(crate) fn dump(&self) -> String { + #[cfg(feature = "alloc")] + pub(crate) fn dump(&self) -> alloc::string::String { let indices = self .indices_slice() .iter() .copied() .map(IntegerULE::iule_to_usize) - .collect::>(); - format!("VarZeroVecComponents {{ indices: {indices:?} }}") + .collect::>(); + alloc::format!("VarZeroVecComponents {{ indices: {indices:?} }}") } } @@ -677,7 +679,8 @@ where } /// Collects the bytes for a VarZeroSlice into a Vec. -pub fn get_serializable_bytes_non_empty(elements: &[A]) -> Option> +#[cfg(feature = "alloc")] +pub fn get_serializable_bytes_non_empty(elements: &[A]) -> Option> where T: VarULE + ?Sized, A: EncodeAsVarULE, @@ -689,7 +692,7 @@ where len >= F::Len::SIZE as u32, "Must have at least F::Len::SIZE bytes to hold the length of the vector" ); - let mut output: Vec = alloc::vec![0; len as usize]; + let mut output = alloc::vec![0u8; len as usize]; write_serializable_bytes::(elements, &mut output); Some(output) } diff --git a/utils/zerovec/src/varzerovec/mod.rs b/utils/zerovec/src/varzerovec/mod.rs index 2c2ddc51f08..43ae91df401 100644 --- a/utils/zerovec/src/varzerovec/mod.rs +++ b/utils/zerovec/src/varzerovec/mod.rs @@ -7,6 +7,7 @@ pub(crate) mod components; pub(crate) mod error; pub(crate) mod lengthless; +#[cfg(feature = "alloc")] pub(crate) mod owned; pub(crate) mod slice; pub(crate) mod vec; @@ -24,6 +25,7 @@ pub use components::VarZeroVecComponents; pub use components::{Index16, Index32, Index8, VarZeroSliceIter, VarZeroVecFormat}; +#[cfg(feature = "alloc")] pub use owned::VarZeroVecOwned; pub use error::VarZeroVecFormatError; diff --git a/utils/zerovec/src/varzerovec/owned.rs b/utils/zerovec/src/varzerovec/owned.rs index b55007732d2..7a23b4f4a88 100644 --- a/utils/zerovec/src/varzerovec/owned.rs +++ b/utils/zerovec/src/varzerovec/owned.rs @@ -10,7 +10,6 @@ use super::*; use crate::ule::*; -use alloc::boxed::Box; use alloc::vec::Vec; use core::any; use core::convert::TryInto; @@ -28,7 +27,8 @@ use super::components::IntegerULE; /// The `F` type parameter is a [`VarZeroVecFormat`] (see its docs for more details), which can be used to select the /// precise format of the backing buffer with various size and performance tradeoffs. It defaults to [`Index16`]. pub struct VarZeroVecOwned { - marker: PhantomData<(Box, F)>, + marker1: PhantomData, + marker2: PhantomData, // safety invariant: must parse into a valid VarZeroVecComponents entire_slice: Vec, } @@ -36,7 +36,8 @@ pub struct VarZeroVecOwned { impl Clone for VarZeroVecOwned { fn clone(&self) -> Self { VarZeroVecOwned { - marker: self.marker, + marker1: PhantomData, + marker2: PhantomData, entire_slice: self.entire_slice.clone(), } } @@ -61,7 +62,8 @@ impl VarZeroVecOwned { /// Construct an empty VarZeroVecOwned pub fn new() -> Self { Self { - marker: PhantomData, + marker1: PhantomData, + marker2: PhantomData, entire_slice: Vec::new(), } } @@ -71,7 +73,8 @@ impl VarZeroVecOwned { /// Construct a VarZeroVecOwned from a [`VarZeroSlice`] by cloning the internal data pub fn from_slice(slice: &VarZeroSlice) -> Self { Self { - marker: PhantomData, + marker1: PhantomData, + marker2: PhantomData, entire_slice: slice.as_bytes().into(), } } @@ -85,7 +88,8 @@ impl VarZeroVecOwned { Self::from_slice(VarZeroSlice::new_empty()) } else { Self { - marker: PhantomData, + marker1: PhantomData, + marker2: PhantomData, // TODO(#1410): Rethink length errors in VZV. entire_slice: components::get_serializable_bytes_non_empty::(elements) .ok_or(F::Index::TOO_LARGE_ERROR)?, @@ -107,7 +111,8 @@ impl VarZeroVecOwned { /// just allocate enough space for 4-byte Ts pub(crate) fn with_capacity(capacity: usize) -> Self { Self { - marker: PhantomData, + marker1: PhantomData, + marker2: PhantomData, entire_slice: Vec::with_capacity(capacity * (F::Index::SIZE + 4)), } } diff --git a/utils/zerovec/src/varzerovec/slice.rs b/utils/zerovec/src/varzerovec/slice.rs index 03801042f0a..2305c86c2ba 100644 --- a/utils/zerovec/src/varzerovec/slice.rs +++ b/utils/zerovec/src/varzerovec/slice.rs @@ -6,8 +6,6 @@ use super::components::{VarZeroSliceIter, VarZeroVecComponents}; use super::vec::VarZeroVecInner; use super::*; use crate::ule::*; -use alloc::boxed::Box; -use alloc::vec::Vec; use core::cmp::{Ord, Ordering, PartialOrd}; use core::fmt; use core::marker::PhantomData; @@ -231,7 +229,8 @@ impl VarZeroSlice { } /// Obtain an owned `Vec>` out of this - pub fn to_vec(&self) -> Vec> { + #[cfg(feature = "alloc")] + pub fn to_vec(&self) -> alloc::vec::Vec> { self.as_components().to_vec() } diff --git a/utils/zerovec/src/varzerovec/vec.rs b/utils/zerovec/src/varzerovec/vec.rs index 9c3f89470c5..c3261264fb7 100644 --- a/utils/zerovec/src/varzerovec/vec.rs +++ b/utils/zerovec/src/varzerovec/vec.rs @@ -4,7 +4,6 @@ use crate::ule::*; -use alloc::vec::Vec; use core::cmp::{Ord, Ordering, PartialOrd}; use core::fmt; use core::ops::Deref; @@ -142,6 +141,7 @@ use super::*; pub struct VarZeroVec<'a, T: ?Sized, F = Index16>(pub(crate) VarZeroVecInner<'a, T, F>); pub(crate) enum VarZeroVecInner<'a, T: ?Sized, F = Index16> { + #[cfg(feature = "alloc")] Owned(VarZeroVecOwned), Borrowed(&'a VarZeroSlice), } @@ -149,6 +149,7 @@ pub(crate) enum VarZeroVecInner<'a, T: ?Sized, F = Index16> { impl<'a, T: ?Sized, F> Clone for VarZeroVec<'a, T, F> { fn clone(&self) -> Self { match self.0 { + #[cfg(feature = "alloc")] VarZeroVecInner::Owned(ref o) => o.clone().into(), VarZeroVecInner::Borrowed(b) => b.into(), } @@ -164,6 +165,7 @@ where } } +#[cfg(feature = "alloc")] impl<'a, T: ?Sized, F> From> for VarZeroVec<'a, T, F> { #[inline] fn from(other: VarZeroVecOwned) -> Self { @@ -177,6 +179,7 @@ impl<'a, T: ?Sized, F> From<&'a VarZeroSlice> for VarZeroVec<'a, T, F> { } } +#[cfg(feature = "alloc")] impl<'a, T: ?Sized + VarULE, F: VarZeroVecFormat> From> for VarZeroVecOwned { @@ -277,6 +280,7 @@ impl<'a, T: VarULE + ?Sized, F: VarZeroVecFormat> VarZeroVec<'a, T, F> { // // This function is crate-public for now since we don't yet want to stabilize // the internal implementation details + #[cfg(feature = "alloc")] pub fn make_mut(&mut self) -> &mut VarZeroVecOwned { match self.0 { VarZeroVecInner::Owned(ref mut vec) => vec, @@ -303,6 +307,7 @@ impl<'a, T: VarULE + ?Sized, F: VarZeroVecFormat> VarZeroVec<'a, T, F> { /// // has 'static lifetime /// let owned = vec.into_owned(); /// ``` + #[cfg(feature = "alloc")] pub fn into_owned(mut self) -> VarZeroVec<'static, T, F> { self.make_mut(); match self.0 { @@ -314,6 +319,7 @@ impl<'a, T: VarULE + ?Sized, F: VarZeroVecFormat> VarZeroVec<'a, T, F> { /// Obtain this `VarZeroVec` as a [`VarZeroSlice`] pub fn as_slice(&self) -> &VarZeroSlice { match self.0 { + #[cfg(feature = "alloc")] VarZeroVecInner::Owned(ref owned) => owned, VarZeroVecInner::Borrowed(b) => b, } @@ -338,8 +344,10 @@ impl<'a, T: VarULE + ?Sized, F: VarZeroVecFormat> VarZeroVec<'a, T, F> { /// VarZeroVec::parse_bytes(&bytes).unwrap(); /// assert_eq!(borrowed, &*strings); /// ``` - pub fn into_bytes(self) -> Vec { + #[cfg(feature = "alloc")] + pub fn into_bytes(self) -> alloc::vec::Vec { match self.0 { + #[cfg(feature = "alloc")] VarZeroVecInner::Owned(vec) => vec.into_bytes(), VarZeroVecInner::Borrowed(vec) => vec.as_bytes().to_vec(), } @@ -350,6 +358,7 @@ impl<'a, T: VarULE + ?Sized, F: VarZeroVecFormat> VarZeroVec<'a, T, F> { /// be used to force it into an owned type pub fn is_owned(&self) -> bool { match self.0 { + #[cfg(feature = "alloc")] VarZeroVecInner::Owned(..) => true, VarZeroVecInner::Borrowed(..) => false, } @@ -361,18 +370,20 @@ impl<'a, T: VarULE + ?Sized, F: VarZeroVecFormat> VarZeroVec<'a, T, F> { } } -impl From<&Vec> for VarZeroVec<'static, T, F> +#[cfg(feature = "alloc")] +impl From<&alloc::vec::Vec> for VarZeroVec<'static, T, F> where T: VarULE + ?Sized, A: EncodeAsVarULE, F: VarZeroVecFormat, { #[inline] - fn from(elements: &Vec) -> Self { + fn from(elements: &alloc::vec::Vec) -> Self { Self::from(elements.as_slice()) } } +#[cfg(feature = "alloc")] impl From<&[A]> for VarZeroVec<'static, T, F> where T: VarULE + ?Sized, @@ -390,6 +401,7 @@ where } } +#[cfg(feature = "alloc")] impl From<&[A; N]> for VarZeroVec<'static, T, F> where T: VarULE + ?Sized, diff --git a/utils/zerovec/src/yoke_impls.rs b/utils/zerovec/src/yoke_impls.rs index 512900dcd32..ced30a62ec4 100644 --- a/utils/zerovec/src/yoke_impls.rs +++ b/utils/zerovec/src/yoke_impls.rs @@ -9,11 +9,16 @@ #![allow(clippy::forget_copy)] #![allow(clippy::forget_non_drop)] +#[cfg(feature = "alloc")] use crate::map::ZeroMapBorrowed; +#[cfg(feature = "alloc")] use crate::map::ZeroMapKV; +#[cfg(feature = "alloc")] use crate::map2d::ZeroMap2dBorrowed; use crate::ule::*; -use crate::{VarZeroCow, VarZeroVec, ZeroMap, ZeroMap2d, ZeroVec}; +use crate::{VarZeroCow, VarZeroVec, ZeroVec}; +#[cfg(feature = "alloc")] +use crate::{ZeroMap, ZeroMap2d}; use core::{mem, ptr}; use yoke::*; @@ -103,6 +108,7 @@ unsafe impl<'a, T: 'static + ?Sized> Yokeable<'a> for VarZeroCow<'static, T> { /// This impl requires enabling the optional `yoke` Cargo feature of the `zerovec` crate #[allow(clippy::transmute_ptr_to_ptr)] +#[cfg(feature = "alloc")] unsafe impl<'a, K, V> Yokeable<'a> for ZeroMap<'static, K, V> where K: 'static + for<'b> ZeroMapKV<'b> + ?Sized, @@ -149,6 +155,7 @@ where /// This impl requires enabling the optional `yoke` Cargo feature of the `zerovec` crate #[allow(clippy::transmute_ptr_to_ptr)] +#[cfg(feature = "alloc")] unsafe impl<'a, K, V> Yokeable<'a> for ZeroMapBorrowed<'static, K, V> where K: 'static + for<'b> ZeroMapKV<'b> + ?Sized, @@ -195,6 +202,7 @@ where /// This impl requires enabling the optional `yoke` Cargo feature of the `zerovec` crate #[allow(clippy::transmute_ptr_to_ptr)] +#[cfg(feature = "alloc")] unsafe impl<'a, K0, K1, V> Yokeable<'a> for ZeroMap2d<'static, K0, K1, V> where K0: 'static + for<'b> ZeroMapKV<'b> + ?Sized, @@ -243,6 +251,7 @@ where /// This impl requires enabling the optional `yoke` Cargo feature of the `zerovec` crate #[allow(clippy::transmute_ptr_to_ptr)] +#[cfg(feature = "alloc")] unsafe impl<'a, K0, K1, V> Yokeable<'a> for ZeroMap2dBorrowed<'static, K0, K1, V> where K0: 'static + for<'b> ZeroMapKV<'b> + ?Sized, diff --git a/utils/zerovec/src/zerofrom_impls.rs b/utils/zerovec/src/zerofrom_impls.rs index a41915ef795..6ba88dd5e79 100644 --- a/utils/zerovec/src/zerofrom_impls.rs +++ b/utils/zerovec/src/zerofrom_impls.rs @@ -2,10 +2,13 @@ // called LICENSE at the top level of the ICU4X source tree // (online at: https://github.com/unicode-org/icu4x/blob/main/LICENSE ). +#[cfg(feature = "alloc")] use crate::map::ZeroMapKV; use crate::ule::*; use crate::vecs::VarZeroVecFormat; -use crate::{VarZeroSlice, VarZeroVec, ZeroMap, ZeroMap2d, ZeroSlice, ZeroVec}; +use crate::{VarZeroSlice, VarZeroVec, ZeroSlice, ZeroVec}; +#[cfg(feature = "alloc")] +use crate::{ZeroMap, ZeroMap2d}; use zerofrom::ZeroFrom; impl<'zf, T> ZeroFrom<'zf, ZeroVec<'_, T>> for ZeroVec<'zf, T> @@ -68,6 +71,7 @@ where } } +#[cfg(feature = "alloc")] impl<'zf, 's, K, V> ZeroFrom<'zf, ZeroMap<'s, K, V>> for ZeroMap<'zf, K, V> where K: 'static + for<'b> ZeroMapKV<'b> + ?Sized, @@ -83,6 +87,7 @@ where } } +#[cfg(feature = "alloc")] impl<'zf, 's, K0, K1, V> ZeroFrom<'zf, ZeroMap2d<'s, K0, K1, V>> for ZeroMap2d<'zf, K0, K1, V> where K0: 'static + for<'b> ZeroMapKV<'b> + ?Sized, diff --git a/utils/zerovec/src/zerovec/mod.rs b/utils/zerovec/src/zerovec/mod.rs index 9bbbac6101a..b4136c8c6d1 100644 --- a/utils/zerovec/src/zerovec/mod.rs +++ b/utils/zerovec/src/zerovec/mod.rs @@ -14,13 +14,15 @@ pub use slice::ZeroSlice; pub use slice::ZeroSliceIter; use crate::ule::*; +#[cfg(feature = "alloc")] use alloc::borrow::Cow; +#[cfg(feature = "alloc")] use alloc::vec::Vec; use core::cmp::{Ord, Ordering, PartialOrd}; use core::fmt; +#[cfg(feature = "alloc")] use core::iter::FromIterator; use core::marker::PhantomData; -use core::mem; use core::num::NonZeroUsize; use core::ops::Deref; use core::ptr::NonNull; @@ -95,8 +97,8 @@ where /// Marker type, signalling variance and dropck behavior /// by containing all potential types this type represents - #[allow(clippy::type_complexity)] // needed to get correct marker type behavior - marker: PhantomData<(Vec, &'a [T::ULE])>, + marker1: PhantomData, + marker2: PhantomData<&'a T::ULE>, } // Send inherits as long as all fields are Send, but also references are Send only @@ -153,6 +155,7 @@ impl EyepatchHackVector { /// data, make sure that `self` is cleaned up after this /// /// (this does not simply take `self` since then it wouldn't be usable from the Drop impl) + #[cfg(feature = "alloc")] unsafe fn get_vec(&self) -> Vec { debug_assert!(self.capacity != 0); let slice: &[U] = self.as_slice(); @@ -163,6 +166,7 @@ impl EyepatchHackVector { } } +#[cfg(feature = "alloc")] impl Drop for EyepatchHackVector { #[inline] fn drop(&mut self) { @@ -177,16 +181,17 @@ impl Drop for EyepatchHackVector { impl<'a, T: AsULE> Clone for ZeroVec<'a, T> { fn clone(&self) -> Self { + #[cfg(feature = "alloc")] if self.is_owned() { - ZeroVec::new_owned(self.as_ule_slice().into()) - } else { - Self { - vector: EyepatchHackVector { - buf: self.vector.buf, - capacity: 0, - }, - marker: PhantomData, - } + return ZeroVec::new_owned(self.as_ule_slice().into()); + } + Self { + vector: EyepatchHackVector { + buf: self.vector.buf, + capacity: 0, + }, + marker1: PhantomData, + marker2: PhantomData, } } } @@ -202,7 +207,16 @@ where T: AsULE + fmt::Debug, { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "ZeroVec({:?})", self.to_vec()) + write!(f, "ZeroVec([")?; + let mut first = true; + for el in self.iter() { + if !first { + write!(f, ", ")?; + } + write!(f, "{el:?}")?; + first = false; + } + write!(f, "])") } } @@ -270,6 +284,7 @@ impl<'a, T: AsULE> From<&'a [T::ULE]> for ZeroVec<'a, T> { } } +#[cfg(feature = "alloc")] impl<'a, T: AsULE> From> for ZeroVec<'a, T> { fn from(other: Vec) -> Self { ZeroVec::new_owned(other) @@ -303,13 +318,14 @@ impl<'a, T: AsULE> ZeroVec<'a, T> { /// If you have a slice of `&[T]`s, prefer using /// [`Self::alloc_from_slice()`]. #[inline] + #[cfg(feature = "alloc")] pub fn new_owned(vec: Vec) -> Self { // Deconstruct the vector into parts // This is the only part of the code that goes from Vec // to ZeroVec, all other such operations should use this function let capacity = vec.capacity(); let len = vec.len(); - let ptr = mem::ManuallyDrop::new(vec).as_mut_ptr(); + let ptr = core::mem::ManuallyDrop::new(vec).as_mut_ptr(); // Safety: `ptr` comes from Vec::as_mut_ptr, which says: // "Returns an unsafe mutable pointer to the vector’s buffer, // or a dangling raw pointer valid for zero sized reads" @@ -317,7 +333,8 @@ impl<'a, T: AsULE> ZeroVec<'a, T> { let buf = NonNull::slice_from_raw_parts(ptr, len); Self { vector: EyepatchHackVector { buf, capacity }, - marker: PhantomData, + marker1: PhantomData, + marker2: PhantomData, } } @@ -333,11 +350,13 @@ impl<'a, T: AsULE> ZeroVec<'a, T> { buf: slice, capacity: 0, }, - marker: PhantomData, + marker1: PhantomData, + marker2: PhantomData, } } /// Creates a new, owned, empty `ZeroVec`, with a certain capacity pre-allocated. + #[cfg(feature = "alloc")] pub fn with_capacity(capacity: usize) -> Self { Self::new_owned(Vec::with_capacity(capacity)) } @@ -416,7 +435,9 @@ impl<'a, T: AsULE> ZeroVec<'a, T> { /// assert!(zv_bytes.is_owned()); /// assert_eq!(zv_bytes.get(0), Some(0xD3)); /// ``` + #[cfg(feature = "alloc")] pub fn into_bytes(self) -> ZeroVec<'a, u8> { + use alloc::borrow::Cow; match self.into_cow() { Cow::Borrowed(slice) => { let bytes: &'a [u8] = T::ULE::slice_as_bytes(slice); @@ -460,6 +481,7 @@ impl<'a, T: AsULE> ZeroVec<'a, T> { /// let zerovec_i16: ZeroVec = zerovec_u16.cast(); /// assert_eq!(zerovec_i16.get(3), Some(-32563)); /// ``` + #[cfg(feature = "alloc")] pub fn cast

(self) -> ZeroVec<'a, P> where P: AsULE, @@ -518,7 +540,7 @@ impl<'a, T: AsULE> ZeroVec<'a, T> { /// let zv_char: ZeroVec = /// ZeroVec::parse_bytes(bytes).expect("valid code points"); /// - /// // Panics! mem::size_of:: != mem::size_of:: + /// // Panics! core::mem::size_of:: != core::mem::size_of:: /// zv_char.try_into_converted::(); /// ``` /// @@ -536,6 +558,7 @@ impl<'a, T: AsULE> ZeroVec<'a, T> { /// assert!(!zv_u16.is_owned()); /// assert_eq!(zv_u16.get(0), Some(0xF37F)); /// ``` + #[cfg(feature = "alloc")] pub fn try_into_converted(self) -> Result, UleError> { assert_eq!( core::mem::size_of::<::ULE>(), @@ -553,7 +576,7 @@ impl<'a, T: AsULE> ZeroVec<'a, T> { // Feature "vec_into_raw_parts" is not yet stable (#65816). Polyfill: let (ptr, len, cap) = { // Take ownership of the pointer - let mut v = mem::ManuallyDrop::new(old_vec); + let mut v = core::mem::ManuallyDrop::new(old_vec); // Fetch the pointer, length, and capacity (v.as_mut_ptr(), v.len(), v.capacity()) }; @@ -655,6 +678,7 @@ impl<'a> ZeroVec<'a, u8> { /// assert!(zerovec.is_owned()); /// assert_eq!(zerovec.get(0), Some(211)); /// ``` + #[cfg(feature = "alloc")] pub fn try_into_parsed(self) -> Result, UleError> { match self.into_cow() { Cow::Borrowed(bytes) => { @@ -692,6 +716,7 @@ where /// assert_eq!(bytes, zerovec.as_bytes()); /// ``` #[inline] + #[cfg(feature = "alloc")] pub fn alloc_from_slice(other: &[T]) -> Self { Self::new_owned(other.iter().copied().map(T::to_unaligned).collect()) } @@ -709,6 +734,7 @@ where /// assert_eq!(nums, vec.as_slice()); /// ``` #[inline] + #[cfg(feature = "alloc")] pub fn to_vec(&self) -> Vec { self.iter().collect() } @@ -762,6 +788,7 @@ where /// assert_eq!(bytes, zerovec.as_bytes()); /// ``` #[inline] + #[cfg(feature = "alloc")] pub fn from_slice_or_alloc(slice: &'a [T]) -> Self { Self::try_from_slice(slice).unwrap_or_else(|| Self::alloc_from_slice(slice)) } @@ -792,6 +819,7 @@ where /// assert!(zerovec.is_owned()); /// ``` #[inline] + #[cfg(feature = "alloc")] pub fn for_each_mut(&mut self, mut f: impl FnMut(&mut T)) { self.to_mut_slice().iter_mut().for_each(|item| { let mut aligned = T::from_unaligned(*item); @@ -821,6 +849,7 @@ where /// # Ok::<(), ()>(()) /// ``` #[inline] + #[cfg(feature = "alloc")] pub fn try_for_each_mut( &mut self, mut f: impl FnMut(&mut T) -> Result<(), E>, @@ -848,13 +877,12 @@ where /// let owned = zerovec.into_owned(); /// assert!(owned.is_owned()); /// ``` + #[cfg(feature = "alloc")] pub fn into_owned(self) -> ZeroVec<'static, T> { + use alloc::borrow::Cow; match self.into_cow() { Cow::Owned(vec) => ZeroVec::new_owned(vec), - Cow::Borrowed(b) => { - let vec: Vec = b.into(); - ZeroVec::new_owned(vec) - } + Cow::Borrowed(b) => ZeroVec::new_owned(b.into()), } } @@ -876,10 +904,12 @@ where /// zerovec.with_mut(|v| v.push(12_u16.to_unaligned())); /// assert!(zerovec.is_owned()); /// ``` - pub fn with_mut(&mut self, f: impl FnOnce(&mut Vec) -> R) -> R { + #[cfg(feature = "alloc")] + pub fn with_mut(&mut self, f: impl FnOnce(&mut alloc::vec::Vec) -> R) -> R { + use alloc::borrow::Cow; // We're in danger if f() panics whilst we've moved a vector out of self; // replace it with an empty dummy vector for now - let this = mem::take(self); + let this = core::mem::take(self); let mut vec = match this.into_cow() { Cow::Owned(v) => v, Cow::Borrowed(s) => s.into(), @@ -907,6 +937,7 @@ where /// zerovec.to_mut_slice()[1] = 5u16.to_unaligned(); /// assert!(zerovec.is_owned()); /// ``` + #[cfg(feature = "alloc")] pub fn to_mut_slice(&mut self) -> &mut [T::ULE] { if !self.is_owned() { // `buf` is either a valid vector or slice of `T::ULE`s, either @@ -945,6 +976,7 @@ where /// assert_eq!(first, 0x0119); /// assert!(zerovec.is_owned()); /// ``` + #[cfg(feature = "alloc")] pub fn take_first(&mut self) -> Option { match core::mem::take(self).into_cow() { Cow::Owned(mut vec) => { @@ -989,6 +1021,7 @@ where /// assert_eq!(last, 0x01A5); /// assert!(zerovec.is_owned()); /// ``` + #[cfg(feature = "alloc")] pub fn take_last(&mut self) -> Option { match core::mem::take(self).into_cow() { Cow::Owned(mut vec) => { @@ -1009,8 +1042,9 @@ where /// Converts the type into a `Cow<'a, [T::ULE]>`, which is /// the logical equivalent of this type's internal representation #[inline] + #[cfg(feature = "alloc")] pub fn into_cow(self) -> Cow<'a, [T::ULE]> { - let this = mem::ManuallyDrop::new(self); + let this = core::mem::ManuallyDrop::new(self); if this.is_owned() { let vec = unsafe { // safe to call: we know it's owned, @@ -1027,6 +1061,7 @@ where } } +#[cfg(feature = "alloc")] impl FromIterator for ZeroVec<'_, T> { /// Creates an owned [`ZeroVec`] from an iterator of values. fn from_iter(iter: I) -> Self diff --git a/utils/zerovec/src/zerovec/slice.rs b/utils/zerovec/src/zerovec/slice.rs index c5be08f9489..33188f7b390 100644 --- a/utils/zerovec/src/zerovec/slice.rs +++ b/utils/zerovec/src/zerovec/slice.rs @@ -3,7 +3,6 @@ // (online at: https://github.com/unicode-org/icu4x/blob/main/LICENSE ). use super::*; -use alloc::boxed::Box; use core::cmp::Ordering; use core::ops::Range; @@ -88,10 +87,11 @@ where /// Construct a `Box>` from a boxed slice of ULEs #[inline] - pub fn from_boxed_slice(slice: Box<[T::ULE]>) -> Box { + #[cfg(feature = "alloc")] + pub fn from_boxed_slice(slice: alloc::boxed::Box<[T::ULE]>) -> alloc::boxed::Box { // This is safe because ZeroSlice is transparent over [T::ULE] // so Box> can be safely cast from Box<[T::ULE]> - unsafe { Box::from_raw(Box::into_raw(slice) as *mut Self) } + unsafe { alloc::boxed::Box::from_raw(alloc::boxed::Box::into_raw(slice) as *mut Self) } } /// Returns this slice as its underlying `&[u8]` byte buffer representation. @@ -567,7 +567,8 @@ impl Ord for ZeroSlice { } } -impl AsRef> for Vec { +#[cfg(feature = "alloc")] +impl AsRef> for alloc::vec::Vec { fn as_ref(&self) -> &ZeroSlice { ZeroSlice::::from_ule_slice(self) }