diff --git a/crates/javy/src/serde/ser.rs b/crates/javy/src/serde/ser.rs index ba78cece..3b6e06fb 100644 --- a/crates/javy/src/serde/ser.rs +++ b/crates/javy/src/serde/ser.rs @@ -1,7 +1,4 @@ -use crate::quickjs::{ - qjs::{JS_DefinePropertyValue, JS_ValueToAtom, JS_PROP_C_W_E}, - Array, Ctx, Object, String as JSString, Value, -}; +use crate::quickjs::{object::Property, Array, Ctx, Object, String as JSString, Value}; use crate::serde::err::{Error, Result}; use anyhow::anyhow; @@ -340,29 +337,16 @@ impl<'a> ser::SerializeMap for &'a mut Serializer<'_> { { let mut map_serializer = Serializer::from_context(self.context.clone())?; value.serialize(&mut map_serializer)?; - let atom = unsafe { JS_ValueToAtom(self.context.as_raw().as_ptr(), self.key.as_raw()) }; - if let Some(o) = self.value.as_object() { - // Use `JS_DefinePropertyValue` to keep the semantics of the object - // unchanged. - let result = unsafe { - JS_DefinePropertyValue( - self.context.as_raw().as_ptr(), - o.as_raw(), - atom, - map_serializer.value.as_raw(), - JS_PROP_C_W_E as i32, - ) - }; - - return if result != 0 { - Ok(()) - } else { - Err(Error::custom("Error while serializing object")) - }; + let prop = Property::from(map_serializer.value.clone()) + .writable() + .configurable() + .enumerable(); + o.prop::<_, _, _>(self.key.clone(), prop) + .map_err(|e| Error::custom(e.to_string())) + } else { + Err(Error::custom("Expected to be an object")) } - - Err(Error::custom("Expected to be an object")) } fn end(self) -> Result<()> { diff --git a/crates/javy/tests/misc.rs b/crates/javy/tests/misc.rs new file mode 100644 index 00000000..435a484b --- /dev/null +++ b/crates/javy/tests/misc.rs @@ -0,0 +1,21 @@ +use anyhow::Result; +use javy::{quickjs::context::EvalOptions, Config, Runtime}; + +#[cfg(feature = "json")] +#[test] +fn string_keys_and_ref_counting() -> Result<()> { + let mut config = Config::default(); + config.override_json_parse_and_stringify(true); + + let source = include_bytes!("string_keys_and_ref_counting.js"); + let rt = Runtime::new(config)?; + + rt.context().with(|this| { + let _: () = this + .eval_with_options(*source, EvalOptions::default()) + .inspect_err(|e| println!("{e}")) + .expect("source evaluation to succeed"); + }); + + Ok(()) +} diff --git a/crates/javy/tests/string_keys_and_ref_counting.js b/crates/javy/tests/string_keys_and_ref_counting.js new file mode 100644 index 00000000..80e9c946 --- /dev/null +++ b/crates/javy/tests/string_keys_and_ref_counting.js @@ -0,0 +1,8 @@ +const input = JSON.parse('{"elements":[{"id":"zza"},{"id":"zzb"},{"id":"zzc"},{"id":"zzd"},{"id":"zze"}]}'); + +const acc = {}; +input.elements.forEach(e => { + if (!acc[e.id]) { + acc[e.id] = 1; + } +});