Comments (20)
Thinking about this a bit more, I suspect that such a feature would require additional functionality from both serde and wasm-bindgen sides to achieve this...
from serde-wasm-bindgen.
Yeah unfortunately that wouldn't be possible.
from serde-wasm-bindgen.
Hmm actually, while very hacky, it could be possible for serde-wasm-bindgen to provide some sort of serde_wasm_bindgen::PreservedValue(JsValue)
method (and, correspondingly, helper {de}serialize_with
functions).
PreservedValue
would need to ask the deserializer to deserialize a newtype with some internally-known unique name (like GUID), and on the serde-wasm-bindgen deserializer side it could recognize the name, and return the Abi
ID to the caller. Then, PreservedValue
would get this ID back and it would reconstruct the JsValue
via FromAbi
back.
This way, it could preserve JsValue
instances as-is while the rest around it would be deserialized.
Unfortunately, I'm pretty busy right now and won't be able to dig into this more, but if this makes sense to you, you're welcome to try in a PR :)
from serde-wasm-bindgen.
I completely agree, however, since I am also trying to start a business, I have to be pragmatic and unfortunately just work around these sorts of issues from time to time :)
from serde-wasm-bindgen.
@RReverser do you have any thoughts regarding workarounds that could achieve something like this, i.e., moving a Rust struct containing JsValues to Javascript?
from serde-wasm-bindgen.
I think instead of using Serde in this case you'd just have to implement conversion via manual methods, where you take a JsValue and step-by-step extract the properties you're interested in to a Rust struct or vice versa.
Of course, if the JsValue you want to preserve is a primitive JSON-like value, you can instead use serde_json::Value
or a similar container that can be used both in deserialization and serialization by any serde implementation, including serde-wasm-bindgen.
from serde-wasm-bindgen.
I think there is a limitation with that approach in that it will not work for types from web_sys such as OffscreenCanvas
or MessagePort
since these types are not representable in Rust.
from serde-wasm-bindgen.
If you mean the 2nd one, then yeah, as I said, it works only for primitive JSON-like values. For anything else you need to implement custom conversion methods.
from serde-wasm-bindgen.
That does sounds pretty hacky! While at a high level I follow what you are saying, I don't think I have quite enough experience with serde or wasm-bindgen at this stage to be able to put a PR together in a reasonable time frame. So unfortunately I think this idea will have to stay on the back burner for the moment.
from serde-wasm-bindgen.
While at a high level I follow what you are saying, I don't think I have quite enough experience with serde or wasm-bindgen at this stage to be able to put a PR together in a reasonable time frame.
In my experience, implementing this kind of hacks is the best and fun way to learn :) But, up to you, of course.
from serde-wasm-bindgen.
Instead of implementing Serialize
and Deserialize
for all JsValue
-like types, which requires to be implemented on the type itself (on wasm_bindgen
, js_sys
and web_sys
side), maybe a type JsTyped<T> where T: JsCast + AsRef<JsValue>
can be created?
So JsTyped<T>
has 3 attributes:
Serialize
is implemented with .as_ref()
.
Deserialize
is implemented with JsCast::dyn_into()
.
Deref<Target = T>
, AsRef<T>
and From<T>
provides ergonomics.
// can directly derive here because `JsTyped<Element>` is Serialize + Deserialize
#[derive(Serialize, Deserialize)]
struct SomeValueToPassToJs {
element: JsTyped<Element>,
}
from serde-wasm-bindgen.
So
JsTyped<T>
has 3 attributes:
Serialize
is implemented with.as_ref()
.Deserialize
is implemented withJsCast::dyn_into()
.
Problem is, you can't implement Serialize
/Deserialize
using those methods because they're generic over any serializers/deserializers, not just serde-wasm-bindgen, and follow a visitor pattern that doesn't know anything about JS values. https://serde.rs/impl-deserialize.html
Instead, you need something like described in #32 (comment) (messing up with internal handles).
from serde-wasm-bindgen.
Problem is, you can't implement Serialize/Deserialize using those methods because they're generic over any serializers/deserializers, not just serde-wasm-bindgen
The intuitive answer seems to be no, but actually there is a way to do it (if we are talking about hacks).
There're 2 quirks with JsValue (and anything contains JsValue):
- JsValue is not Send (hence serializer / deserializer are not Send)
- There cannot be 2 serializers / deserializers running at the same time in the same thread.
Hence, serializer and deserializer can be detected with thread-locals.
from serde-wasm-bindgen.
There cannot be 2 serializers / deserializers running at the same time in the same thread.
Why not? You can have nested serializers or deserializers.
Personally, I'd prefer to go with newtype + handles, those are safe in all scenarios.
from serde-wasm-bindgen.
#[derive(Debug, Serialize, Deserialize)]
#[wasm_bindgen]
pub struct CanFrame {
pub id: u32,
pub data: heapless::Vec<u8, 8>,
}
--> protocol/src/lib.rs:4:26
|
4 | use serde_wasm_bindgen::{from_value, to_value, Error, Serializer};
| ^^^^^^^^^^ ^^^^^^^^ ^^^^^ ^^^^^^^^^^
|
= note: `#[warn(unused_imports)]` on by default
error[E0277]: the trait bound `heapless::Vec<u8, 8_usize>: IntoWasmAbi` is not satisfied
--> protocol/src/lib.rs:55:1
|
55 | #[wasm_bindgen]
| ^^^^^^^^^^^^^^^ the trait `IntoWasmAbi` is not implemented for `heapless::Vec<u8, 8_usize>`
|
= help: the following other types implement trait `IntoWasmAbi`:
&'a (dyn Fn() -> R + 'b)
&'a (dyn Fn(A) -> R + 'b)
&'a (dyn Fn(A, B) -> R + 'b)
&'a (dyn Fn(A, B, C) -> R + 'b)
&'a (dyn Fn(A, B, C, D) -> R + 'b)
&'a (dyn Fn(A, B, C, D, E) -> R + 'b)
&'a (dyn Fn(A, B, C, D, E, F) -> R + 'b)
&'a (dyn Fn(A, B, C, D, E, F, G) -> R + 'b)
and 198 others
= note: this error originates in the attribute macro `wasm_bindgen` (in Nightly builds, run with -Z macro-backtrace for more info)
error[E0277]: the trait bound `heapless::Vec<u8, 8_usize>: FromWasmAbi` is not satisfied
--> protocol/src/lib.rs:55:1
|
55 | #[wasm_bindgen]
| ^^^^^^^^^^^^^^^ the trait `FromWasmAbi` is not implemented for `heapless::Vec<u8, 8_usize>`
|
= help: the following other types implement trait `FromWasmAbi`:
*const T
*mut T
CanFrame
Clamped<T>
FilterType
JsValue
_::_serde::__private::Vec<T>
bool
and 93 others
= note: this error originates in the attribute macro `wasm_bindgen` (in Nightly builds, run with -Z macro-backtrace for more info)
This isn't exactly related but maybe it'd be helpful if in the repo an example of how to implement this kind of trait was done so that a nested struct field could be easily serialized/deserialized to+from Rust->WASM?
from serde-wasm-bindgen.
@brandonros That's very much irrelevant to this issue, yes.
As your error says, the problem is that heapless::Vec<u8>
is not compatible with wasm-bindgen crates; but if you're using Serde Serialize/Deserialize, you don't need #[wasm_bindgen]
on your struct anyway.
If you remove it, that error should go away.
from serde-wasm-bindgen.
Since JsValue
is just an integer pointer, why not have JsTyped<T: JsCast>: JsCast + Deref<JsValue>
serialize to usize
. as when constructing the JsValue
, we can trivially cast back to the original type. For deserializing, much the same should happen.
This also takes advantage of the !Send + !Sync
assumption, and would make doing the unsafe casts sound.
from serde-wasm-bindgen.
The biggest issue with my suggestion, is that there's no way to know what serializer will be used, (with specialization we could), so if the user serialized to, for example, JSON, then deserializing would necessarily not work, so some trickery would need to happen to make this work in that case. But perhaps all of this could be mitigated with an explicit unsafe naming, such as UnsafeJsTyped<T>
where the docs specify the safety requirement to only use serde_wasm_bindgen
deserializer.
from serde-wasm-bindgen.
That was more or less my suggestion and see the open PR at #40 that basically does that. It needed a few minor final touches but fell off the radar I suspect.
from serde-wasm-bindgen.
Closed by #40.
from serde-wasm-bindgen.
Related Issues (20)
- ReferenceType integration? HOT 1
- WASM Reference Types HOT 2
- Add support for serializing `Closure`s HOT 1
- Internally tagged enumerations cannot deserialize byte buffers HOT 2
- `serde-wasm-bindgen` doesn't handle `serde(deny_unknown_fields)` properly HOT 3
- Error is not compatible with `Sync`/`Send`/`anyhow::Error` HOT 3
- as_bytes() does not work if self is an Array HOT 3
- Better interop between Tauri and serde-wasm-bindgen HOT 1
- Produce Object instead of Map when converting to JsValue HOT 2
- Hitting an unreachable! panic in serializing HOT 5
- Structures containing usize seems to create BigInt dependency in generated JavaScript bindings HOT 4
- json_compatible Deserializer HOT 1
- IntoWasmAbi HOT 3
- Preserved value de-serialization error HOT 8
- [improvement] Allow overriding default serializer used in to_value HOT 1
- `js_sys::Function` is not serialized correctly HOT 2
- Can't figure out how to get Option<js_sys::Date> to work when serializing to JS HOT 11
- #[serde(alias = "somename")] stopped working after 0.6 HOT 15
- More efficient serialization of struct HOT 1
- Decimal to JS with arbitrary precision HOT 2
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from serde-wasm-bindgen.