flow_value/
crud.rs

1use crate::Value;
2use thiserror::Error as ThisError;
3
4pub mod path;
5
6fn parse_index(key: &str) -> Option<usize> {
7    if key == "0" {
8        Some(0)
9    } else if key.starts_with('0') {
10        None
11    } else {
12        key.parse().ok()
13    }
14}
15
16/// [evaluation](https://www.rfc-editor.org/rfc/rfc6901#section-4) operation
17pub fn get<'v, S: AsRef<str>>(value: &'v Value, path: &[S]) -> Option<&'v Value> {
18    let mut result = value;
19    for s in path {
20        let key = s.as_ref();
21        result = match result {
22            Value::Map(map) => map.get(key)?,
23            Value::Array(array) => {
24                let idx = parse_index(key)?;
25                array.get(idx)?
26            }
27            _ => return None,
28        };
29    }
30    Some(result)
31}
32
33/// [evaluation](https://www.rfc-editor.org/rfc/rfc6901#section-4) operation
34pub fn get_mut<'v, S: AsRef<str>>(value: &'v mut Value, path: &[S]) -> Option<&'v mut Value> {
35    let mut result = value;
36    for s in path {
37        let key = s.as_ref();
38        result = match result {
39            Value::Map(map) => map.get_mut(key)?,
40            Value::Array(array) => {
41                let idx = parse_index(key)?;
42                array.get_mut(idx)?
43            }
44            _ => return None,
45        };
46    }
47    Some(result)
48}
49
50/// [remove](https://www.rfc-editor.org/rfc/rfc6902#section-4.2) operation
51pub fn remove<S: AsRef<str>>(value: &mut Value, path: &[S]) -> Option<Value> {
52    if path.is_empty() {
53        return Some(std::mem::replace(value, Value::Null));
54    }
55
56    let parent_path = &path[..path.len() - 1];
57
58    let parent = get_mut(value, parent_path)?;
59    let key = path.last().expect("!path.is_empty()").as_ref();
60    match parent {
61        Value::Map(map) => map.swap_remove(key),
62        Value::Array(array) => {
63            let idx = parse_index(key)?;
64            if idx < array.len() {
65                Some(array.remove(idx))
66            } else {
67                None
68            }
69        }
70        _ => None,
71    }
72}
73
74#[derive(ThisError, Debug)]
75#[error("failed to insert")]
76pub struct InsertError;
77
78/// [add](https://www.rfc-editor.org/rfc/rfc6902#section-4.1) operation
79pub fn insert<S: AsRef<str>>(
80    value: &mut Value,
81    path: &[S],
82    insert: Value,
83) -> Result<Option<Value>, InsertError> {
84    if path.is_empty() {
85        return Ok(Some(std::mem::replace(value, insert)));
86    }
87
88    let parent_path = &path[..path.len() - 1];
89    let parent = get_mut(value, parent_path).ok_or(InsertError)?;
90    let key = path.last().expect("!path.is_empty()").as_ref();
91    match parent {
92        Value::Map(map) => Ok(map.insert(key.to_owned(), insert)),
93        Value::Array(array) => {
94            if key == "-" {
95                array.push(insert);
96            } else {
97                let idx = parse_index(key).ok_or(InsertError)?;
98                if idx > array.len() {
99                    return Err(InsertError);
100                } else {
101                    array.insert(idx, insert);
102                }
103            }
104            Ok(None)
105        }
106        _ => Err(InsertError),
107    }
108}