Skip to content

enhancement(codecs): Support protobuf encoding integers as floats #19527

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

Open
wants to merge 1 commit into
base: master
Choose a base branch
from

Conversation

goakley
Copy link
Contributor

@goakley goakley commented Jan 5, 2024

Rust's conversion functionality allows converting i64 to f32 and f64 with high precision for all possible i64 values. We can leverage this convenience to avoid users having to remap types using VRL.

…oubles

Rust's conversion functionality allows converting i64 to f32 and f64 with high precision for all possible i64 values.
We can leverage this convenience for protobuf encoding.
@jszwedko jszwedko requested a review from pront January 5, 2024 18:48
@@ -96,6 +96,8 @@ fn convert_value_raw(
}
(Value::Float(f), Kind::Double) => Ok(prost_reflect::Value::F64(f.into_inner())),
(Value::Float(f), Kind::Float) => Ok(prost_reflect::Value::F32(f.into_inner() as f32)),
(Value::Integer(i), Kind::Double) => Ok(prost_reflect::Value::F64(i as f64)),
(Value::Integer(i), Kind::Float) => Ok(prost_reflect::Value::F32(i as f32)),
Copy link
Member

Choose a reason for hiding this comment

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

Even it's a "high precision conversion", the farther you get from 0 the more problematic it becomes. I am not fully convinced we want to introduce this. Is the motivation to avoid using a remap transform? (that might also have problems with very large integers)

Perhaps if we document very clearly the caveats especially when it comes to large i64 we can justify introducing this for convenience. Users who know their data can leverage it.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@pront could you clarify "the farther you get from 0 the more problematic it becomes"? I added tests in this PR specifically to see if that was the case.

The motivation is to avoid using a remap to transform, particularly when the conversion to integer is the result of another parser and not a remap itself, e.g. the JSON parser deciding that the number it parsed is an integer instead of a float.

Copy link
Member

Choose a reason for hiding this comment

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

I see now, this use case makes sense.

Copy link
Member

Choose a reason for hiding this comment

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

The problem is that integer values larger than the number of mantissa bits will have the low-order bits cleared.

Copy link
Member

Choose a reason for hiding this comment

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

The problem is that integer values larger than the number of mantissa bits will have the low-order bits cleared.

This is what I was referring to as problematic. These conversions are lossy and that would need to be documented. VRL also performs lossy conversions, see here.

let message = encode_message(
&test_message_descriptor("Floats"),
Value::Object(BTreeMap::from([
("d".into(), Value::Integer(9223372036854775807)),
Copy link
Member

@pront pront Jan 9, 2024

Choose a reason for hiding this comment

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

Is the intention here to use i64::MAX? If yes, please replace.

@pront
Copy link
Member

pront commented Jan 9, 2024

There are a few failing checks. I also left one new comment.

])),
)
.unwrap();
assert_eq!(Some(9.223372036854775807e18), mfield!(message, "d").as_f64());
Copy link
Member

@bruceg bruceg Jan 9, 2024

Choose a reason for hiding this comment

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

Unfortunately, this doesn't actually test what it appears to: 9.223372036854775807e18 (AKA 9223372036854775807.0) silently converts to 9.223372036854776e+18 which its internal representation. Run this Rust Playground to demonstrate.

)
.unwrap();
assert_eq!(Some(9.223372036854775807e18), mfield!(message, "d").as_f64());
assert_eq!(Some(9.223372036854775807e18), mfield!(message, "f").as_f32());
Copy link
Member

Choose a reason for hiding this comment

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

Similarly, this silently converts to 9.223372e18 internally.

@@ -96,6 +96,8 @@ fn convert_value_raw(
}
(Value::Float(f), Kind::Double) => Ok(prost_reflect::Value::F64(f.into_inner())),
(Value::Float(f), Kind::Float) => Ok(prost_reflect::Value::F32(f.into_inner() as f32)),
(Value::Integer(i), Kind::Double) => Ok(prost_reflect::Value::F64(i as f64)),
(Value::Integer(i), Kind::Float) => Ok(prost_reflect::Value::F32(i as f32)),
Copy link
Member

Choose a reason for hiding this comment

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

The problem is that integer values larger than the number of mantissa bits will have the low-order bits cleared.

@jszwedko jszwedko requested a review from a team as a code owner October 3, 2024 18:54
@thomasqueirozb thomasqueirozb added the meta: awaiting author Pull requests that are awaiting their author. label Jul 9, 2025
@pront pront force-pushed the master branch 4 times, most recently from 1720078 to ffe54be Compare July 10, 2025 15:43
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
meta: awaiting author Pull requests that are awaiting their author.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants