mod compile_ctx;
mod logic;
mod payload;
mod populate;
mod prelit;
pub use logic::Logic;
pub(crate) use compile_ctx::{CompileCtx, NodeId, SYNTHETIC_ID};
pub(crate) use logic::node_is_static;
#[cfg(feature = "ext-control")]
pub(crate) use payload::CompiledExistsData;
#[cfg(feature = "error-handling")]
pub(crate) use payload::CompiledThrowData;
#[cfg(feature = "templating")]
pub(crate) use payload::StructuredObjectData;
pub(crate) use payload::{
CompiledMissingArg, CompiledMissingData, CompiledMissingMin, CompiledMissingPaths,
CompiledMissingSomeData, CseData, CustomOperatorData, MetadataHint, PathSegment, ReduceHint,
};
pub(crate) use populate::populate_lits;
pub(crate) use prelit::PreLit;
use crate::opcode::OpCode;
use datavalue::OwnedDataValue;
use populate::precompute_lit;
use std::num::NonZeroU32;
#[derive(Debug, Clone)]
pub(crate) enum CompiledNode {
Value {
id: NodeId,
value: OwnedDataValue,
lit: Option<PreLit>,
},
Array {
id: NodeId,
nodes: Box<[CompiledNode]>,
},
BuiltinOperator {
id: NodeId,
opcode: OpCode,
args: Box<[CompiledNode]>,
predicate_hint: Option<Box<crate::operators::array::FastPredicate>>,
iter_arg_kind: crate::operators::array::IterArgKind,
},
CustomOperator(Box<CustomOperatorData>),
#[cfg(feature = "templating")]
StructuredObject(Box<StructuredObjectData>),
Var {
id: NodeId,
scope_level: u32,
segments: Box<[PathSegment]>,
reduce_hint: ReduceHint,
metadata_hint: MetadataHint,
default_value: Option<Box<CompiledNode>>,
},
#[cfg(feature = "ext-control")]
Exists(Box<CompiledExistsData>),
#[cfg(feature = "error-handling")]
Throw(Box<CompiledThrowData>),
Missing(Box<CompiledMissingData>),
MissingSome(Box<CompiledMissingSomeData>),
InvalidArgs { id: NodeId, op_name: &'static str },
Cse(Box<CseData>),
}
impl CompiledNode {
#[inline]
pub(crate) fn id(&self) -> u32 {
self.node_id().map(NonZeroU32::get).unwrap_or(0)
}
#[inline]
pub(crate) fn node_id(&self) -> NodeId {
match self {
CompiledNode::Value { id, .. } => *id,
CompiledNode::Array { id, .. } => *id,
CompiledNode::BuiltinOperator { id, .. } => *id,
CompiledNode::CustomOperator(data) => data.id,
CompiledNode::Cse(data) => data.inner.node_id(),
#[cfg(feature = "templating")]
CompiledNode::StructuredObject(data) => data.id,
CompiledNode::Var { id, .. } => *id,
#[cfg(feature = "ext-control")]
CompiledNode::Exists(data) => data.id,
#[cfg(feature = "error-handling")]
CompiledNode::Throw(data) => data.id,
CompiledNode::Missing(data) => data.id,
CompiledNode::MissingSome(data) => data.id,
CompiledNode::InvalidArgs { id, .. } => *id,
}
}
pub(crate) fn visit_indexed_children<F: FnMut(u32, &CompiledNode)>(&self, f: &mut F) {
match self {
CompiledNode::Value { .. } => {}
CompiledNode::Array { nodes, .. } => {
for (i, n) in nodes.iter().enumerate() {
f(i as u32, n);
}
}
CompiledNode::BuiltinOperator { args, .. } => {
for (i, n) in args.iter().enumerate() {
f(i as u32, n);
}
}
CompiledNode::CustomOperator(data) => {
for (i, n) in data.args.iter().enumerate() {
f(i as u32, n);
}
}
CompiledNode::Cse(data) => f(0, &data.inner),
#[cfg(feature = "templating")]
CompiledNode::StructuredObject(data) => {
for (i, (_, n)) in data.fields.iter().enumerate() {
f(i as u32, n);
}
}
CompiledNode::Var { default_value, .. } => {
if let Some(d) = default_value {
f(0, d);
}
}
#[cfg(feature = "ext-control")]
CompiledNode::Exists(_) => {}
#[cfg(feature = "error-handling")]
CompiledNode::Throw(_) => {}
CompiledNode::Missing(data) => {
for (i, arg) in data.args.iter().enumerate() {
if let CompiledMissingArg::Later(n) = arg {
f(i as u32, n);
}
}
}
CompiledNode::MissingSome(data) => {
if let CompiledMissingMin::Later(n) = &data.min_present {
f(0, n);
}
if let CompiledMissingPaths::Later(n) = &data.paths {
f(1, n);
}
}
CompiledNode::InvalidArgs { .. } => {}
}
}
pub(crate) fn visit_children_mut<F: FnMut(&mut CompiledNode)>(&mut self, f: &mut F) {
match self {
CompiledNode::Value { .. } => {}
CompiledNode::Array { nodes, .. } => {
for n in nodes.iter_mut() {
f(n);
}
}
CompiledNode::BuiltinOperator { args, .. } => {
for n in args.iter_mut() {
f(n);
}
}
CompiledNode::CustomOperator(data) => {
for n in data.args.iter_mut() {
f(n);
}
}
CompiledNode::Cse(data) => f(&mut data.inner),
#[cfg(feature = "templating")]
CompiledNode::StructuredObject(data) => {
for (_, n) in data.fields.iter_mut() {
f(n);
}
}
CompiledNode::Var { default_value, .. } => {
if let Some(d) = default_value {
f(d);
}
}
#[cfg(feature = "ext-control")]
CompiledNode::Exists(_) => {}
#[cfg(feature = "error-handling")]
CompiledNode::Throw(_) => {}
CompiledNode::Missing(data) => {
for arg in data.args.iter_mut() {
if let CompiledMissingArg::Later(n) = arg {
f(n);
}
}
}
CompiledNode::MissingSome(data) => {
if let CompiledMissingMin::Later(n) = &mut data.min_present {
f(n);
}
if let CompiledMissingPaths::Later(n) = &mut data.paths {
f(n);
}
}
CompiledNode::InvalidArgs { .. } => {}
}
}
#[inline]
pub(crate) fn synthetic_value(value: OwnedDataValue) -> Self {
Self::value_with_id(SYNTHETIC_ID, value)
}
#[inline]
pub(crate) fn value_with_id(id: NodeId, value: OwnedDataValue) -> Self {
let lit = precompute_lit(&value);
CompiledNode::Value { id, value, lit }
}
pub(crate) fn compile_time_value(id: NodeId, value: OwnedDataValue) -> Self {
let mut node = Self::value_with_id(id, value);
if let CompiledNode::Value { value, lit, .. } = &mut node {
if lit.is_none() {
*lit = PreLit::composite(value);
}
}
node
}
pub(crate) fn operator_name(&self) -> Option<std::borrow::Cow<'static, str>> {
use std::borrow::Cow;
match self {
CompiledNode::BuiltinOperator { opcode, .. } => Some(Cow::Borrowed(opcode.as_str())),
CompiledNode::CustomOperator(data) => Some(Cow::Owned(data.name.clone())),
CompiledNode::Cse(data) => data.inner.operator_name(),
CompiledNode::Var { .. } => Some(Cow::Borrowed("var")),
#[cfg(feature = "ext-control")]
CompiledNode::Exists(_) => Some(Cow::Borrowed("exists")),
#[cfg(feature = "error-handling")]
CompiledNode::Throw(_) => Some(Cow::Borrowed("throw")),
CompiledNode::Missing(_) => Some(Cow::Borrowed("missing")),
CompiledNode::MissingSome(_) => Some(Cow::Borrowed("missing_some")),
CompiledNode::InvalidArgs { op_name, .. } => Some(Cow::Borrowed(op_name)),
_ => None,
}
}
}
#[cfg(test)]
mod layout_tests {
#[test]
#[cfg(target_pointer_width = "64")]
fn compiled_node_stays_small() {
assert!(
std::mem::size_of::<super::CompiledNode>() <= 48,
"CompiledNode grew past 48 bytes ({}); box the payload of the offending variant",
std::mem::size_of::<super::CompiledNode>()
);
}
}