use std::marker::PhantomData;
use std::ops::Deref;
use std::sync::Arc;
use bumpalo::Bump;
use datavalue::OwnedDataValue;
use crate::arena::DataValue;
use crate::{Engine, EvalInput, Logic, Result};
pub struct Session<'engine, E = &'engine Engine> {
engine: E,
arena: Bump,
_engine: PhantomData<&'engine Engine>,
}
pub type SharedSession = Session<'static, Arc<Engine>>;
impl SharedSession {
pub fn new(engine: Arc<Engine>) -> Self {
Session::with_engine(engine)
}
}
impl From<Arc<Engine>> for SharedSession {
fn from(engine: Arc<Engine>) -> Self {
SharedSession::new(engine)
}
}
impl<E: Deref<Target = Engine>> std::fmt::Debug for Session<'_, E> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("Session")
.field("engine", &*self.engine)
.field("arena_allocated_bytes", &self.arena.allocated_bytes())
.finish_non_exhaustive()
}
}
impl<'engine> Session<'engine> {
#[inline]
pub(crate) fn borrowing(engine: &'engine Engine) -> Self {
Session::with_engine(engine)
}
}
impl<'engine, E: Deref<Target = Engine>> Session<'engine, E> {
#[inline]
fn with_engine(engine: E) -> Self {
Self {
engine,
arena: Bump::new(),
_engine: PhantomData,
}
}
#[inline]
pub fn engine(&self) -> &Engine {
&self.engine
}
#[inline]
pub fn reset(&mut self) {
self.arena.reset();
}
pub fn reset_with_capacity(&mut self, capacity: usize) {
self.arena = Bump::with_capacity(capacity);
}
#[inline]
pub fn allocated_bytes(&self) -> usize {
self.arena.allocated_bytes()
}
pub fn eval<'a, D>(&'a mut self, compiled: &Logic, data: D) -> Result<OwnedDataValue>
where
D: EvalInput<'a>,
{
self.eval_as(compiled, data)
}
pub fn eval_as<'a, R, D>(&'a mut self, compiled: &Logic, data: D) -> Result<R>
where
R: crate::FromDataValue,
D: EvalInput<'a>,
{
let arena: &'a Bump = &self.arena;
let compiled = compiled.for_engine(&self.engine);
let av = data.into_arena_for(compiled, &self.engine, arena)?;
R::from_arena(self.engine.evaluate(compiled, av, arena)?)
}
pub fn eval_str<'a, D>(&'a mut self, compiled: &Logic, data: D) -> Result<String>
where
D: EvalInput<'a>,
{
self.eval_as(compiled, data)
}
#[cfg(feature = "serde_json")]
#[cfg_attr(docsrs, doc(cfg(feature = "serde_json")))]
pub fn eval_into<'a, T, D>(&'a mut self, compiled: &Logic, data: D) -> Result<T>
where
T: serde::de::DeserializeOwned,
D: EvalInput<'a>,
{
let value: serde_json::Value = self.eval_as(compiled, data)?;
serde_json::from_value(value).map_err(crate::Error::from)
}
#[cfg(feature = "budget")]
#[cfg_attr(docsrs, doc(cfg(feature = "budget")))]
pub fn eval_metered<'a, D>(
&'a mut self,
compiled: &Logic,
data: D,
budget: u64,
) -> Result<crate::Metered<OwnedDataValue>>
where
D: EvalInput<'a>,
{
self.eval_metered_report(compiled, data, budget).transpose()
}
#[cfg(feature = "budget")]
#[cfg_attr(docsrs, doc(cfg(feature = "budget")))]
pub fn eval_metered_report<'a, D>(
&'a mut self,
compiled: &Logic,
data: D,
budget: u64,
) -> crate::Metered<Result<OwnedDataValue>>
where
D: EvalInput<'a>,
{
let arena: &'a Bump = &self.arena;
let compiled = compiled.for_engine(&self.engine);
let av = match data.into_arena_for(compiled, &self.engine, arena) {
Ok(av) => av,
Err(e) => {
return crate::Metered {
value: Err(e),
ops: 0,
};
}
};
let metered = self
.engine
.evaluate_metered_report(compiled, av, arena, budget);
crate::Metered {
value: metered.value.and_then(crate::FromDataValue::from_arena),
ops: metered.ops,
}
}
pub fn eval_borrowed<'a, D>(
&'a mut self,
compiled: &'a Logic,
data: D,
) -> Result<&'a DataValue<'a>>
where
D: EvalInput<'a>,
{
let arena: &'a Bump = &self.arena;
self.engine.evaluate(compiled, data, arena)
}
}