serde-wasm-bindgen icon indicating copy to clipboard operation
serde-wasm-bindgen copied to clipboard

Enabling #[serde(default)]

Open halzy opened this issue 4 years ago • 8 comments

Added de-serialization from a js_sys::Map. This makes it easier to use data from the result of DurableObject::load().

Having #[serde(default)] enables a simple, yet effective data migration.

halzy avatar Jun 19 '21 14:06 halzy

This makes it easier to use data from the result of DurableObject::load().

I don't know what this is a reference to / what is DurableObject.

I agree serde(default) is useful and should work, but I don't feel comfortable mixing up dynamic types even further. Maps should be deserialized to maps, objects should be deserialized to structs. Is it possible to enable serde(default) without allowing arbitrary object -> map conversions?

RReverser avatar Jul 11 '21 15:07 RReverser

Apologies, but it's been 3 weeks since I put the PR and I had to re-read it.

Are you concerned about a JS Map being deserialized into a Rust Struct instead of a Rust HashMap? Arguably it's more correct for a JS Map to be deserialized into a Struct due to the JS Map's variable value types. https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map#objects_vs._maps

halzy avatar Jul 12 '21 17:07 halzy

Apologies, but it's been 3 weeks since I put the PR and I had to re-read it.

Yeah sorry looks like I accidentally unsubscribed from the repo.

Are you concerned about a JS Map being deserialized into a Rust Struct instead of a Rust HashMap?

Yes.

Arguably it's more correct for a JS Map to be deserialized into a Struct due to the JS Map's variable value types.

I disagree, Map is still closer to HashMap / BTreeMap / etc. due to dynamic nature of keys themselves. Any non-string keys can't be deserialized into non-string-keyed Maps, so semantically map-to-map is a more correct conversion.

If someone wants to use dynamic values in JS Map and deserialize those to Rust, they can do so by either using enums as a value, or a struct with custom Deserialize implementation. If someone really wants to deserialize Map to a struct, they can do so via deserialize_with (once that's fixed).

I just don't want a built-in conversion to mix types even further - at least some level of type checking is useful.

RReverser avatar Jul 12 '21 17:07 RReverser

Any non-string keys can't be deserialized into non-string-keyed Maps, so semantically map-to-map is a more correct conversion.

Thank you for the explanation.

I'm in a situation where I save a JS Object via DurableObject::put() and later can retrieve it via DurableObject::list() as a Promise<Map<string, any>>. I'm trying to keep the WASM size small and avoid HashMaps altogether.

Having a custom deserializer for each struct that comes out of the DurableObject seems a bit much. Is there another option?

halzy avatar Jul 12 '21 18:07 halzy

I think the fundamental difference is that I think any JS iterable should be able to be deserialized into a Rust struct.

halzy avatar Jul 12 '21 18:07 halzy

Is there another option?

You can get result of durableObject.list() and invoke Object.fromEntries(...) on it - either on JS side or via wasm-bindgen - before passing to serde-wasm-bindgen. This can be done generically regardless of specific object type.

RReverser avatar Jul 12 '21 19:07 RReverser

Removing this section will prevent the Map deserializing into an Object. Is there anything else needed for the PR?

halzy avatar Jul 12 '21 21:07 halzy

It's hard to tell without seeing the whole / final diff. Please update the PR and I'll review as soon as I can.

RReverser avatar Jul 12 '21 23:07 RReverser

Fixed, including the mentioned concerns, in an alternative implementation in https://github.com/cloudflare/serde-wasm-bindgen/commit/bf15072c58ec1a8228e8afc1dbab41b6818fc49b.

RReverser avatar Aug 30 '22 10:08 RReverser