Skip to content

Commit

Permalink
dry
Browse files Browse the repository at this point in the history
  • Loading branch information
robertbastian committed Jul 1, 2024
1 parent fb0570a commit 39034cd
Show file tree
Hide file tree
Showing 6 changed files with 86 additions and 49 deletions.
23 changes: 17 additions & 6 deletions provider/adapters/src/fallback/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ use crate::helpers::result_is_err_missing_locale;
use icu_locale::provider::*;
use icu_locale::LocaleFallbacker;
use icu_provider::prelude::*;
use icu_provider::DryDataProvider;

/// A data provider wrapper that performs locale fallback. This enables arbitrary locales to be
/// handled at runtime.
Expand Down Expand Up @@ -246,11 +247,11 @@ where
fn load_any(
&self,
marker: DataMarkerInfo,
base_req: DataRequest,
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,11 +266,11 @@ 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,
)
Expand All @@ -281,12 +282,22 @@ 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)
}
}
26 changes: 19 additions & 7 deletions provider/blob/src/blob_data_provider.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ use alloc::boxed::Box;
use icu_provider::buf::BufferFormat;
use icu_provider::prelude::*;
use icu_provider::Cart;
use icu_provider::DynamicDryDataProvider;
use yoke::*;

/// A data provider that reads from serialized blobs of data.
Expand Down Expand Up @@ -124,15 +125,26 @@ impl DynamicDataProvider<BufferMarker> for BlobDataProvider {
marker: DataMarkerInfo,
req: DataRequest,
) -> Result<DataResponse<BufferMarker>, DataError> {
let payload = self
.data
.try_map_project_cloned(|blob, _| blob.load(marker, req))
.map(DataPayload::from_yoked_buffer)?;
let mut metadata = DataResponseMetadata::default();
metadata.buffer_format = Some(BufferFormat::Postcard1);
Ok(DataResponse {
metadata,
payload: DataPayload::from_yoked_buffer(
self.data
.try_map_project_cloned(|blob, _| blob.load(marker, req))?,
),
})
Ok(DataResponse { metadata, payload })
}
}

impl DynamicDryDataProvider<BufferMarker> for BlobDataProvider {
fn dry_load_data(
&self,
marker: DataMarkerInfo,
req: DataRequest,
) -> Result<DataResponseMetadata, DataError> {
self.data.get().load(marker, req)?;
let mut metadata = DataResponseMetadata::default();
metadata.buffer_format = Some(BufferFormat::Postcard1);
Ok(metadata)
}
}

Expand Down
20 changes: 10 additions & 10 deletions provider/core/src/buf/serde.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,9 @@

use crate::buf::BufferFormat;
use crate::buf::BufferProvider;
use crate::data_provider::DynamicCanLoad;
use crate::data_provider::DynamicDryDataProvider;
use crate::prelude::*;
use crate::CanLoad;
use crate::DryDataProvider;
use serde::de::Deserialize;
use yoke::trait_hack::YokeTraitHack;
use yoke::Yokeable;
Expand Down Expand Up @@ -186,18 +186,18 @@ where
}
}

impl<P, M> DynamicCanLoad<M> for DeserializingBufferProvider<'_, P>
impl<P, M> DynamicDryDataProvider<M> for DeserializingBufferProvider<'_, P>
where
M: DynamicDataMarker,
P: DynamicCanLoad<BufferMarker> + ?Sized,
P: DynamicDryDataProvider<BufferMarker> + ?Sized,
// Actual bound:
// for<'de> <M::Yokeable as Yokeable<'de>>::Output: serde::de::Deserialize<'de>,
// Necessary workaround bound (see `yoke::trait_hack` docs):
for<'de> YokeTraitHack<<M::Yokeable as Yokeable<'de>>::Output>: Deserialize<'de>,
{
fn can_load_data(&self, marker: DataMarkerInfo, req: DataRequest) -> Result<bool, DataError> {
fn dry_load_data(&self, marker: DataMarkerInfo, req: DataRequest) -> Result<DataResponseMetadata, DataError> {
// Avoids deserialization, deserialization cannot produce `DataErrorKind::MissingLocale`
self.0.can_load_data(marker, req)
self.0.dry_load_data(marker, req)
}
}

Expand All @@ -223,18 +223,18 @@ where
}
}

