use crate::errors::{error, nil, New};
use crate::types::{byte, int, slice, string};
pub use serde_json::Value as RawValue;
pub type RawMessage = Vec<byte>;
#[derive(Debug, Clone, PartialEq)]
pub enum Value {
Null,
Bool(bool),
Number(f64),
String(string),
Array(Vec<Value>),
Object(Vec<(string, Value)>),
}
impl Default for Value {
fn default() -> Self { Value::Null }
}
impl Value {
pub fn IsNull(&self) -> bool { matches!(self, Value::Null) }
pub fn IsBool(&self) -> bool { matches!(self, Value::Bool(_)) }
pub fn IsNumber(&self) -> bool { matches!(self, Value::Number(_)) }
pub fn IsString(&self) -> bool { matches!(self, Value::String(_)) }
pub fn IsArray(&self) -> bool { matches!(self, Value::Array(_)) }
pub fn IsObject(&self) -> bool { matches!(self, Value::Object(_)) }
pub fn String(&self) -> string {
match self {
Value::String(s) => s.clone(),
_ => "".into(),
}
}
pub fn Int(&self) -> crate::types::int64 {
match self {
Value::Number(n) => *n as i64,
_ => 0,
}
}
pub fn Float(&self) -> f64 {
match self {
Value::Number(n) => *n,
_ => 0.0,
}
}
pub fn Bool(&self) -> bool {
match self {
Value::Bool(b) => *b,
_ => false,
}
}
pub fn Get(&self, key: impl AsRef<str>) -> Value {
if let Value::Object(m) = self {
for (k, v) in m {
if k == key.as_ref() { return v.clone(); }
}
}
Value::Null
}
pub fn Index(&self, i: int) -> Value {
if let Value::Array(a) = self {
if i >= 0 && (i as usize) < a.len() { return a[i as usize].clone(); }
}
Value::Null
}
pub fn Len(&self) -> int {
match self {
Value::Array(a) => a.len() as int,
Value::Object(o) => o.len() as int,
Value::String(s) => s.len() as int,
_ => 0,
}
}
pub fn Set(&mut self, key: impl AsRef<str>, value: Value) {
if let Value::Object(m) = self {
for (k, v) in m.iter_mut() {
if k == key.as_ref() { *v = value; return; }
}
m.push((key.as_ref().into(), value));
}
}
}
fn to_raw(v: &Value) -> RawValue {
match v {
Value::Null => RawValue::Null,
Value::Bool(b) => RawValue::Bool(*b),
Value::Number(n) => {
if n.is_finite() && n.fract() == 0.0 && *n >= i64::MIN as f64 && *n <= i64::MAX as f64 {
RawValue::Number(serde_json::Number::from(*n as i64))
} else {
serde_json::Number::from_f64(*n)
.map(RawValue::Number)
.unwrap_or(RawValue::Null)
}
}
Value::String(s) => RawValue::String(s.as_str().into()),
Value::Array(a) => RawValue::Array(a.iter().map(to_raw).collect()),
Value::Object(m) => {
let mut map = serde_json::Map::new();
for (k, v) in m {
map.insert(k.as_str().into(), to_raw(v));
}
RawValue::Object(map)
}
}
}
fn from_raw(v: &RawValue) -> Value {
match v {
RawValue::Null => Value::Null,
RawValue::Bool(b) => Value::Bool(*b),
RawValue::Number(n) => Value::Number(n.as_f64().unwrap_or(0.0)),
RawValue::String(s) => Value::String(s.as_str().into()),
RawValue::Array(a) => Value::Array(a.iter().map(from_raw).collect()),
RawValue::Object(m) => Value::Object(
m.iter().map(|(k, v)| (string::from(k.as_str()), from_raw(v))).collect()
),
}
}
#[allow(non_snake_case)]
pub fn Marshal(v: &Value) -> (Vec<byte>, error) {
match serde_json::to_vec(&to_raw(v)) {
Ok(b) => (b, nil),
Err(e) => (Vec::new(), New(&e.to_string())),
}
}
#[allow(non_snake_case)]
pub fn MarshalIndent(v: &Value, _prefix: impl AsRef<str>, indent: impl AsRef<str>) -> (Vec<byte>, error) {
let indent = indent.as_ref();
let mut buf = Vec::new();
let formatter = serde_json::ser::PrettyFormatter::with_indent(indent.as_bytes());
let mut ser = serde_json::Serializer::with_formatter(&mut buf, formatter);
use serde::Serialize;
match to_raw(v).serialize(&mut ser) {
Ok(()) => (buf, nil),
Err(e) => (Vec::new(), New(&e.to_string())),
}
}
#[allow(non_snake_case)]
pub fn Unmarshal(data: &[byte], v: &mut Value) -> error {
match serde_json::from_slice::<RawValue>(data) {
Ok(raw) => {
*v = from_raw(&raw);
nil
}
Err(e) => New(&e.to_string()),
}
}
#[allow(non_snake_case)]
pub fn Valid(data: &[byte]) -> bool {
serde_json::from_slice::<RawValue>(data).is_ok()
}
#[allow(non_snake_case)]
pub fn HTMLEscape(dst: &mut Vec<byte>, src: &[byte]) {
let n = src.len();
let mut i = 0;
while i < n {
let c = src[i];
if c == b'<' || c == b'>' || c == b'&' {
dst.extend_from_slice(&[b'\\', b'u', b'0', b'0']);
const HEX: &[u8] = b"0123456789abcdef";
dst.push(HEX[(c >> 4) as usize]);
dst.push(HEX[(c & 0xf) as usize]);
i += 1;
continue;
}
if i + 2 < n && src[i] == 0xe2 && src[i+1] == 0x80 && (src[i+2] == 0xa8 || src[i+2] == 0xa9) {
dst.extend_from_slice(b"\\u202");
dst.push(if src[i+2] == 0xa8 { b'8' } else { b'9' });
i += 3;
continue;
}
dst.push(c);
i += 1;
}
}
#[allow(non_snake_case)]
pub fn Compact(dst: &mut Vec<byte>, src: &[byte]) -> error {
match serde_json::from_slice::<RawValue>(src) {
Ok(raw) => match serde_json::to_vec(&raw) {
Ok(bs) => { dst.extend_from_slice(&bs); nil }
Err(e) => New(&e.to_string()),
},
Err(e) => New(&e.to_string()),
}
}
#[allow(non_snake_case)]
pub fn Indent(dst: &mut Vec<byte>, src: &[byte], _prefix: impl AsRef<str>, indent: impl AsRef<str>) -> error {
let indent_bytes = indent.as_ref().as_bytes().to_vec();
match serde_json::from_slice::<RawValue>(src) {
Ok(raw) => {
let formatter = serde_json::ser::PrettyFormatter::with_indent(&indent_bytes);
let mut ser = serde_json::Serializer::with_formatter(Vec::<u8>::new(), formatter);
use serde::Serialize;
match raw.serialize(&mut ser) {
Ok(()) => { dst.extend_from_slice(&ser.into_inner()); nil }
Err(e) => New(&e.to_string()),
}
}
Err(e) => New(&e.to_string()),
}
}
#[allow(non_snake_case)]
pub fn Object(pairs: slice<(string, Value)>) -> Value {
Value::Object(pairs.into_vec())
}
#[allow(non_snake_case)]
pub fn Array(values: slice<Value>) -> Value {
Value::Array(values.into_vec())
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn marshal_simple_object() {
let mut v = Value::Object(Vec::new());
v.Set("name", Value::String("alice".into()));
v.Set("age", Value::Number(30.0));
let (data, err) = Marshal(&v);
assert_eq!(err, nil);
let s = String::from_utf8(data).unwrap();
assert!(s.contains("\"name\":\"alice\""));
assert!(s.contains("\"age\":30"));
}
#[test]
fn unmarshal_simple_object() {
let s = r#"{"name":"alice","age":30,"active":true,"tags":["a","b"]}"#;
let mut v = Value::Null;
let err = Unmarshal(s.as_bytes(), &mut v);
assert_eq!(err, nil);
assert_eq!(v.Get("name").String(), "alice");
assert_eq!(v.Get("age").Int(), 30);
assert_eq!(v.Get("active").Bool(), true);
assert_eq!(v.Get("tags").Len(), 2);
assert_eq!(v.Get("tags").Index(0).String(), "a");
}
#[test]
fn unmarshal_invalid_returns_error() {
let mut v = Value::Null;
let err = Unmarshal(b"{broken}", &mut v);
assert!(err != nil);
}
#[test]
fn marshal_indent_formats() {
let mut v = Value::Object(Vec::new());
v.Set("x", Value::Number(1.0));
let (data, err) = MarshalIndent(&v, "", " ");
assert_eq!(err, nil);
let s = String::from_utf8(data).unwrap();
assert!(s.contains('\n'));
assert!(s.contains(" \"x\""));
}
#[test]
fn valid_detects_good_and_bad() {
assert!(Valid(br#"{"a":1}"#));
assert!(!Valid(b"not json"));
}
#[test]
fn round_trip_nested() {
let original = Value::Object(vec![
("outer".into(), Value::Object(vec![
("inner".into(), Value::Array(vec![
Value::Number(1.0), Value::Number(2.0), Value::Number(3.0)
])),
])),
]);
let (data, _) = Marshal(&original);
let mut decoded = Value::Null;
Unmarshal(&data, &mut decoded);
assert_eq!(decoded.Get("outer").Get("inner").Len(), 3);
assert_eq!(decoded.Get("outer").Get("inner").Index(2).Int(), 3);
}
#[test]
fn null_defaults() {
let v: Value = Value::Null;
assert_eq!(v.String(), "");
assert_eq!(v.Int(), 0);
assert_eq!(v.Bool(), false);
}
}