Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

implement i64/u64 using BigInt #21

Closed
osiewers opened this issue Sep 28, 2021 · 8 comments
Closed

implement i64/u64 using BigInt #21

osiewers opened this issue Sep 28, 2021 · 8 comments

Comments

@osiewers
Copy link

I tried to implement this feature myself, but I literally am using rust for the first time today.

Serializing the data is simple, by now it's implemented in serde. Sadly I have no idea how to implement the corresponding deserialization of it. Don't want to create a halfhearted PR tho...

@RReverser
Copy link
Owner

BigInt used to be unsupported by wasm-bindgen itself, but searching among their issues, I found rustwasm/wasm-bindgen#2629 that finally implemented it recently.

Among other things, it's added BigInt bindings in js-sys: https://docs.rs/js-sys/0.3.55/js_sys/struct.BigInt.html

Those bindings have conversions from u64/i64 which you can use for deserialization: https://docs.rs/js-sys/0.3.55/js_sys/struct.BigInt.html#impl-From%3Ci64%3E

I'm actually not sure how to do serialization yet - I don't see relevant APIs - but if you already figured out how to implement it as well, that's great.

PR would be welcome (and welcome to Rust! 😀).

@RReverser
Copy link
Owner

Implemented in #24.

@gRoussac
Copy link

gRoussac commented Aug 8, 2023

Hi @RReverser,

Refering to rustwasm/wasm-bindgen#2350 so as I a have an issue with u64 may I ask

this works well using serde-wasm-bindgen = "0.5.0"

        log(&format!(
            "test {:?}",
            serde_wasm_bindgen::to_value(&rand::thread_rng().gen::<u64>().to_string())
        ));

prints

test Ok(JsValue("341827912451372972"))

and this too

        log(&format!(
            "test {:?}",
            serde_wasm_bindgen::to_value(&rand::thread_rng().gen::<f64>())
        ));

however this prints
test Err(Error(JsValue(Error: 328383884975377644 can't be represented as a JavaScript number Error: 328383884975377644 can't be represented as a JavaScript number

        log(&format!(
            "test {:?}",
            serde_wasm_bindgen::to_value(&rand::thread_rng().gen::<u64>())
        ));

what do I miss here please ? as both wasm-bindgen and serde-wasm-bindgen are supporting u64 to BigInt.

Thanks

@RReverser
Copy link
Owner

RReverser commented Aug 8, 2023

@gRoussac See serde-wasm-bindgen docs, in particular:

Serializer configuration options

[...]
.serialize_large_number_types_as_bigints(true): Serialize u64, i64, usize and isize to bigints instead of attempting to fit them into the safe integer number or failing.

It's not enabled by default because historically a lot of people expect i64/u64 to be fallibly converted to number (which is compatible with JSON as long as number is in 2^53 range) 🤷🏼‍♂️

@gRoussac
Copy link

gRoussac commented Aug 8, 2023

@RReverser thank you my eyes did not pass the conversion table, I missed what was below, rtfm fatigue.

So for the curious

from

let json = serde_wasm_bindgen::to_value(&data);

to

let serializer = Serializer::new().serialize_large_number_types_as_bigints(true);
let json = data.serialize(&serializer);

and now I also understand why maps were not objects too =)

thank you very much

@RReverser
Copy link
Owner

RReverser commented Aug 8, 2023

and now I also understand why maps were not objects too =)

At that point the variable also shouldn't be called JSON to avoid confusion :) (as BigInt is not a valid JSON value)

@gRoussac
Copy link

gRoussac commented Aug 8, 2023

Yes indeed as far as I understand it is still a JsValue but does not stringify as JSON on javascript side, the "json" var in my use case is actually a complex struct where the u64 is nested into.

Now actually I am wondering if I use the correct approach as the doc says that if you don't need Maps/Sets etc then

#[wasm_bindgen]
pub fn send_example_to_js() -> JsValue {
    let mut field1 = HashMap::new();
    field1.insert(0, String::from("ex"));
    let example = Example {
        field1,
        field2: vec![vec![1., 2.], vec![3., 4.]],
        field3: [1., 2., 3., 4.]
    };

    serde_wasm_bindgen::to_value(&example).unwrap()
}

and

#[wasm_bindgen]
pub fn send_example_to_js() -> JsValue {
    let mut field1 = HashMap::new();
    field1.insert(0, String::from("ex"));
    let example = Example {
        field1,
        field2: vec![vec![1., 2.], vec![3., 4.]],
        field3: [1., 2., 3., 4.]
    };

    JsValue::from_serde(&example).unwrap()
}

are approx equivalent but last is JSON directly so I need to test now in my use case.

Thanks again for your help.

@RReverser
Copy link
Owner

directly

Well "directly" means it uses serde-json on Rust side to serialize to JSON, and then JS parses that string back. It might be sometimes faster and sometimes not, but at least in terms of size it tends to add more overhead. Measuring on your own app is the only way to know for sure.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants