use crate::arena::DataValue;
use crate::arena::value::coerce_to_number;
use bumpalo::Bump;
use std::fmt::Display;
#[inline]
fn write_into_arena<'a>(arena: &'a Bump, value: impl Display) -> &'a DataValue<'a> {
use std::fmt::Write;
let mut buf = bumpalo::collections::String::new_in(arena);
write!(&mut buf, "{}", value).expect("bumpalo String write is infallible");
arena.alloc(DataValue::String(buf.into_bump_str()))
}
#[inline]
fn extract_dt_dur(
av: &DataValue<'_>,
) -> (
Option<datavalue::DataDateTime>,
Option<datavalue::DataDuration>,
) {
use super::{extract_datetime, extract_duration};
let dt = extract_datetime(av);
let dur = if dt.is_none() {
extract_duration(av)
} else {
None
};
(dt, dur)
}
#[inline]
pub(crate) fn datetime_subtract<'a>(
a_av: &'a DataValue<'a>,
b_av: &'a DataValue<'a>,
arena: &'a Bump,
) -> Option<&'a DataValue<'a>> {
let (a_dt, a_dur) = extract_dt_dur(a_av);
let (b_dt, b_dur) = extract_dt_dur(b_av);
if let (Some(d1), Some(d2)) = (&a_dt, &b_dt) {
return Some(write_into_arena(arena, d1.diff(d2)));
}
if let (Some(d), Some(dur)) = (&a_dt, &b_dur) {
return Some(write_into_arena(arena, d.sub_duration(dur)));
}
if let (Some(d1), Some(d2)) = (&a_dur, &b_dur) {
return Some(write_into_arena(arena, d1.sub(d2)));
}
None
}
#[inline]
pub(crate) fn datetime_add<'a>(
a_av: &'a DataValue<'a>,
b_av: &'a DataValue<'a>,
arena: &'a Bump,
) -> Option<&'a DataValue<'a>> {
let (a_dt, a_dur) = extract_dt_dur(a_av);
let (_b_dt, b_dur) = extract_dt_dur(b_av);
if let (Some(dt), Some(dur)) = (&a_dt, &b_dur) {
return Some(write_into_arena(arena, dt.add_duration(dur)));
}
if let (Some(d1), Some(d2)) = (&a_dur, &b_dur) {
return Some(write_into_arena(arena, d1.add(d2)));
}
None
}
#[inline]
pub(crate) fn datetime_multiply<'a>(
a_av: &'a DataValue<'a>,
b_av: &'a DataValue<'a>,
arena: &'a Bump,
) -> Option<&'a DataValue<'a>> {
let (_, a_dur) = extract_dt_dur(a_av);
let (_, b_dur) = extract_dt_dur(b_av);
if let (Some(dur), None) = (&a_dur, &b_dur) {
if let Some(factor) = coerce_to_number(b_av) {
return Some(write_into_arena(arena, dur.multiply(factor)));
}
}
if let (None, Some(dur)) = (&a_dur, &b_dur) {
if let Some(factor) = coerce_to_number(a_av) {
return Some(write_into_arena(arena, dur.multiply(factor)));
}
}
None
}
#[inline]
pub(crate) fn datetime_divide<'a>(
a_av: &'a DataValue<'a>,
b_av: &'a DataValue<'a>,
arena: &'a Bump,
) -> Option<crate::Result<&'a DataValue<'a>>> {
let (_, a_dur) = extract_dt_dur(a_av);
let a_dur = a_dur?;
let divisor = coerce_to_number(b_av)?;
if divisor == 0.0 {
return Some(Err(crate::Error::nan()));
}
Some(Ok(write_into_arena(arena, a_dur.divide(divisor))))
}