Revision control

Copy as Markdown

Other Tools

// This file is part of ICU4X. For terms of use, please see the file
// called LICENSE at the top level of the ICU4X source tree
use super::ForkByErrorPredicate;
use alloc::vec::Vec;
#[cfg(feature = "datagen")]
use icu_provider::datagen;
use icu_provider::prelude::*;
/// A provider that returns data from one of two child providers based on a predicate function.
///
/// This is an abstract forking provider that must be provided with a type implementing the
/// [`ForkByErrorPredicate`] trait.
///
/// [`ForkByErrorProvider`] does not support forking between [`DataProvider`]s. However, it
/// supports forking between [`AnyProvider`], [`BufferProvider`], and [`DynamicDataProvider`].
#[derive(Debug, PartialEq, Eq)]
pub struct ForkByErrorProvider<P0, P1, F>(P0, P1, F);
impl<P0, P1, F> ForkByErrorProvider<P0, P1, F> {
/// Create a new provider that forks between the two children.
///
/// The `predicate` argument should be an instance of a struct implementing
/// [`ForkByErrorPredicate`].
pub fn new_with_predicate(p0: P0, p1: P1, predicate: F) -> Self {
Self(p0, p1, predicate)
}
/// Returns references to the inner providers.
pub fn inner(&self) -> (&P0, &P1) {
(&self.0, &self.1)
}
/// Returns mutable references to the inner providers.
pub fn inner_mut(&mut self) -> (&mut P0, &mut P1) {
(&mut self.0, &mut self.1)
}
/// Returns ownership of the inner providers to the caller.
pub fn into_inner(self) -> (P0, P1) {
(self.0, self.1)
}
}
impl<P0, P1, F> BufferProvider for ForkByErrorProvider<P0, P1, F>
where
P0: BufferProvider,
P1: BufferProvider,
F: ForkByErrorPredicate,
{
fn load_buffer(
&self,
key: DataKey,
req: DataRequest,
) -> Result<DataResponse<BufferMarker>, DataError> {
let result = self.0.load_buffer(key, req);
match result {
Ok(ok) => return Ok(ok),
Err(err) if !self.2.test(key, Some(req), err) => return Err(err),
_ => (),
};
self.1.load_buffer(key, req)
}
}
impl<P0, P1, F> AnyProvider for ForkByErrorProvider<P0, P1, F>
where
P0: AnyProvider,
P1: AnyProvider,
F: ForkByErrorPredicate,
{
fn load_any(&self, key: DataKey, req: DataRequest) -> Result<AnyResponse, DataError> {
let result = self.0.load_any(key, req);
match result {
Ok(ok) => return Ok(ok),
Err(err) if !self.2.test(key, Some(req), err) => return Err(err),
_ => (),
};
self.1.load_any(key, req)
}
}
impl<M, P0, P1, F> DynamicDataProvider<M> for ForkByErrorProvider<P0, P1, F>
where
M: DataMarker,
P0: DynamicDataProvider<M>,
P1: DynamicDataProvider<M>,
F: ForkByErrorPredicate,
{
fn load_data(&self, key: DataKey, req: DataRequest) -> Result<DataResponse<M>, DataError> {
let result = self.0.load_data(key, req);
match result {
Ok(ok) => return Ok(ok),
Err(err) if !self.2.test(key, Some(req), err) => return Err(err),
_ => (),
};
self.1.load_data(key, req)
}
}
#[cfg(feature = "datagen")]
impl<M, P0, P1, F> datagen::IterableDynamicDataProvider<M> for ForkByErrorProvider<P0, P1, F>
where
M: DataMarker,
P0: datagen::IterableDynamicDataProvider<M>,
P1: datagen::IterableDynamicDataProvider<M>,
F: ForkByErrorPredicate,
{
fn supported_locales_for_key(&self, key: DataKey) -> Result<Vec<DataLocale>, DataError> {
let result = self.0.supported_locales_for_key(key);
match result {
Ok(ok) => return Ok(ok),
Err(err) if !self.2.test(key, None, err) => return Err(err),
_ => (),
};
self.1.supported_locales_for_key(key)
}
}
/// A provider that returns data from the first child provider passing a predicate function.
///
/// This is an abstract forking provider that must be provided with a type implementing the
/// [`ForkByErrorPredicate`] trait.
///
/// [`MultiForkByErrorProvider`] does not support forking between [`DataProvider`]s. However, it
/// supports forking between [`AnyProvider`], [`BufferProvider`], and [`DynamicDataProvider`].
#[derive(Debug)]
pub struct MultiForkByErrorProvider<P, F> {
providers: Vec<P>,
predicate: F,
}
impl<P, F> MultiForkByErrorProvider<P, F> {
/// Create a new provider that forks between the vector of children.
///
/// The `predicate` argument should be an instance of a struct implementing
/// [`ForkByErrorPredicate`].
pub fn new_with_predicate(providers: Vec<P>, predicate: F) -> Self {
Self {
providers,
predicate,
}
}
/// Returns a slice of the inner providers.
pub fn inner(&self) -> &[P] {
&self.providers
}
/// Exposes a mutable vector of providers to a closure so it can be mutated.
pub fn with_inner_mut(&mut self, f: impl FnOnce(&mut Vec<P>)) {
f(&mut self.providers)
}
/// Returns ownership of the inner providers to the caller.
pub fn into_inner(self) -> Vec<P> {
self.providers
}
/// Adds an additional child provider.
pub fn push(&mut self, provider: P) {
self.providers.push(provider);
}
}
impl<P, F> BufferProvider for MultiForkByErrorProvider<P, F>
where
P: BufferProvider,
F: ForkByErrorPredicate,
{
fn load_buffer(
&self,
key: DataKey,
req: DataRequest,
) -> Result<DataResponse<BufferMarker>, DataError> {
let mut last_error = F::UNIT_ERROR.with_key(key);
for provider in self.providers.iter() {
let result = provider.load_buffer(key, req);
match result {
Ok(ok) => return Ok(ok),
Err(err) if !self.predicate.test(key, 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,
F: ForkByErrorPredicate,
{
fn load_any(&self, key: DataKey, req: DataRequest) -> Result<AnyResponse, DataError> {
let mut last_error = F::UNIT_ERROR.with_key(key);
for provider in self.providers.iter() {
let result = provider.load_any(key, req);
match result {
Ok(ok) => return Ok(ok),
Err(err) if !self.predicate.test(key, Some(req), err) => return Err(err),
Err(err) => last_error = err,
};
}
Err(last_error)
}
}
impl<M, P, F> DynamicDataProvider<M> for MultiForkByErrorProvider<P, F>
where
M: DataMarker,
P: DynamicDataProvider<M>,
F: ForkByErrorPredicate,
{
fn load_data(&self, key: DataKey, req: DataRequest) -> Result<DataResponse<M>, DataError> {
let mut last_error = F::UNIT_ERROR.with_key(key);
for provider in self.providers.iter() {
let result = provider.load_data(key, req);
match result {
Ok(ok) => return Ok(ok),
Err(err) if !self.predicate.test(key, Some(req), err) => return Err(err),
Err(err) => last_error = err,
};
}
Err(last_error)
}
}
#[cfg(feature = "datagen")]
impl<M, P, F> datagen::IterableDynamicDataProvider<M> for MultiForkByErrorProvider<P, F>
where
M: DataMarker,
P: datagen::IterableDynamicDataProvider<M>,
F: ForkByErrorPredicate,
{
fn supported_locales_for_key(&self, key: DataKey) -> Result<Vec<DataLocale>, DataError> {
let mut last_error = F::UNIT_ERROR.with_key(key);
for provider in self.providers.iter() {
let result = provider.supported_locales_for_key(key);
match result {
Ok(ok) => return Ok(ok),
Err(err) if !self.predicate.test(key, None, err) => return Err(err),
Err(err) => last_error = err,
};
}
Err(last_error)
}
}
#[cfg(feature = "datagen")]
impl<P, MFrom, MTo, F> datagen::DataConverter<MFrom, MTo> for MultiForkByErrorProvider<P, F>
where
P: datagen::DataConverter<MFrom, MTo>,
F: ForkByErrorPredicate,
MFrom: DataMarker,
MTo: DataMarker,
{
fn convert(
&self,
key: DataKey,
mut from: DataPayload<MFrom>,
) -> Result<DataPayload<MTo>, (DataPayload<MFrom>, DataError)> {
let mut last_error = F::UNIT_ERROR.with_key(key);
for provider in self.providers.iter() {
let result = provider.convert(key, from);
match result {
Ok(ok) => return Ok(ok),
Err(e) => {
let (returned, err) = e;
if !self.predicate.test(key, None, err) {
return Err((returned, err));
}
from = returned;
last_error = err;
}
};
}
Err((from, last_error))
}
}
#[cfg(feature = "datagen")]
impl<P0, P1, F, MFrom, MTo> datagen::DataConverter<MFrom, MTo> for ForkByErrorProvider<P0, P1, F>
where
P0: datagen::DataConverter<MFrom, MTo>,
P1: datagen::DataConverter<MFrom, MTo>,
F: ForkByErrorPredicate,
MFrom: DataMarker,
MTo: DataMarker,
{
fn convert(
&self,
key: DataKey,
mut from: DataPayload<MFrom>,
) -> Result<DataPayload<MTo>, (DataPayload<MFrom>, DataError)> {
let result = self.0.convert(key, from);
match result {
Ok(ok) => return Ok(ok),
Err(e) => {
let (returned, err) = e;
if !self.2.test(key, None, err) {
return Err((returned, err));
}
from = returned;
}
};
self.1.convert(key, from)
}
}