Skip to main content

mruby_serde_json/json_value/
mod.rs

1use std::cell::RefCell;
2use std::rc::Rc;
3
4use mrubyedge::Error;
5use mrubyedge::yamrb::helpers::mrb_funcall;
6use mrubyedge::yamrb::value::RObject;
7use mrubyedge::yamrb::value::RValue;
8use mrubyedge::yamrb::vm::VM;
9use serde::ser::{Serialize, SerializeMap, SerializeSeq, Serializer};
10use serde_json::Value;
11
12pub struct Json<'a> {
13    mrb: Rc<RefCell<&'a mut VM>>,
14    inner: Rc<RObject>,
15}
16
17impl<'a> Json<'a> {
18    pub fn get_inner(&self) -> Rc<RObject> {
19        self.inner.clone()
20    }
21
22    pub fn from_robject(mrb: Rc<RefCell<&'a mut VM>>, inner: Rc<RObject>) -> Self {
23        Self { mrb, inner }
24    }
25}
26
27impl<'a> From<Json<'a>> for Rc<RObject> {
28    fn from(value: Json<'a>) -> Self {
29        value.get_inner()
30    }
31}
32
33impl<'a> Serialize for Json<'a> {
34    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
35    where
36        S: Serializer,
37    {
38        match self.get_inner().value {
39            RValue::Nil => serializer.serialize_none(),
40            RValue::Bool(b) => serializer.serialize_bool(b),
41            RValue::Integer(i) => serializer.serialize_i64(i),
42            RValue::Float(f) => serializer.serialize_f64(f),
43            RValue::String(ref s, _) => {
44                serializer.serialize_str(&String::from_utf8_lossy(&s.borrow()))
45            }
46            RValue::Symbol(ref s) => serializer.serialize_str(&s.name),
47            RValue::Array(ref arr) => {
48                let arr = arr.borrow();
49                let mut seq = serializer.serialize_seq(Some(arr.len()))?;
50                for item in arr.iter() {
51                    let json_item = Json::from_robject(self.mrb.clone(), item.clone());
52                    seq.serialize_element(&json_item)?;
53                }
54                seq.end()
55            }
56            RValue::Hash(ref hash) => {
57                let hash = hash.borrow();
58                let mut map = serializer.serialize_map(Some(hash.len()))?;
59                for (_, (key, value)) in hash.iter() {
60                    let key_str = match key.value {
61                        RValue::String(ref s, _) => {
62                            String::from_utf8_lossy(&s.borrow()).to_string()
63                        }
64                        RValue::Symbol(ref s) => s.name.to_string(),
65                        _ => {
66                            return Err(serde::ser::Error::custom("Non-string key in JSON object"));
67                        }
68                    };
69                    let json_value = Json::from_robject(self.mrb.clone(), value.clone());
70                    map.serialize_entry(&key_str, &json_value)?;
71                }
72                map.end()
73            }
74            _ => {
75                let obj = self.get_inner();
76                let vm = &mut self.mrb.borrow_mut();
77                let serializable = mrb_funcall(vm, Some(obj), "to_json", &[]);
78                let json_obj = Json::from_robject(
79                    self.mrb.clone(),
80                    serializable.expect("to_json not defined for instance"),
81                );
82                json_obj.serialize(serializer)
83            }
84        }
85    }
86}
87
88pub(crate) fn mrb_json_dump(vm: &mut VM, obj: Rc<RObject>) -> Result<Rc<RObject>, Error> {
89    let vm = Rc::new(RefCell::new(vm));
90    let json_value = Json::from_robject(vm, obj);
91    let serialized =
92        serde_json::to_string(&json_value).expect("Failed to serialize JSON value to string");
93    Ok(RObject::string(serialized).to_refcount_assigned())
94}
95
96pub struct JsonValue {
97    inner: Rc<RObject>,
98}
99
100impl JsonValue {
101    pub fn new(inner: Rc<RObject>) -> Self {
102        Self { inner }
103    }
104
105    pub fn get_inner(&self) -> Rc<RObject> {
106        self.inner.clone()
107    }
108}
109
110impl From<JsonValue> for Rc<RObject> {
111    fn from(value: JsonValue) -> Self {
112        value.get_inner()
113    }
114}
115
116impl From<Value> for JsonValue {
117    fn from(value: Value) -> Self {
118        let obj = match value {
119            Value::Null => RObject::nil().to_refcount_assigned(),
120            Value::Bool(b) => RObject::boolean(b).to_refcount_assigned(),
121            Value::Number(n) => {
122                if let Some(i) = n.as_i64() {
123                    RObject::integer(i).to_refcount_assigned()
124                } else if let Some(u) = n.as_u64() {
125                    RObject::integer(u as i64).to_refcount_assigned()
126                } else if let Some(f) = n.as_f64() {
127                    RObject::float(f).to_refcount_assigned()
128                } else {
129                    panic!("Invalid range of numeric value");
130                }
131            }
132            Value::String(s) => RObject::string(s).to_refcount_assigned(),
133            Value::Array(arr) => {
134                let vec = arr.into_iter().map(JsonValue::from).collect::<Vec<_>>();
135                let arr = RObject::array(vec.into_iter().map(|j| j.get_inner()).collect());
136                arr.to_refcount_assigned()
137            }
138            Value::Object(obj) => {
139                let map = obj
140                    .into_iter()
141                    .map(|(k, v)| {
142                        let key = RObject::string(k).to_refcount_assigned();
143                        (
144                            key.as_hash_key().expect("object cannot use for hashed key"),
145                            (key.clone(), JsonValue::from(v).get_inner()),
146                        )
147                    })
148                    .collect();
149                let hash = RObject::hash(map);
150                hash.to_refcount_assigned()
151            }
152        };
153        JsonValue::new(obj)
154    }
155}
156
157pub(crate) fn mrb_json_load(_vm: &mut VM, json_str: impl Into<String>) -> Result<JsonValue, Error> {
158    let value = serde_json::from_str::<serde_json::Value>(&json_str.into())
159        .map_err(|e| Error::RuntimeError(format!("Failed to parse JSON string: {}", e)))?;
160    Ok(value.into())
161}