impl<P, M> CanLoad<M> for DeserializingBufferProvider<'_, P>
impl<P, M> DryDataProvider<M> for DeserializingBufferProvider<'_, P>
where
M: DataMarker,
P: DynamicCanLoad<BufferMarker> + ?Sized,
P: DynamicDryDataProvider<BufferMarker> + ?Sized,
// Actual bound:
// for<'de> <M::Yokeable as Yokeable<'de>>::Output: Deserialize<'de>,
// Necessary workaround bound (see `yoke::trait_hack` docs):
for<'de> YokeTraitHack<<M::Yokeable as Yokeable<'de>>::Output>: Deserialize<'de>,
{
fn can_load(&self, req: DataRequest) -> Result<bool, DataError> {
fn dry_load(&self, req: DataRequest) -> Result<DataResponseMetadata, DataError> {
// Avoids deserialization, deserialization cannot produce `DataErrorKind::MissingLocale`
self.0.can_load_data(M::INFO, req)
self.0.dry_load_data(M::INFO, req)
}
}

Expand Down
34 changes: 14 additions & 20 deletions provider/core/src/data_provider.rs
Original file line number Diff line number Diff line change
Expand Up @@ -76,18 +76,15 @@ where

/// A data provider that can determine whehter it can load a particular data identifier,
/// potentially cheaper than performing the load.
pub trait CanLoad<M: DataMarker>: DataProvider<M> {
/// This method returns false iff [`load`] fails with a [`DataErrorKind::IdentifierNotFound`].
///
/// Other errors are returned as [`load`] would.
pub trait DryDataProvider<M: DataMarker>: DataProvider<M> {
/// This method goes through the motions of [`load`], but only returns the metadata.
///
/// It must be equivalent to calling `load(req).map(|r| r.metadata)`, but might
/// be implemented in a more efficient way.
///
/// [`load`]: DataProvider::load
fn can_load(&self, req: DataRequest) -> Result<bool, DataError> {
match self.load(req) {
Ok(_) => Ok(true),
Err(e) if e.kind == DataErrorKind::IdentifierNotFound => Ok(false),
Err(e) => Err(e),
}
fn dry_load(&self, req: DataRequest) -> Result<DataResponseMetadata, DataError> {
self.load(req).map(|r| r.metadata)
}
}

Expand All @@ -114,18 +111,15 @@ where

/// A dynanmic data provider that can determine whehter it can load a particular data identifier,
/// potentially cheaper than performing the load.
pub trait DynamicCanLoad<M: DynamicDataMarker>: DynamicDataProvider<M> {
/// This method returns false iff [`load_data`] fails with a [`DataErrorKind::IdentifierNotFound`].
///
/// Other errors are returned as [`load_data`] would.
pub trait DynamicDryDataProvider<M: DynamicDataMarker>: DynamicDataProvider<M> {
/// This method goes through the motions of [`load_data`], but only returns the metadata.
///
/// It must be equivalent to calling `load_data(req).map(|r| r.metadata)`, but might
/// be implemented in a more efficient way.
///
/// [`load_data`]: DynamicDataProvider::load_data
fn can_load_data(&self, marker: DataMarkerInfo, req: DataRequest) -> Result<bool, DataError> {
match self.load_data(marker, req) {
Ok(_) => Ok(true),
Err(e) if e.kind == DataErrorKind::IdentifierNotFound => Ok(false),
Err(e) => Err(e),
}
fn dry_load_data(&self, marker: DataMarkerInfo, req: DataRequest) -> Result<DataResponseMetadata, DataError> {
self.load_data(marker, req).map(|r| r.metadata)
}
}

Expand Down
2 changes: 1 addition & 1 deletion provider/core/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,7 @@ pub mod serde_borrow_de_utils;

mod data_provider;
pub use data_provider::{
BoundDataProvider, CanLoad, DataProvider, DataProviderWithMarker, DynamicCanLoad,
BoundDataProvider, DryDataProvider, DataProvider, DataProviderWithMarker, DynamicDryDataProvider,
DynamicDataProvider,
};
#[cfg(feature = "std")]
Expand Down
30 changes: 25 additions & 5 deletions provider/fs/src/fs_data_provider.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

use crate::manifest::Manifest;
use icu_provider::prelude::*;
use icu_provider::DynamicDryDataProvider;
use std::fmt::Debug;
use std::fmt::Write;
use std::fs;
Expand Down Expand Up @@ -60,14 +61,12 @@ impl FsDataProvider {
root,
})
}
}

impl DynamicDataProvider<BufferMarker> for FsDataProvider {
fn load_data(
fn dry_load_internal(
&self,
marker: DataMarkerInfo,
req: DataRequest,
) -> Result<DataResponse<BufferMarker>, DataError> {
) -> Result<(DataResponseMetadata, PathBuf), DataError> {
if marker.is_singleton && !req.id.locale.is_empty() {
return Err(DataErrorKind::InvalidRequest.with_req(marker, req));
}
Expand All @@ -84,12 +83,33 @@ impl DynamicDataProvider<BufferMarker> for FsDataProvider {
if !Path::new(&path).exists() {
return Err(DataErrorKind::IdentifierNotFound.with_req(marker, req));
}
let buffer = fs::read(&path).map_err(|e| DataError::from(e).with_path_context(&path))?;
let mut metadata = DataResponseMetadata::default();
metadata.buffer_format = Some(self.manifest.buffer_format);
Ok((metadata, path.into()))
}
}

impl DynamicDataProvider<BufferMarker> for FsDataProvider {
fn load_data(
&self,
marker: DataMarkerInfo,
req: DataRequest,
) -> Result<DataResponse<BufferMarker>, DataError> {
let (metadata, path) = self.dry_load_internal(marker, req)?;
let buffer = fs::read(&path).map_err(|e| DataError::from(e).with_path_context(&path))?;
Ok(DataResponse {
metadata,
payload: DataPayload::from_owned_buffer(buffer.into_boxed_slice()),
})
}
}

impl DynamicDryDataProvider<BufferMarker> for FsDataProvider {
fn dry_load_data(
&self,
marker: DataMarkerInfo,
req: DataRequest,
) -> Result<DataResponseMetadata, DataError> {
Ok(self.dry_load_internal(marker, req)?.0)
}
}

0 comments on commit 39034cd

Please sign in to comment.