Skip to content

Commit

Permalink
DryDataProvider (unicode-org#5141)
Browse files Browse the repository at this point in the history
  • Loading branch information
robertbastian authored Jul 4, 2024
1 parent 4fc37e9 commit b3006b2
Show file tree
Hide file tree
Showing 11 changed files with 374 additions and 50 deletions.
30 changes: 30 additions & 0 deletions provider/adapters/src/either.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,23 @@ impl<M: DynamicDataMarker, P0: DynamicDataProvider<M>, P1: DynamicDataProvider<M
}
}

impl<M: DynamicDataMarker, P0: DynamicDryDataProvider<M>, P1: DynamicDryDataProvider<M>>
DynamicDryDataProvider<M> for EitherProvider<P0, P1>
{
#[inline]
fn dry_load_data(
&self,
marker: DataMarkerInfo,
req: DataRequest,
) -> Result<DataResponseMetadata, DataError> {
use EitherProvider::*;
match self {
A(p) => p.dry_load_data(marker, req),
B(p) => p.dry_load_data(marker, req),
}
}
}

impl<M: DataMarker, P0: DataProvider<M>, P1: DataProvider<M>> DataProvider<M>
for EitherProvider<P0, P1>
{
Expand All @@ -60,6 +77,19 @@ impl<M: DataMarker, P0: DataProvider<M>, P1: DataProvider<M>> DataProvider<M>
}
}

impl<M: DataMarker, P0: DryDataProvider<M>, P1: DryDataProvider<M>> DryDataProvider<M>
for EitherProvider<P0, P1>
{
#[inline]
fn dry_load(&self, req: DataRequest) -> Result<DataResponseMetadata, DataError> {
use EitherProvider::*;
match self {
A(p) => p.dry_load(req),
B(p) => p.dry_load(req),
}
}
}

#[cfg(feature = "std")]
impl<
M: DynamicDataMarker,
Expand Down
97 changes: 87 additions & 10 deletions provider/adapters/src/fallback/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ use crate::helpers::result_is_err_missing_locale;
use icu_locale::provider::*;
use icu_locale::LocaleFallbacker;
use icu_provider::prelude::*;
use icu_provider::DryDataProvider;
use icu_provider::DynamicDryDataProvider;

