Skip to content

Commit

Permalink
More no-alloc (#6166)
Browse files Browse the repository at this point in the history
`icu_time`, `icu_decimal`, `icu_list`

#6076

---------

Co-authored-by: Manish Goregaokar <[email protected]>
  • Loading branch information
robertbastian and Manishearth authored Feb 25, 2025
1 parent dabb344 commit 8132034
Show file tree
Hide file tree
Showing 46 changed files with 241 additions and 149 deletions.
3 changes: 3 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion components/collator/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ icu_properties = { workspace = true }
icu_provider = { workspace = true }
utf8_iter = { workspace = true }
utf16_iter = { workspace = true }
smallvec = { workspace = true, features = ["union", "const_generics", "const_new"] }
smallvec = { workspace = true, features = ["union", "const_generics", "const_new"] } # alloc
zerovec = { workspace = true }

databake = { workspace = true, optional = true, features = ["derive"] }
Expand Down
4 changes: 2 additions & 2 deletions components/datetime/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ icu_locale_core = { workspace = true }
icu_pattern = { workspace = true, features = ["zerovec", "alloc"] }
icu_plurals = { workspace = true }
icu_provider = { workspace = true, features = ["macros"] }
icu_time = { workspace = true }
icu_time = { workspace = true, features = ["alloc"] }
smallvec = { workspace = true }
tinystr = { workspace = true, features = ["alloc", "zerovec"] }
potential_utf = { workspace = true, features = ["alloc", "zerovec"] }
Expand All @@ -50,7 +50,7 @@ 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", features = ["alloc"] }
icu_time = { path = "../time", features = ["ixdtf"] }
icu_time = { path = "../time", features = ["ixdtf", "alloc"] }
litemap = { path = "../../utils/litemap" }

serde = { workspace = true, features = ["derive"] }
Expand Down
7 changes: 4 additions & 3 deletions components/decimal/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,12 @@ all-features = true
[dependencies]
displaydoc = { workspace = true }
fixed_decimal = { workspace = true }
icu_provider = { workspace = true, features = ["alloc"] }
icu_provider = { workspace = true }
icu_locale_core = { path = "../../components/locale_core" }
writeable = { workspace = true }
zerovec = { workspace = true }
databake = { workspace = true, features = ["derive"], optional = true}
serde = { workspace = true, features = ["derive", "alloc"], optional = true }
serde = { workspace = true, features = ["derive"], optional = true }

icu_decimal_data = { workspace = true, optional = true }
tinystr = { workspace = true }
Expand All @@ -47,9 +47,10 @@ criterion = { workspace = true }
[features]
default = ["compiled_data"]
serde = ["dep:serde", "icu_provider/serde", "zerovec/serde", "tinystr/serde"]
datagen = ["serde", "dep:databake", "zerovec/databake", "tinystr/databake", "icu_provider/export"]
datagen = ["serde", "dep:databake", "zerovec/databake", "tinystr/databake", "icu_provider/export", "alloc"]
compiled_data = ["dep:icu_decimal_data"]
ryu = ["fixed_decimal/ryu"]
alloc = ["serde?/alloc", "zerovec/alloc"]

[lints.rust]
unexpected_cfgs = { level = "warn", check-cfg = ['cfg(icu4x_run_size_tests)'] }
Expand Down
7 changes: 4 additions & 3 deletions components/decimal/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,7 @@
)]
#![warn(missing_docs)]

#[cfg(feature = "alloc")]
extern crate alloc;

mod format;
Expand All @@ -103,13 +104,11 @@ pub(crate) mod size_test_macro;

pub use format::FormattedDecimal;

use alloc::string::String;
use fixed_decimal::Decimal;
use icu_locale_core::locale;
use icu_locale_core::preferences::define_preferences;
use icu_provider::prelude::*;
use size_test_macro::size_test;
use writeable::Writeable;

size_test!(DecimalFormatter, decimal_formatter_size, 96);

Expand Down Expand Up @@ -302,7 +301,9 @@ impl DecimalFormatter {
}

/// Formats a [`Decimal`], returning a [`String`].
pub fn format_to_string(&self, value: &Decimal) -> String {
#[cfg(feature = "alloc")]
pub fn format_to_string(&self, value: &Decimal) -> alloc::string::String {
use writeable::Writeable;
self.format(value).write_to_string().into_owned()
}
}
Expand Down
31 changes: 16 additions & 15 deletions components/decimal/src/provider.rs
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,6 @@
#![allow(clippy::exhaustive_structs)]
#![allow(clippy::exhaustive_enums)]

use alloc::borrow::Cow;
use icu_provider::prelude::*;
use zerovec::VarZeroCow;

