blob: 7fd8289df31843e140f97c615c491d484bfff80a [file] [log] [blame]
// 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
// (online at: https://github.com/unicode-org/icu4x/blob/main/LICENSE ).
//! Data provider returning multilingual "Hello World" strings for testing.
#![allow(clippy::exhaustive_structs)] // data struct module
use crate::buf::BufferFormat;
#[cfg(feature = "datagen")]
use crate::datagen::IterableDataProvider;
use crate::helpers;
use crate::prelude::*;
use crate::yoke::{self, *};
use crate::zerofrom::{self, *};
use alloc::borrow::Cow;
use alloc::string::String;
use core::fmt::Debug;
use writeable::Writeable;
/// A struct containing "Hello World" in the requested language.
#[derive(Debug, PartialEq, Clone, Yokeable, ZeroFrom)]
#[cfg_attr(feature = "serde", derive(serde::Deserialize))]
#[cfg_attr(feature = "datagen", derive(serde::Serialize, databake::Bake))]
#[cfg_attr(feature = "datagen", databake(path = icu_provider::hello_world))]
pub struct HelloWorldV1<'data> {
/// The translation of "Hello World".
#[cfg_attr(feature = "serde", serde(borrow))]
pub message: Cow<'data, str>,
}
impl Default for HelloWorldV1<'_> {
fn default() -> Self {
HelloWorldV1 {
message: Cow::Borrowed("(und) Hello World"),
}
}
}
/// Marker type for [`HelloWorldV1`].
#[cfg_attr(feature = "datagen", derive(Default, databake::Bake))]
#[cfg_attr(feature = "datagen", databake(path = icu_provider::hello_world))]
pub struct HelloWorldV1Marker;
impl DataMarker for HelloWorldV1Marker {
type Yokeable = HelloWorldV1<'static>;
}
impl KeyedDataMarker for HelloWorldV1Marker {
const KEY: DataKey = crate::data_key!("core/helloworld@1");
}
/// A data provider returning Hello World strings in different languages.
///
/// Mostly useful for testing.
///
/// # Examples
///
/// ```
/// use icu_locid::locale;
/// use icu_provider::hello_world::*;
/// use icu_provider::prelude::*;
///
/// let german_hello_world: DataPayload<HelloWorldV1Marker> =
/// HelloWorldProvider
/// .load(DataRequest {
/// locale: &locale!("de").into(),
/// metadata: Default::default(),
/// })
/// .expect("Loading should succeed")
/// .take_payload()
/// .expect("Data should be present");
///
/// assert_eq!("Hallo Welt", german_hello_world.get().message);
/// ```
#[derive(Debug, PartialEq, Default)]
pub struct HelloWorldProvider;
impl HelloWorldProvider {
// Data from https://en.wiktionary.org/wiki/Hello_World#Translations
// Keep this sorted!
const DATA: &'static [(&'static str, &'static str)] = &[
("bn", "ওহে বিশ্ব"),
("cs", "Ahoj světe"),
("de", "Hallo Welt"),
("el", "Καλημέρα κόσμε"),
("en", "Hello World"),
("eo", "Saluton, Mondo"),
("fa", "سلام دنیا‎"),
("fi", "hei maailma"),
("is", "Halló, heimur"),
("ja", "こんにちは世界"),
("la", "Ave, munde"),
("pt", "Olá, mundo"),
("ro", "Salut, lume"),
("ru", "Привет, мир"),
("vi", "Xin chào thế giới"),
("zh", "你好世界"),
];
/// Converts this provider into one that serves JSON blobs of the same data.
pub fn into_json_provider(self) -> HelloWorldJsonProvider {
HelloWorldJsonProvider(self)
}
}
impl DataProvider<HelloWorldV1Marker> for HelloWorldProvider {
fn load(&self, req: DataRequest) -> Result<DataResponse<HelloWorldV1Marker>, DataError> {
#[allow(clippy::indexing_slicing)] // binary_search
let data = Self::DATA
.binary_search_by(|(k, _)| req.locale.strict_cmp(k.as_bytes()).reverse())
.map(|i| Self::DATA[i].1)
.map(|s| HelloWorldV1 {
message: Cow::Borrowed(s),
})
.map_err(|_| DataErrorKind::MissingLocale.with_req(HelloWorldV1Marker::KEY, req))?;
Ok(DataResponse {
metadata: Default::default(),
payload: Some(DataPayload::from_owned(data)),
})
}
}
impl DataPayload<HelloWorldV1Marker> {
/// Make a [`DataPayload`]`<`[`HelloWorldV1Marker`]`>` from a static string slice.
pub fn from_static_str(s: &'static str) -> DataPayload<HelloWorldV1Marker> {
DataPayload::from_owned(HelloWorldV1 {
message: Cow::Borrowed(s),
})
}
}
#[cfg(not(feature = "datagen"))]
impl_dynamic_data_provider!(HelloWorldProvider, [HelloWorldV1Marker,], AnyMarker);
#[cfg(feature = "datagen")]
make_exportable_provider!(HelloWorldProvider, [HelloWorldV1Marker,]);
/// A data provider returning Hello World strings in different languages as JSON blobs.
///
/// Mostly useful for testing.
///
/// # Examples
///
/// ```
/// use icu_locid::locale;
/// use icu_provider::hello_world::*;
/// use icu_provider::prelude::*;
///
/// let german_hello_world = HelloWorldProvider
/// .into_json_provider()
/// .load_buffer(HelloWorldV1Marker::KEY, DataRequest {
/// locale: &locale!("de").into(),
/// metadata: Default::default(),
/// })
/// .expect("Loading should succeed")
/// .take_payload()
/// .expect("Data should be present");
///
/// assert_eq!(b"{\"message\":\"Hallo Welt\"}", german_hello_world.get());
pub struct HelloWorldJsonProvider(HelloWorldProvider);
impl BufferProvider for HelloWorldJsonProvider {
fn load_buffer(
&self,
key: DataKey,
req: DataRequest,
) -> Result<DataResponse<BufferMarker>, DataError> {
key.match_key(HelloWorldV1Marker::KEY)?;
let result = self.0.load(req)?;
let (mut metadata, old_payload) =
DataResponse::<HelloWorldV1Marker>::take_metadata_and_payload(result)?;
metadata.buffer_format = Some(BufferFormat::Json);
let mut buffer = String::new();
buffer.push_str("{\"message\":\"");
helpers::escape_for_json(&old_payload.get().message, &mut buffer);
buffer.push_str("\"}");
Ok(DataResponse {
metadata,
payload: Some(DataPayload::from_owned_buffer(
buffer.into_bytes().into_boxed_slice(),
)),
})
}
}
/// A type that formats localized "hello world" strings.
///
/// This type is intended to take the shape of a typical ICU4X formatter API.
///
/// # Examples
///
/// ```
/// use icu_locid::locale;
/// use icu_provider::hello_world::{HelloWorldFormatter, HelloWorldProvider};
/// use writeable::assert_writeable_eq;
///
/// let fmt = HelloWorldFormatter::try_new_unstable(
/// &HelloWorldProvider,
/// &locale!("eo").into(),
/// )
/// .expect("locale exists");
///
/// assert_writeable_eq!(fmt.format(), "Saluton, Mondo");
/// ```
pub struct HelloWorldFormatter {
data: DataPayload<HelloWorldV1Marker>,
}
/// A formatted hello world message. Implements [`Writeable`].
///
/// For an example, see [`HelloWorldFormatter`].
pub struct FormattedHelloWorld<'l> {
data: &'l HelloWorldV1<'l>,
}
impl HelloWorldFormatter {
/// Creates a new [`HelloWorldFormatter`] for the specified locale.
///
/// See [`HelloWorldFormatter`] for an example.
///
/// [📚 Help choosing a constructor](crate::constructors)
/// <div class="stab unstable">
/// ⚠️ The bounds on this function may change over time, including in SemVer minor releases.
/// </div>
pub fn try_new_unstable<P>(provider: &P, locale: &DataLocale) -> Result<Self, DataError>
where
P: DataProvider<HelloWorldV1Marker>,
{
let data = provider
.load(DataRequest {
locale,
metadata: Default::default(),
})?
.take_payload()?;
Ok(Self { data })
}
crate::gen_any_buffer_constructors!(locale: include, options: skip, error: DataError);
/// Formats a hello world message, returning a [`FormattedHelloWorld`].
#[allow(clippy::needless_lifetimes)] // documentary example
pub fn format<'l>(&'l self) -> FormattedHelloWorld<'l> {
FormattedHelloWorld {
data: self.data.get(),
}
}
/// Formats a hello world message, returning a [`String`].
pub fn format_to_string(&self) -> String {
self.format().write_to_string().into_owned()
}
}
impl<'l> Writeable for FormattedHelloWorld<'l> {
fn write_to<W: core::fmt::Write + ?Sized>(&self, sink: &mut W) -> core::fmt::Result {
self.data.message.write_to(sink)
}
fn write_to_string(&self) -> Cow<str> {
self.data.message.clone()
}
fn writeable_length_hint(&self) -> writeable::LengthHint {
self.data.message.writeable_length_hint()
}
}
writeable::impl_display_with_writeable!(FormattedHelloWorld<'_>);
#[cfg(feature = "datagen")]
impl IterableDataProvider<HelloWorldV1Marker> for HelloWorldProvider {
fn supported_locales(&self) -> Result<Vec<DataLocale>, DataError> {
#[allow(clippy::unwrap_used)] // datagen
Ok(Self::DATA
.iter()
.map(|(s, _)| s.parse::<icu_locid::LanguageIdentifier>().unwrap())
.map(DataLocale::from)
.collect())
}
}
#[cfg(feature = "datagen")]
#[test]
fn test_iter() {
use icu_locid::locale;
assert_eq!(
HelloWorldProvider.supported_locales().unwrap(),
vec![
locale!("bn").into(),
locale!("cs").into(),
locale!("de").into(),
locale!("el").into(),
locale!("en").into(),
locale!("eo").into(),
locale!("fa").into(),
locale!("fi").into(),
locale!("is").into(),
locale!("ja").into(),
locale!("la").into(),
locale!("pt").into(),
locale!("ro").into(),
locale!("ru").into(),
locale!("vi").into(),
locale!("zh").into()
]
);
}