use datavalue::{NumberValue, OwnedDataValue};
use crate::node::{
CompileCtx, CompiledMissingArg, CompiledMissingData, CompiledMissingMin, CompiledMissingPaths,
CompiledMissingSomeData, CompiledNode, PathSegment,
};
use super::path_segments::parse_path_segments;
#[inline]
fn parse_missing_arg(s: &str) -> (Box<str>, Box<[PathSegment]>) {
let segments = parse_path_segments(s).into_boxed_slice();
(s.into(), segments)
}
pub(super) fn compile_missing(args: Box<[CompiledNode]>, ctx: &mut CompileCtx) -> CompiledNode {
let mapped: Vec<CompiledMissingArg> = args
.into_vec()
.into_iter()
.map(|arg| match &arg {
CompiledNode::Value {
value: OwnedDataValue::String(s),
..
} => CompiledMissingArg::Now(parse_missing_arg(s)),
_ => CompiledMissingArg::Later(arg),
})
.collect();
CompiledNode::Missing(Box::new(CompiledMissingData {
id: Some(ctx.next_id()),
args: mapped.into_boxed_slice(),
}))
}
pub(super) fn compile_missing_some(
args: Box<[CompiledNode]>,
ctx: &mut CompileCtx,
) -> CompiledNode {
let mut iter = args.into_vec().into_iter();
let min_arg = iter.next();
let paths_arg = iter.next();
let min_present = match min_arg {
Some(CompiledNode::Value {
value: OwnedDataValue::Number(n),
..
}) => match n {
NumberValue::Integer(v) if v >= 0 => CompiledMissingMin::Now(v as usize),
NumberValue::Integer(_) => CompiledMissingMin::Now(0),
NumberValue::Float(f) => CompiledMissingMin::Now(f.max(0.0) as usize),
},
Some(other) => CompiledMissingMin::Later(other),
None => CompiledMissingMin::Now(1),
};
let paths = match paths_arg {
Some(CompiledNode::Value {
value: OwnedDataValue::Array(arr),
..
}) if arr.iter().all(|v| matches!(v, OwnedDataValue::String(_))) => {
let parsed: Vec<(Box<str>, Box<[PathSegment]>)> = arr
.into_iter()
.map(|v| match v {
OwnedDataValue::String(s) => parse_missing_arg(&s),
_ => unreachable!(),
})
.collect();
CompiledMissingPaths::Now(parsed.into_boxed_slice())
}
Some(other) => CompiledMissingPaths::Later(other),
None => CompiledMissingPaths::Now(Box::new([])),
};
CompiledNode::MissingSome(Box::new(CompiledMissingSomeData {
id: Some(ctx.next_id()),
min_present,
paths,
}))
}