use crate::value::format::FormatError;
use serde_json::Value;
pub struct JsonSupport;
impl JsonSupport {
pub fn parse(input: &str) -> Result<Value, FormatError> {
serde_json::from_str(input).map_err(|e| {
FormatError::ParseError(format!("JSON parse error: {e}"))
})
}
pub fn to_pretty_string(value: &Value) -> Result<String, FormatError> {
serde_json::to_string_pretty(value).map_err(|e| {
FormatError::SerializeError(format!("JSON serialize error: {e}"))
})
}
pub fn to_compact_string(value: &Value) -> Result<String, FormatError> {
serde_json::to_string(value).map_err(|e| {
FormatError::SerializeError(format!("JSON serialize error: {e}"))
})
}
pub fn is_valid_json(input: &str) -> bool {
serde_json::from_str::<Value>(input).is_ok()
}
pub fn get_type_name(value: &Value) -> &'static str {
match value {
Value::Null => "null",
Value::Bool(_) => "boolean",
Value::Number(_) => "number",
Value::String(_) => "string",
Value::Array(_) => "array",
Value::Object(_) => "object",
}
}
pub fn deep_clone(value: &Value) -> Value {
value.clone()
}
}
pub struct JsonPath;
impl JsonPath {
pub fn get_field<'a>(value: &'a Value, field: &str) -> Option<&'a Value> {
value.as_object()?.get(field)
}
pub fn get_index(value: &Value, index: usize) -> Option<&Value> {
value.as_array()?.get(index)
}
pub fn array_len(value: &Value) -> Option<usize> {
value.as_array().map(|arr| arr.len())
}
pub fn object_keys(value: &Value) -> Option<Vec<&str>> {
value
.as_object()
.map(|obj| obj.keys().map(|s| s.as_str()).collect())
}
pub fn is_type(value: &Value, type_name: &str) -> bool {
match type_name.to_lowercase().as_str() {
"null" => value.is_null(),
"bool" | "boolean" => value.is_boolean(),
"number" | "num" => value.is_number(),
"string" | "str" => value.is_string(),
"array" | "list" => value.is_array(),
"object" | "map" => value.is_object(),
_ => false,
}
}
}
#[cfg(feature = "update")]
pub struct JsonModifier;
#[cfg(feature = "update")]
impl JsonModifier {
pub fn set_field(
value: &mut Value,
field: &str,
new_value: Value,
) -> Result<(), FormatError> {
match value {
Value::Object(map) => {
map.insert(field.to_string(), new_value);
Ok(())
}
_ => Err(FormatError::SerializeError(
"Cannot set field on non-object value".to_string(),
)),
}
}
pub fn set_index(
value: &mut Value,
index: usize,
new_value: Value,
) -> Result<(), FormatError> {
match value {
Value::Array(arr) => {
if index < arr.len() {
arr[index] = new_value;
Ok(())
} else if index == arr.len() {
arr.push(new_value);
Ok(())
} else {
Err(FormatError::SerializeError(format!(
"Array index {index} out of bounds"
)))
}
}
_ => Err(FormatError::SerializeError(
"Cannot set index on non-array value".to_string(),
)),
}
}
pub fn ensure_path<'a>(
root: &'a mut Value,
path: &[crate::parser::path::PathSegment],
) -> Result<&'a mut Value, FormatError> {
let mut current = root;
for segment in path {
match segment {
crate::parser::path::PathSegment::Field(field) => {
if !current.is_object() {
*current = serde_json::json!({});
}
let obj = current.as_object_mut().unwrap();
if !obj.contains_key(field) {
obj.insert(field.clone(), Value::Null);
}
current = obj.get_mut(field).unwrap();
}
crate::parser::path::PathSegment::Index(index) => {
if !current.is_array() {
*current = serde_json::json!([]);
}
let arr = current.as_array_mut().unwrap();
while arr.len() <= *index {
arr.push(Value::Null);
}
current = &mut arr[*index];
}
_ => {
return Err(FormatError::SerializeError(
"Cannot ensure path with wildcards or type filters"
.to_string(),
));
}
}
}
Ok(current)
}
}
#[cfg(test)]
mod tests {
use super::*;
use serde_json::json;
#[test]
fn test_json_support_parse() {
let input = r#"{"name": "Alice", "age": 30}"#;
let value = JsonSupport::parse(input).unwrap();
assert_eq!(value["name"], "Alice");
assert_eq!(value["age"], 30);
}
#[test]
fn test_json_support_serialize() {
let value = json!({"name": "Alice", "age": 30});
let pretty = JsonSupport::to_pretty_string(&value).unwrap();
assert!(pretty.contains("Alice"));
assert!(pretty.contains("30"));
let compact = JsonSupport::to_compact_string(&value).unwrap();
assert!(compact.contains("Alice"));
assert!(!compact.contains(" ")); }
#[test]
fn test_json_path_operations() {
let value = json!({
"users": [
{"name": "Alice", "age": 30},
{"name": "Bob", "age": 25}
]
});
let users = JsonPath::get_field(&value, "users").unwrap();
assert!(users.is_array());
let first_user = JsonPath::get_index(users, 0).unwrap();
assert_eq!(first_user["name"], "Alice");
assert!(JsonPath::is_type(&value["users"], "array"));
assert!(JsonPath::is_type(&value["users"][0]["name"], "string"));
}
#[test]
fn test_get_type_name() {
assert_eq!(JsonSupport::get_type_name(&json!(null)), "null");
assert_eq!(JsonSupport::get_type_name(&json!(true)), "boolean");
assert_eq!(JsonSupport::get_type_name(&json!(42)), "number");
assert_eq!(JsonSupport::get_type_name(&json!("hello")), "string");
assert_eq!(JsonSupport::get_type_name(&json!([])), "array");
assert_eq!(JsonSupport::get_type_name(&json!({})), "object");
}
#[cfg(feature = "update")]
#[test]
fn test_json_modifier() {
let mut value = json!({"users": []});
JsonModifier::set_field(&mut value, "version", json!("1.0")).unwrap();
assert_eq!(value["version"], "1.0");
let mut arr = json!([1, 2, 3]);
JsonModifier::set_index(&mut arr, 1, json!(42)).unwrap();
assert_eq!(arr[1], 42);
}
}