icu_provider_fs/
fs_data_provider.rs
use crate::datapath::get_data_marker_id;
use crate::manifest::Manifest;
use icu_provider::prelude::*;
use icu_provider::DynamicDryDataProvider;
use std::fmt::Debug;
use std::fmt::Write;
use std::fs;
use std::path::PathBuf;
#[derive(Debug, PartialEq, Clone)]
pub struct FsDataProvider {
root: PathBuf,
manifest: Manifest,
}
impl FsDataProvider {
pub fn try_new(root: PathBuf) -> Result<Self, DataError> {
Ok(Self {
manifest: Manifest::parse(&root)?,
root,
})
}
fn dry_load_internal(
&self,
marker: DataMarkerInfo,
req: DataRequest,
) -> Result<(DataResponseMetadata, PathBuf), DataError> {
if marker.is_singleton && !req.id.locale.is_default() {
return Err(DataErrorKind::InvalidRequest.with_req(marker, req));
}
let Some((component, marker_name)) = get_data_marker_id(marker.id) else {
return Err(DataErrorKind::MarkerNotFound.with_req(marker, req));
};
let mut path = self.root.join(component).join(marker_name);
if !path.exists() {
return Err(DataErrorKind::MarkerNotFound.with_req(marker, req));
}
let checksum = if marker.is_singleton {
std::fs::read_to_string(format!("{}_checksum", path.display()))
} else {
std::fs::read_to_string(path.join(".checksum"))
}
.ok()
.and_then(|s| s.parse().ok());
if !marker.is_singleton {
if !req.id.marker_attributes.is_empty() {
if req.metadata.attributes_prefix_match {
path.push(
std::fs::read_dir(&path)?
.filter_map(|e| e.ok()?.file_name().into_string().ok())
.filter(|c| c.starts_with(req.id.marker_attributes.as_str()))
.min()
.ok_or(DataErrorKind::IdentifierNotFound.with_req(marker, req))?,
);
} else {
path.push(req.id.marker_attributes.as_str());
}
}
let mut string_path = path.into_os_string();
write!(&mut string_path, "/{}", req.id.locale).expect("infallible");
path = PathBuf::from(string_path);
}
path.set_extension(self.manifest.file_extension);
if !path.exists() {
return Err(DataErrorKind::IdentifierNotFound.with_req(marker, req));
}
let mut metadata = DataResponseMetadata::default();
metadata.buffer_format = Some(self.manifest.buffer_format);
metadata.checksum = checksum;
Ok((metadata, path))
}
}
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)
}
}