/// A data provider wrapper that performs locale fallback. This enables arbitrary locales to be
/// handled at runtime.
Expand Down Expand Up @@ -243,14 +245,10 @@ impl<P> AnyProvider for LocaleFallbackProvider<P>
where
P: AnyProvider,
{
fn load_any(
&self,
marker: DataMarkerInfo,
base_req: DataRequest,
) -> Result<AnyResponse, DataError> {
fn load_any(&self, marker: DataMarkerInfo, req: DataRequest) -> Result<AnyResponse, DataError> {
self.run_fallback(
marker,
base_req,
req,
|req| self.inner.load_any(marker, req),
|res| &mut res.metadata,
)
Expand All @@ -265,28 +263,107 @@ where
fn load_data(
&self,
marker: DataMarkerInfo,
base_req: DataRequest,
req: DataRequest,
) -> Result<DataResponse<M>, DataError> {
self.run_fallback(
marker,
base_req,
req,
|req| self.inner.load_data(marker, req),
|res| &mut res.metadata,
)
}
}

impl<P, M> DynamicDryDataProvider<M> for LocaleFallbackProvider<P>
where
P: DynamicDryDataProvider<M>,
M: DynamicDataMarker,
{
fn dry_load_data(
&self,
marker: DataMarkerInfo,
req: DataRequest,
) -> Result<DataResponseMetadata, DataError> {
self.run_fallback(
marker,
req,
|req| self.inner.dry_load_data(marker, req),
|m| m,
)
}
}

impl<P, M> DataProvider<M> for LocaleFallbackProvider<P>
where
P: DataProvider<M>,
M: DataMarker,
{
fn load(&self, base_req: DataRequest) -> Result<DataResponse<M>, DataError> {
fn load(&self, req: DataRequest) -> Result<DataResponse<M>, DataError> {
self.run_fallback(
M::INFO,
base_req,
req,
|req| self.inner.load(req),
|res| &mut res.metadata,
)
}
}

impl<P, M> DryDataProvider<M> for LocaleFallbackProvider<P>
where
P: DryDataProvider<M>,
M: DataMarker,
{
fn dry_load(&self, req: DataRequest) -> Result<DataResponseMetadata, DataError> {
self.run_fallback(M::INFO, req, |req| self.inner.dry_load(req), |m| m)
}
}

#[test]
fn dry_test() {
use icu_provider::hello_world::*;

struct TestProvider;
impl DataProvider<HelloWorldV1Marker> for TestProvider {
fn load(&self, _: DataRequest) -> Result<DataResponse<HelloWorldV1Marker>, DataError> {
panic!("pretend this is super expensive")
}
}

impl DryDataProvider<HelloWorldV1Marker> for TestProvider {
fn dry_load(&self, req: DataRequest) -> Result<DataResponseMetadata, DataError> {
// We support all languages except English, and no regional variants. This is cheap to check.
if req.id.locale.region().is_some() || req.id.locale.language().as_str() == "en" {
Err(DataErrorKind::IdentifierNotFound.into_error())
} else {
Ok(Default::default())
}
}
}

let provider = LocaleFallbackProvider::new_with_fallbacker(
TestProvider,
LocaleFallbacker::new().static_to_owned(),
);

assert_eq!(
provider
.dry_load(DataRequest {
id: DataIdentifierBorrowed::for_locale(&"de-CH".parse().unwrap()),
..Default::default()
})
.unwrap()
.locale,
"de".parse::<DataLocale>().ok()
);

assert_eq!(
provider
.dry_load(DataRequest {
id: DataIdentifierBorrowed::for_locale(&"en-GB".parse().unwrap()),
..Default::default()
})
.unwrap()
.locale,
Some(DataLocale::default())
);
}
69 changes: 48 additions & 21 deletions provider/adapters/src/filter/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,20 @@ where
pub filter_name: &'static str,
}

impl<D, F> FilterDataProvider<D, F>
where
F: Fn(DataIdentifierBorrowed) -> bool,
{
fn check(&self, marker: DataMarkerInfo, req: DataRequest) -> Result<(), DataError> {
if !(self.predicate)(req.id) {
return Err(DataErrorKind::IdentifierNotFound
.with_str_context(self.filter_name)
.with_req(marker, req));
}
Ok(())
}
}

impl<D, F, M> DynamicDataProvider<M> for FilterDataProvider<D, F>
where
F: Fn(DataIdentifierBorrowed) -> bool,
Expand All @@ -60,13 +74,24 @@ where
marker: DataMarkerInfo,
req: DataRequest,
) -> Result<DataResponse<M>, DataError> {
if (self.predicate)(req.id) {
self.inner.load_data(marker, req)
} else {
Err(DataErrorKind::IdentifierNotFound
.with_str_context(self.filter_name)
.with_req(marker, req))
}
self.check(marker, req)?;
self.inner.load_data(marker, req)
}
}

impl<D, F, M> DynamicDryDataProvider<M> for FilterDataProvider<D, F>
where
F: Fn(DataIdentifierBorrowed) -> bool,
M: DynamicDataMarker,
D: DynamicDryDataProvider<M>,
{
fn dry_load_data(
&self,
marker: DataMarkerInfo,
req: DataRequest,
) -> Result<DataResponseMetadata, DataError> {
self.check(marker, req)?;
self.inner.dry_load_data(marker, req)
}
}

Expand All @@ -77,13 +102,20 @@ where
D: DataProvider<M>,
{
fn load(&self, req: DataRequest) -> Result<DataResponse<M>, DataError> {
if (self.predicate)(req.id) {
self.inner.load(req)
} else {
Err(DataErrorKind::IdentifierNotFound
.with_str_context(self.filter_name)
.with_req(M::INFO, req))
}
self.check(M::INFO, req)?;
self.inner.load(req)
}
}

impl<D, F, M> DryDataProvider<M> for FilterDataProvider<D, F>
where
F: Fn(DataIdentifierBorrowed) -> bool,
M: DataMarker,
D: DryDataProvider<M>,
{
fn dry_load(&self, req: DataRequest) -> Result<DataResponseMetadata, DataError> {
self.check(M::INFO, req)?;
self.inner.dry_load(req)
}
}

