use crate::dimensions;
use crate::locale::Locale;
use crate::types::{DimensionValue, Entity, Node, TokenData};
use chrono::{DateTime, FixedOffset, Utc};
#[cfg(not(debug_assertions))]
use std::panic::{catch_unwind, AssertUnwindSafe};
#[derive(Debug, Clone)]
pub struct Context {
pub reference_time: DateTime<FixedOffset>,
pub locale: Locale,
}
impl Context {
pub fn new(reference_time: DateTime<FixedOffset>, locale: Locale) -> Self {
Self {
reference_time,
locale,
}
}
pub fn timezone(&self) -> FixedOffset {
*self.reference_time.offset()
}
}
impl Default for Context {
fn default() -> Self {
Self::new(Utc::now().fixed_offset(), Locale::default())
}
}
#[derive(Debug, Clone, Default)]
pub struct Options {
pub with_latent: bool,
}
pub fn resolve(
node: &Node,
context: &Context,
options: &Options,
text: &str,
budget: &mut dimensions::time::series::Budget,
) -> Option<Entity> {
let body = text[node.range.start..node.range.end].to_string();
let latent = node.token_data.is_latent();
let resolved = resolve_token(&node.token_data, context, options, budget)?;
Some(Entity {
body,
start: node.range.start,
end: node.range.end,
value: resolved,
latent: Some(latent),
})
}
fn resolve_token(
token: &TokenData,
context: &Context,
options: &Options,
budget: &mut dimensions::time::series::Budget,
) -> Option<DimensionValue> {
#[cfg(debug_assertions)]
{
match token {
TokenData::Numeral(data) => Some(dimensions::numeral::resolve(data)),
TokenData::Ordinal(data) => Some(dimensions::ordinal::resolve(data)),
TokenData::Temperature(data) => dimensions::temperature::resolve(data),
TokenData::Distance(data) => dimensions::distance::resolve(data),
TokenData::Volume(data) => dimensions::volume::resolve(data),
TokenData::Quantity(data) => dimensions::quantity::resolve(data),
TokenData::AmountOfMoney(data) => {
dimensions::amount_of_money::resolve(data, options.with_latent)
}
TokenData::Email(data) => Some(dimensions::email::resolve(data)),
TokenData::PhoneNumber(data) => Some(dimensions::phone_number::resolve(data)),
TokenData::Url(data) => Some(dimensions::url::resolve(data)),
TokenData::CreditCardNumber(data) => {
Some(dimensions::credit_card_number::resolve(data))
}
TokenData::TimeGrain(grain) => Some(dimensions::time_grain::resolve(grain)),
TokenData::Duration(data) => Some(dimensions::duration::resolve(data)),
TokenData::Time(data) => {
dimensions::time::resolve(data, context, options.with_latent, budget)
}
TokenData::RegexMatch(_) => None,
}
}
#[cfg(not(debug_assertions))]
{
catch_unwind(AssertUnwindSafe(|| match token {
TokenData::Numeral(data) => Some(dimensions::numeral::resolve(data)),
TokenData::Ordinal(data) => Some(dimensions::ordinal::resolve(data)),
TokenData::Temperature(data) => dimensions::temperature::resolve(data),
TokenData::Distance(data) => dimensions::distance::resolve(data),
TokenData::Volume(data) => dimensions::volume::resolve(data),
TokenData::Quantity(data) => dimensions::quantity::resolve(data),
TokenData::AmountOfMoney(data) => {
dimensions::amount_of_money::resolve(data, options.with_latent)
}
TokenData::Email(data) => Some(dimensions::email::resolve(data)),
TokenData::PhoneNumber(data) => Some(dimensions::phone_number::resolve(data)),
TokenData::Url(data) => Some(dimensions::url::resolve(data)),
TokenData::CreditCardNumber(data) => {
Some(dimensions::credit_card_number::resolve(data))
}
TokenData::TimeGrain(grain) => Some(dimensions::time_grain::resolve(grain)),
TokenData::Duration(data) => Some(dimensions::duration::resolve(data)),
TokenData::Time(data) => {
dimensions::time::resolve(data, context, options.with_latent, budget)
}
TokenData::RegexMatch(_) => None,
}))
.ok()
.flatten()
}
}