1use alloc::format;
7use alloc::string::String;
8
9use serde_json::{Map, Value};
10
11pub const PREV: &str = "$prev";
13
14pub const ITEM: &str = "$item";
16
17pub fn fill(input: &Value, prev: Option<&Value>) -> Result<Value, String> {
22 fill_with(input, prev, None)
23}
24
25pub fn fill_with(
32 input: &Value,
33 prev: Option<&Value>,
34 item: Option<&Value>,
35) -> Result<Value, String> {
36 match input {
37 Value::Object(object) => {
38 if let Some(pointer) = sole(object, PREV) {
39 let prev = prev.ok_or_else(|| format!("{PREV} {pointer:?} in the first step"))?;
40 return prev.pointer(pointer).cloned().ok_or_else(|| {
41 format!("{PREV} {pointer:?} names nothing in the previous reply")
42 });
43 }
44 if let Some(pointer) = sole(object, ITEM) {
45 let item = item.ok_or_else(|| format!("{ITEM} {pointer:?} outside a fan-out"))?;
46 return item
47 .pointer(pointer)
48 .cloned()
49 .ok_or_else(|| format!("{ITEM} {pointer:?} names nothing in the element"));
50 }
51 let mut filled = Map::with_capacity(object.len());
52 for (key, value) in object {
53 filled.insert(key.clone(), fill_with(value, prev, item)?);
54 }
55 Ok(Value::Object(filled))
56 }
57 Value::Array(items) => items
58 .iter()
59 .map(|value| fill_with(value, prev, item))
60 .collect::<Result<_, _>>()
61 .map(Value::Array),
62 other => Ok(other.clone()),
63 }
64}
65
66#[must_use]
69pub fn names_prev(input: &Value) -> bool {
70 match input {
71 Value::Object(object) => sole(object, PREV).is_some() || object.values().any(names_prev),
72 Value::Array(items) => items.iter().any(names_prev),
73 _ => false,
74 }
75}
76
77fn sole<'a>(object: &'a Map<String, Value>, key: &str) -> Option<&'a str> {
79 match (object.len(), object.get(key)) {
80 (1, Some(Value::String(pointer))) => Some(pointer),
81 _ => None,
82 }
83}
84
85#[cfg(test)]
86#[path = "prev_tests.rs"]
87mod tests;