Expand Down Expand Up @@ -174,6 +173,7 @@ pub struct GroupingSizes {
#[zerovec::make_varule(DecimalSymbolsStrs)]
#[zerovec::derive(Debug)]
#[zerovec::skip_derive(Ord)]
#[cfg_attr(not(feature = "alloc"), zerovec::skip_derive(ZeroMapKV, ToOwned))]
#[cfg_attr(feature = "serde", zerovec::derive(Deserialize))]
#[cfg_attr(feature = "datagen", zerovec::derive(Serialize))]
// Each affix/separator is at most three characters, which tends to be around 3-12 bytes each
Expand All @@ -183,31 +183,32 @@ pub struct GroupingSizes {
pub struct DecimalSymbolStrsBuilder<'data> {
/// Prefix to apply when a negative sign is needed.
#[cfg_attr(feature = "serde", serde(borrow))]
pub minus_sign_prefix: Cow<'data, str>,
pub minus_sign_prefix: VarZeroCow<'data, str>,
/// Suffix to apply when a negative sign is needed.
#[cfg_attr(feature = "serde", serde(borrow))]
pub minus_sign_suffix: Cow<'data, str>,
pub minus_sign_suffix: VarZeroCow<'data, str>,

/// Prefix to apply when a positive sign is needed.
#[cfg_attr(feature = "serde", serde(borrow))]
pub plus_sign_prefix: Cow<'data, str>,
pub plus_sign_prefix: VarZeroCow<'data, str>,
/// Suffix to apply when a positive sign is needed.
#[cfg_attr(feature = "serde", serde(borrow))]
pub plus_sign_suffix: Cow<'data, str>,
pub plus_sign_suffix: VarZeroCow<'data, str>,

/// Character used to separate the integer and fraction parts of the number.
#[cfg_attr(feature = "serde", serde(borrow))]
pub decimal_separator: Cow<'data, str>,
pub decimal_separator: VarZeroCow<'data, str>,

/// Character used to separate groups in the integer part of the number.
#[cfg_attr(feature = "serde", serde(borrow))]
pub grouping_separator: Cow<'data, str>,
pub grouping_separator: VarZeroCow<'data, str>,

/// The numbering system to use.
#[cfg_attr(feature = "serde", serde(borrow))]
pub numsys: Cow<'data, str>,
pub numsys: VarZeroCow<'data, str>,
}

#[cfg(feature = "alloc")]
impl DecimalSymbolStrsBuilder<'_> {
/// Build a [`DecimalSymbolsStrs`]
pub fn build(&self) -> VarZeroCow<'static, DecimalSymbolsStrs> {
Expand Down Expand Up @@ -277,13 +278,13 @@ impl DecimalSymbols<'static> {
/// Create a new en-US format for use in testing
pub(crate) fn new_en_for_testing() -> Self {
let strings = DecimalSymbolStrsBuilder {
minus_sign_prefix: Cow::Borrowed("-"),
minus_sign_suffix: Cow::Borrowed(""),
plus_sign_prefix: Cow::Borrowed("+"),
plus_sign_suffix: Cow::Borrowed(""),
decimal_separator: ".".into(),
grouping_separator: ",".into(),
numsys: Cow::Borrowed("latn"),
minus_sign_prefix: VarZeroCow::new_borrowed("-"),
minus_sign_suffix: VarZeroCow::new_borrowed(""),
plus_sign_prefix: VarZeroCow::new_borrowed("+"),
plus_sign_suffix: VarZeroCow::new_borrowed(""),
decimal_separator: VarZeroCow::new_borrowed("."),
grouping_separator: VarZeroCow::new_borrowed(","),
numsys: VarZeroCow::new_borrowed("latn"),
};
Self {
strings: VarZeroCow::from_encodeable(&strings),
Expand Down
6 changes: 3 additions & 3 deletions components/icu/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -25,14 +25,14 @@ icu_casemap = { workspace = true }
icu_collator = { workspace = true }
icu_collections = { workspace = true }
icu_datetime = { workspace = true }
icu_decimal = { workspace = true }
icu_list = { workspace = true }
icu_decimal = { workspace = true, features = ["alloc"] }
icu_list = { workspace = true, features = ["alloc"] }
icu_locale = { workspace = true }
icu_normalizer = { workspace = true }
icu_plurals = { workspace = true }
icu_properties = { workspace = true, features = ["alloc"] }
icu_segmenter = { workspace = true }
icu_time = { workspace = true }
icu_time = { workspace = true, features = ["alloc"] }
icu_experimental = { workspace = true, optional = true }
icu_pattern = { workspace = true, optional = true }

Expand Down
12 changes: 7 additions & 5 deletions components/list/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,13 @@ all-features = true

[dependencies]
displaydoc = { workspace = true }
icu_provider = { workspace = true, features = ["alloc"] }
icu_provider = { workspace = true }
regex-automata = { workspace = true, features = ["dfa-search"] }
writeable = { workspace = true }
zerovec = { workspace = true }

databake = { workspace = true, features = ["derive"], optional = true}
serde = { workspace = true, features = ["derive", "alloc"], optional = true }
serde = { workspace = true, features = ["derive"], optional = true }

icu_list_data = { workspace = true, optional = true }

Expand All @@ -39,10 +40,11 @@ serde_json = { workspace = true }

[features]
default = ["compiled_data"]
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"]
serde = ["dep:serde", "icu_provider/serde", "icu_provider/alloc", "zerovec/serde"]
serde_human = ["serde", "regex-automata/dfa-build", "regex-automata/syntax", "alloc"]
datagen = ["serde", "dep:databake", "regex-automata/dfa-build", "regex-automata/syntax", "zerovec/databake", "alloc", "serde_human"]
compiled_data = ["dep:icu_list_data"]
alloc = ["zerovec/alloc", "icu_provider/alloc", "serde?/alloc"]

[[example]]
name = "and_list"
2 changes: 1 addition & 1 deletion components/list/src/lazy_automaton.rs
Original file line number Diff line number Diff line change
Expand Up @@ -56,8 +56,8 @@ impl<T: AsRef<[u8]>> LazyAutomaton for DFA<T> {
#[test]
fn test() {
use crate::provider::SerdeDFA;
use alloc::borrow::Cow;
use regex_automata::Input;
use std::borrow::Cow;

let matcher = SerdeDFA::new(Cow::Borrowed("^11(000)*$")).unwrap();

Expand Down
1 change: 1 addition & 0 deletions components/list/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,7 @@
)]
#![warn(missing_docs)]

#[cfg(feature = "alloc")]
extern crate alloc;

mod lazy_automaton;
Expand Down
1 change: 1 addition & 0 deletions components/list/src/list_formatter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,7 @@ impl ListFormatter {

/// Returns a [`String`] composed of the input [`Writeable`]s and the language-dependent
/// formatting.
#[cfg(feature = "alloc")]
pub fn format_to_string<W: Writeable, I: Iterator<Item = W> + Clone>(
&self,
values: I,
Expand Down
38 changes: 23 additions & 15 deletions components/list/src/patterns.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,27 +5,31 @@
use crate::lazy_automaton::LazyAutomaton;
use crate::provider::*;
#[cfg(feature = "datagen")]
use alloc::borrow::Cow;
#[cfg(feature = "datagen")]
use alloc::string::ToString;
#[cfg(feature = "datagen")]
use icu_provider::DataError;
use writeable::{LengthHint, Writeable};
#[cfg(feature = "datagen")]
use zerovec::VarZeroCow;

impl ListFormatterPatterns<'_> {
/// Creates a new [`ListFormatterPatterns`] from the given patterns. Fails if any pattern is invalid.
#[cfg(feature = "datagen")]
pub fn try_new(start: &str, middle: &str, end: &str, pair: &str) -> Result<Self, DataError> {
use zerovec::VarZeroCow;

let err = DataError::custom("Invalid list pattern");
Ok(Self {
start: ListJoinerPattern::try_from_str(start, true, false)?,
middle: middle
.strip_prefix("{0}")
.ok_or(err)?
.strip_suffix("{1}")
.ok_or(err)?
.to_string()
.into(),
middle: VarZeroCow::new_owned(
middle
.strip_prefix("{0}")
.ok_or(err)?
.strip_suffix("{1}")
.ok_or(err)?
.to_string()
.into_boxed_str(),
),
end: ListJoinerPattern::try_from_str(end, false, true)?.into(),
pair: if end != pair {
Some(ListJoinerPattern::try_from_str(pair, true, true)?.into())
Expand Down Expand Up @@ -99,12 +103,15 @@ impl<'data> ListJoinerPattern<'data> {
}
#[allow(clippy::indexing_slicing)] // find
Ok(ListJoinerPattern {
string: Cow::Owned(alloc::format!(
"{}{}{}",
&pattern[0..index_0],
&pattern[index_0 + 3..index_1],
&pattern[index_1 + 3..]
)),
string: VarZeroCow::new_owned(
alloc::format!(
"{}{}{}",
&pattern[0..index_0],
&pattern[index_0 + 3..index_1],
&pattern[index_1 + 3..]
)
.into_boxed_str(),
),
index_0: index_0 as u8,
index_1: (index_1 - 3) as u8,
})
Expand Down Expand Up @@ -142,6 +149,7 @@ impl<'data> From<ListJoinerPattern<'data>> for ConditionalListJoinerPattern<'dat
#[cfg(all(test, feature = "datagen"))]
pub mod test {
use super::*;
use std::borrow::Cow;

pub fn test_patterns_general() -> ListFormatterPatterns<'static> {
ListFormatterPatterns::try_new("@{0}:{1}", "{0},{1}", "{0}.{1}!", "${0};{1}+").unwrap()
Expand Down
Loading

0 comments on commit 8132034

Please sign in to comment.