use bytes::Bytes;
use super::index::OpPathIndex;
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub(crate) enum OpKind {
Add,
Replace,
Remove,
Extract,
}
impl OpKind {
pub(crate) const fn is_mutating(self) -> bool {
matches!(self, Self::Add | Self::Replace | Self::Remove)
}
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub enum ExtractDest {
Metadata(String),
Structured {
namespace: String,
key: String,
},
Header(String),
}
impl ExtractDest {
#[must_use]
pub fn metadata(key: impl Into<String>) -> Self {
Self::Metadata(key.into())
}
#[must_use]
pub fn structured(namespace: impl Into<String>, key: impl Into<String>) -> Self {
Self::Structured {
namespace: namespace.into(),
key: key.into(),
}
}
#[must_use]
pub fn header(name: impl Into<String>) -> Self {
Self::Header(name.into())
}
}
#[derive(Clone, Debug)]
pub(crate) enum ValueSource {
Static(Bytes),
Metadata(String),
Structured {
namespace: String,
key: String,
},
}
#[derive(Clone, Debug)]
pub(crate) struct CompiledOp {
pub pointer: String,
pub tokens: Vec<String>,
pub kind: OpKind,
pub source: Option<ValueSource>,
pub dest: Option<ExtractDest>,
pub encoded_last_token: Option<Bytes>,
}
#[derive(Clone, Debug)]
pub(crate) struct CompiledOpSet {
pub ops: Vec<CompiledOp>,
pub index: OpPathIndex,
pub growth_hint: usize,
pub extract_only: bool,
}
impl CompiledOpSet {
pub(crate) fn empty() -> Self {
Self {
ops: Vec::new(),
index: OpPathIndex::build(&[]),
growth_hint: 0,
extract_only: false,
}
}
pub(crate) fn finalize(ops: Vec<CompiledOp>) -> Self {
let growth_hint = ops.iter().map(op_growth_bytes).sum();
let index = OpPathIndex::build(&ops);
let extract_only = !ops.is_empty() && ops.iter().all(|op| op.kind == OpKind::Extract);
Self {
ops,
index,
growth_hint,
extract_only,
}
}
}
pub(crate) fn op_growth_bytes(op: &CompiledOp) -> usize {
let payload = match &op.source {
Some(ValueSource::Static(bytes)) => bytes.len(),
Some(ValueSource::Metadata(_) | ValueSource::Structured { .. }) | None => 0,
};
let key = op.encoded_last_token.as_ref().map_or(0, Bytes::len);
match op.kind {
OpKind::Add | OpKind::Replace => payload.saturating_add(key),
OpKind::Remove | OpKind::Extract => 0,
}
}