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

Create floats feature to remove float operations #1

Open
wants to merge 6 commits into
base: master
Choose a base branch
from

Conversation

webmaster128
Copy link
Owner

Updated version of Maksym's work from nearprotocol#1

Kudos, Max!

Updated version of Maksym's work from
nearprotocol#1

Kudos!
Copy link

@ethanfrey ethanfrey left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm digging in a bit to try to figure out where this float issue could be caused by.
Do you have a simple test case to see if there is float output (eg. sample code to compile to wasm and wasm2wat + grep script to check it)? I can try some changes and see if they hit anything.

@@ -458,7 +465,9 @@ impl<'de, R: Read<'de>> Deserializer<R> {

fn parse_number(&mut self, positive: bool, significand: u64) -> Result<ParserNumber> {
Ok(match tri!(self.peek_or_null()) {
#[cfg(feature = "floats")]

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't we want to immediately error on these two cases if cfg(not(feature = "floats"))?
It may make sense to just provide two implementations for parse_number (with and without floats)

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Right. At the moment those cases fall into the fallback implementation which is made for digits only, which cuts the number at the . or e.

@ethanfrey
Copy link

One difference I notice from my fork from serde-json-core is that there are f64 arguments involved here, even if ignored. In number.rs:

            #[inline]
            #[cfg(feature = "floats")]
            fn visit_f64<E>(self, value: f64) -> Result<Number, E>
            where
                E: de::Error,
            {
                Number::from_f64(value).ok_or_else(|| de::Error::custom("not a JSON number"))
            }

            #[inline]
            #[cfg(not(feature = "floats"))]
            fn visit_f64<E>(self, _value: f64) -> Result<Number, E>
            where
                E: de::Error,
            {
                unreachable!();
            }

However, in my fork of serde-json-core, the visit_f64 method doesn't even exist:

    fn deserialize_f64<V>(self, _visitor: V) -> Result<V::Value, Self::Error>
    where
        V: Visitor<'de>,
    {
        unreachable!()
    }

Basically, the float-free code is marking f64 as unreachable in the Deserializer, while your current fork marks it as unreachable in the Visitor. This means at some point this may interpret a f64 in the code?

I do see the Deserializer also marks it as un-implemented.

    #[cfg(feature = "floats")]
    deserialize_number!(deserialize_f64 => visit_f64);
    #[cfg(not(feature = "floats"))]
    fn deserialize_f64<V: de::Visitor<'de>>(self, _: V) -> Result<V::Value, Error> {
        unimplemented!()
    }

@ethanfrey
Copy link

Thinking a bit more, this seems to have to do with Display, and the biggest Display use is Error.

This line might be causing the issue (by calling Display implementations from other code):

ErrorCode::Io(ref err) => Display::fmt(err, f),

Try replacing with a constant string to test (thus no code path calls into the Error::Display implementation of some random IoError we don't control). Maybe this helps 🙏

@webmaster128
Copy link
Owner Author

This means at some point this may interpret a f64 in the code?

The Visitor trait has a default implementation that is alomst the same as the one in here:

    /// The input contains an `f32`.
    ///
    /// The default implementation forwards to [`visit_f64`].
    ///
    /// [`visit_f64`]: #method.visit_f64
    fn visit_f32<E>(self, v: f32) -> Result<Self::Value, E>
    where
        E: Error,
    {
        self.visit_f64(v as f64)
    }

    /// The input contains an `f64`.
    ///
    /// The default implementation fails with a type error.
    fn visit_f64<E>(self, v: f64) -> Result<Self::Value, E>
    where
        E: Error,
    {
        Err(Error::invalid_type(Unexpected::Float(v), &self))
    }

I think the main difference is, that serde-json-wasm (mind the separators) does not implement a custom Visitor trait at all.

@webmaster128
Copy link
Owner Author

This line might be causing the issue (by calling Display implementations from other code):

I just tried this one but it was not sufficient.

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

Successfully merging this pull request may close these issues.

2 participants