use crate::bindings::payload::PayloadBinding;
use crate::constants::PAYLOAD;
use crate::context::input::InputContext;
use crate::input::Format;
use crate::value::Value;
use pel::expression::Symbol;
use pel::runtime::value::Value as PelValue;
use pel::runtime::{Binding as PelBinding, Context, ValueHandler};
use pel::Reference;
use std::cell::RefCell;
pub(crate) struct PayloadContext<'a> {
input_context: &'a InputContext,
binding: &'a dyn PayloadBinding,
payload: RefCell<Option<PelValue>>,
}
impl<'a> PayloadContext<'a> {
pub fn new(input_context: &'a InputContext, binding: &'a dyn PayloadBinding) -> Self {
Self {
input_context,
binding,
payload: RefCell::new(None),
}
}
fn do_resolve(&self) -> PelValue {
let present = self.payload.borrow().is_some();
if !present {
let bytes = self.binding.as_bytes();
let value = match self.input_context.format().unwrap_or(&Format::PlainText) {
Format::Json => serde_json::from_slice(bytes.as_ref()).unwrap_or(Value::Null),
Format::PlainText => {
Value::String(String::from_utf8_lossy(bytes.as_ref()).to_string())
}
};
self.payload.replace(Some(value.into_pel()));
}
self.payload
.borrow()
.as_ref()
.cloned()
.unwrap_or_else(PelValue::null)
}
}
impl Context for PayloadContext<'_> {
fn resolve(&self, symbol: &Symbol) -> PelBinding {
match self.input_context.format().is_some() && symbol.as_str() == PAYLOAD {
true => PelBinding::Available(self.do_resolve()),
false => PelBinding::Unknown,
}
}
fn value_handler(&self, _reference: Reference) -> Option<&dyn ValueHandler> {
None
}
}