use fluent::FluentValue;
use fluent::types::{FluentNumber, FluentNumberOptions, FluentNumberStyle, FluentNumberType};
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct VariableDescription {
#[serde(default)]
pub optional: bool,
#[serde(default)]
pub one_of: Option<Vec<Variable>>,
#[serde(default)]
pub default_value: Option<Variable>,
#[serde(rename = "type")]
pub typ: VariableType,
#[serde(default)]
pub use_grouping: bool,
#[serde(default)]
pub minimum_integer_digits: Option<usize>,
#[serde(default)]
pub minimum_fraction_digits: Option<usize>,
#[serde(default)]
pub maximum_fraction_digits: Option<usize>,
#[serde(default)]
pub minimum_significant_digits: Option<usize>,
#[serde(default)]
pub maximum_significant_digits: Option<usize>,
}
impl VariableDescription {
pub fn matches_variable(&self, var: &Variable) -> bool {
if var.get_affinity() != self.typ.get_affinity() {
return false;
}
if let Some(list) = &self.one_of {
for test in list {
if var == test {
return true;
}
}
return false;
}
return true;
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum VariableType {
Text,
Bool,
Cardinal,
Ordinal,
DefaultNumber,
Percent,
}
impl VariableType {
pub fn get_affinity(&self) -> VariableAffinity {
match self {
Self::Text => VariableAffinity::Text,
Self::Bool => VariableAffinity::Bool,
Self::Percent | Self::Cardinal | Self::Ordinal | Self::DefaultNumber => {
VariableAffinity::Number
}
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum VariableAffinity {
Text,
Number,
Bool,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(untagged)]
pub enum Variable {
Text(String),
Number(f64),
Bool(bool),
}
impl Variable {
pub fn get_affinity(&self) -> VariableAffinity {
match self {
Self::Text(_) => VariableAffinity::Text,
Self::Number(_) => VariableAffinity::Number,
Self::Bool(_) => VariableAffinity::Bool,
}
}
pub fn into_fluent_value(self, description: &VariableDescription) -> FluentValue<'static> {
match self {
Self::Text(text) => FluentValue::String(text.into()),
Self::Bool(true) => FluentValue::String("true".into()),
Self::Bool(false) => FluentValue::String("false".into()),
Self::Number(n) if matches!(description.typ, VariableType::DefaultNumber) => {
FluentValue::Number(FluentNumber {
value: n,
options: Default::default(),
})
}
Self::Number(n) => FluentValue::Number(FluentNumber {
value: n,
options: FluentNumberOptions {
r#type: if matches!(description.typ, VariableType::Ordinal) {
FluentNumberType::Ordinal
} else {
FluentNumberType::Cardinal
},
style: if matches!(description.typ, VariableType::Percent) {
FluentNumberStyle::Percent
} else {
FluentNumberStyle::Decimal
},
currency: None,
currency_display: Default::default(),
use_grouping: description.use_grouping,
minimum_integer_digits: description.minimum_integer_digits,
minimum_fraction_digits: description.minimum_fraction_digits,
maximum_fraction_digits: description.maximum_fraction_digits,
minimum_significant_digits: description.minimum_significant_digits,
maximum_significant_digits: description.maximum_significant_digits,
},
}),
}
}
}