Expand All @@ -93,13 +125,8 @@ where
D: AnyProvider,
{
fn load_any(&self, marker: DataMarkerInfo, req: DataRequest) -> Result<AnyResponse, DataError> {
if (self.predicate)(req.id) {
self.inner.load_any(marker, req)
} else {
Err(DataErrorKind::IdentifierNotFound
.with_str_context(self.filter_name)
.with_req(marker, req))
}
self.check(marker, req)?;
self.inner.load_any(marker, req)
}
}

Expand Down
84 changes: 84 additions & 0 deletions provider/adapters/src/fork/by_error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,24 @@ where
}
}

impl<M, P0, P1, F> DryDataProvider<M> for ForkByErrorProvider<P0, P1, F>
where
M: DataMarker,
P0: DryDataProvider<M>,
P1: DryDataProvider<M>,
F: ForkByErrorPredicate,
{
fn dry_load(&self, req: DataRequest) -> Result<DataResponseMetadata, DataError> {
let result = self.0.dry_load(req);
match result {
Ok(ok) => return Ok(ok),
Err(err) if !self.2.test(M::INFO, Some(req), err) => return Err(err),
_ => (),
};
self.1.dry_load(req)
}
}

impl<P0, P1, F> AnyProvider for ForkByErrorProvider<P0, P1, F>
where
P0: AnyProvider,
Expand Down Expand Up @@ -98,6 +116,28 @@ where
}
}

impl<M, P0, P1, F> DynamicDryDataProvider<M> for ForkByErrorProvider<P0, P1, F>
where
M: DynamicDataMarker,
P0: DynamicDryDataProvider<M>,
P1: DynamicDryDataProvider<M>,
F: ForkByErrorPredicate,
{
fn dry_load_data(
&self,
marker: DataMarkerInfo,
req: DataRequest,
) -> Result<DataResponseMetadata, DataError> {
let result = self.0.dry_load_data(marker, req);
match result {
Ok(ok) => return Ok(ok),
Err(err) if !self.2.test(marker, Some(req), err) => return Err(err),
_ => (),
};
self.1.dry_load_data(marker, req)
}
}

#[cfg(feature = "std")]
impl<M, P0, P1, F> IterableDynamicDataProvider<M> for ForkByErrorProvider<P0, P1, F>
where
Expand Down Expand Up @@ -186,6 +226,26 @@ where
}
}

impl<M, P, F> DryDataProvider<M> for MultiForkByErrorProvider<P, F>
where
M: DataMarker,
P: DryDataProvider<M>,
F: ForkByErrorPredicate,
{
fn dry_load(&self, req: DataRequest) -> Result<DataResponseMetadata, DataError> {
let mut last_error = F::UNIT_ERROR.with_marker(M::INFO);
for provider in self.providers.iter() {
let result = provider.dry_load(req);
match result {
Ok(ok) => return Ok(ok),
Err(err) if !self.predicate.test(M::INFO, Some(req), err) => return Err(err),
Err(err) => last_error = err,
};
}
Err(last_error)
}
}

impl<P, F> AnyProvider for MultiForkByErrorProvider<P, F>
where
P: AnyProvider,
Expand Down Expand Up @@ -229,6 +289,30 @@ where
}
}

impl<M, P, F> DynamicDryDataProvider<M> for MultiForkByErrorProvider<P, F>
where
M: DynamicDataMarker,
P: DynamicDryDataProvider<M>,
F: ForkByErrorPredicate,
{
fn dry_load_data(
&self,
marker: DataMarkerInfo,
req: DataRequest,
) -> Result<DataResponseMetadata, DataError> {
let mut last_error = F::UNIT_ERROR.with_marker(marker);
for provider in self.providers.iter() {
let result = provider.dry_load_data(marker, req);
match result {
Ok(ok) => return Ok(ok),
Err(err) if !self.predicate.test(marker, Some(req), err) => return Err(err),
Err(err) => last_error = err,
};
}
Err(last_error)
}
}

#[cfg(feature = "std")]
impl<M, P, F> IterableDynamicDataProvider<M> for MultiForkByErrorProvider<P, F>
where
Expand Down
Loading

0 comments on commit b3006b2

Please sign in to comment.