Skip to content

Commit 1841505

Browse files
authored
chore(core): Value unification part 1 - NotNan floats (#11291)
1 parent 9e82026 commit 1841505

File tree

28 files changed

+342
-137
lines changed

28 files changed

+342
-137
lines changed

Cargo.lock

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

lib/vector-common/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ chrono = { version = "0.4", optional = true }
4747
derivative = "2.1.3"
4848
metrics = { version = "0.17.0", default-features = false, features = ["std"] }
4949
nom = { version = "7", optional = true }
50+
ordered-float = { version = "2.10.0", default-features = false }
5051
serde_json = { version = "1.0.78", default-features = false, features = ["std", "raw_value"] }
5152
serde = { version = "1.0.136", optional = true, features = ["derive"] }
5253
smallvec = { version = "1", default-features = false }

lib/vector-common/src/conversion.rs

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ use std::{
66

77
use bytes::Bytes;
88
use chrono::{DateTime, ParseError as ChronoParseError, TimeZone as _, Utc};
9+
use ordered_float::NotNan;
910
use snafu::{ResultExt, Snafu};
1011

1112
use super::datetime::{datetime_to_utc, TimeZone};
@@ -40,6 +41,8 @@ pub enum Error {
4041
BoolParse { s: String },
4142
#[snafu(display("Invalid integer {:?}: {}", s, source))]
4243
IntParse { s: String, source: ParseIntError },
44+
#[snafu(display("NaN number not supported {:?}", s))]
45+
NanFloat { s: String },
4346
#[snafu(display("Invalid floating point number {:?}: {}", s, source))]
4447
FloatParse { s: String, source: ParseFloatError },
4548
#[snafu(
@@ -140,7 +143,7 @@ impl Conversion {
140143
/// Returns errors from the underlying conversion functions. See `enum Error`.
141144
pub fn convert<T>(&self, bytes: Bytes) -> Result<T, Error>
142145
where
143-
T: From<Bytes> + From<i64> + From<f64> + From<bool> + From<DateTime<Utc>>,
146+
T: From<Bytes> + From<i64> + From<NotNan<f64>> + From<bool> + From<DateTime<Utc>>,
144147
{
145148
Ok(match self {
146149
Self::Bytes => bytes.into(),
@@ -152,9 +155,11 @@ impl Conversion {
152155
}
153156
Self::Float => {
154157
let s = String::from_utf8_lossy(&bytes);
155-
s.parse::<f64>()
156-
.with_context(|_| FloatParseSnafu { s })?
157-
.into()
158+
let parsed = s
159+
.parse::<f64>()
160+
.with_context(|_| FloatParseSnafu { s: s.clone() })?;
161+
let f = NotNan::new(parsed).map_err(|_| Error::NanFloat { s: s.to_string() })?;
162+
f.into()
158163
}
159164
Self::Boolean => parse_bool(&String::from_utf8_lossy(&bytes))?.into(),
160165
Self::Timestamp(tz) => parse_timestamp(*tz, &String::from_utf8_lossy(&bytes))?.into(),

lib/vector-common/src/conversion/tests/mod.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
use bytes::Bytes;
22
use chrono::{DateTime, Utc};
3+
use ordered_float::NotNan;
34

45
use crate::conversion::parse_bool;
56

@@ -33,6 +34,12 @@ impl From<f64> for StubValue {
3334
}
3435
}
3536

37+
impl From<NotNan<f64>> for StubValue {
38+
fn from(v: NotNan<f64>) -> Self {
39+
StubValue::Float(v.into_inner())
40+
}
41+
}
42+
3643
impl From<i64> for StubValue {
3744
fn from(v: i64) -> Self {
3845
StubValue::Integer(v)

lib/vector-common/src/conversion/tests/unix.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
use bytes::Bytes;
22
use chrono::{DateTime, NaiveDateTime, TimeZone as _, Utc};
33
use chrono_tz::{Australia, Tz};
4+
use ordered_float::NotNan;
45

56
use crate::{
67
conversion::{parse_timestamp, tests::StubValue, Conversion, Error},
@@ -56,7 +57,7 @@ fn dateref() -> DateTime<Utc> {
5657

5758
fn convert<T>(fmt: &str, value: &'static str) -> Result<T, Error>
5859
where
59-
T: From<Bytes> + From<i64> + From<f64> + From<bool> + From<DateTime<Utc>>,
60+
T: From<Bytes> + From<i64> + From<NotNan<f64>> + From<bool> + From<DateTime<Utc>>,
6061
{
6162
std::env::set_var("TZ", TIMEZONE_NAME);
6263
Conversion::parse(fmt, TimeZone::Local)

lib/vector-core/src/event/discriminant.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ fn value_eq(this: &Value, other: &Value) -> bool {
5858
(Value::Timestamp(this), Value::Timestamp(other)) => this.eq(other),
5959
(Value::Null, Value::Null) => true,
6060
// Non-trivial.
61-
(Value::Float(this), Value::Float(other)) => f64_eq(*this, *other),
61+
(Value::Float(this), Value::Float(other)) => f64_eq(this.into_inner(), other.into_inner()),
6262
(Value::Array(this), Value::Array(other)) => array_eq(this, other),
6363
(Value::Map(this), Value::Map(other)) => map_eq(this, other),
6464
// Type mismatch.
@@ -125,7 +125,7 @@ fn hash_value<H: Hasher>(hasher: &mut H, value: &Value) {
125125
Value::Integer(val) => val.hash(hasher),
126126
Value::Timestamp(val) => val.hash(hasher),
127127
// Non-trivial.
128-
Value::Float(val) => hash_f64(hasher, *val),
128+
Value::Float(val) => hash_f64(hasher, val.into_inner()),
129129
Value::Array(val) => hash_array(hasher, val),
130130
Value::Map(val) => hash_map(hasher, val),
131131
Value::Null => hash_null(hasher),

lib/vector-core/src/event/legacy_lookup/mod.rs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ use std::{
1313
};
1414

1515
use indexmap::map::IndexMap;
16+
use ordered_float::NotNan;
1617
use pest::{iterators::Pair, Parser};
1718
pub use segment::Segment;
1819
use serde::{
@@ -118,7 +119,10 @@ impl Lookup {
118119
match value {
119120
TomlValue::String(s) => discoveries.insert(lookup, Value::from(s)),
120121
TomlValue::Integer(i) => discoveries.insert(lookup, Value::from(i)),
121-
TomlValue::Float(f) => discoveries.insert(lookup, Value::from(f)),
122+
TomlValue::Float(f) => {
123+
let value = NotNan::new(f).map_err(|_| "NaN value not supported")?;
124+
discoveries.insert(lookup, Value::Float(value))
125+
}
122126
TomlValue::Boolean(b) => discoveries.insert(lookup, Value::from(b)),
123127
TomlValue::Datetime(dt) => {
124128
let dt = dt.to_string();

lib/vector-core/src/event/lua/value.rs

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
use mlua::prelude::*;
2+
use ordered_float::NotNan;
23

34
use super::util::{table_is_timestamp, table_to_timestamp, timestamp_to_table};
45
use crate::event::Value;
@@ -9,7 +10,7 @@ impl<'a> ToLua<'a> for Value {
910
match self {
1011
Value::Bytes(b) => lua.create_string(b.as_ref()).map(LuaValue::String),
1112
Value::Integer(i) => Ok(LuaValue::Integer(i)),
12-
Value::Float(f) => Ok(LuaValue::Number(f)),
13+
Value::Float(f) => Ok(LuaValue::Number(f.into_inner())),
1314
Value::Boolean(b) => Ok(LuaValue::Boolean(b)),
1415
Value::Timestamp(t) => timestamp_to_table(lua, t).map(LuaValue::Table),
1516
Value::Map(m) => lua.create_table_from(m.into_iter()).map(LuaValue::Table),
@@ -24,7 +25,14 @@ impl<'a> FromLua<'a> for Value {
2425
match value {
2526
LuaValue::String(s) => Ok(Value::Bytes(Vec::from(s.as_bytes()).into())),
2627
LuaValue::Integer(i) => Ok(Value::Integer(i)),
27-
LuaValue::Number(f) => Ok(Value::Float(f)),
28+
LuaValue::Number(f) => {
29+
let f = NotNan::new(f).map_err(|_| mlua::Error::FromLuaConversionError {
30+
from: value.type_name(),
31+
to: "Value",
32+
message: Some("NaN not supported".to_string()),
33+
})?;
34+
Ok(Value::Float(f))
35+
}
2836
LuaValue::Boolean(b) => Ok(Value::Boolean(b)),
2937
LuaValue::Table(t) => {
3038
if t.len()? > 0 {
@@ -58,13 +66,13 @@ mod test {
5866
Value::Bytes("\u{237a}\u{3b2}\u{3b3}".into()),
5967
),
6068
("123", Value::Integer(123)),
61-
("4.333", Value::Float(4.333)),
69+
("4.333", Value::from(4.333)),
6270
("true", Value::Boolean(true)),
6371
(
6472
"{ x = 1, y = '2', nested = { other = 5.678 } }",
6573
Value::Map(
6674
vec![
67-
("x".into(), 1.into()),
75+
("x".into(), 1_i64.into()),
6876
("y".into(), "2".into()),
6977
(
7078
"nested".into(),
@@ -77,7 +85,7 @@ mod test {
7785
),
7886
(
7987
"{1, '2', 0.57721566}",
80-
Value::Array(vec![1.into(), "2".into(), 0.577_215_66.into()]),
88+
Value::Array(vec![1_i64.into(), "2".into(), 0.577_215_66.into()]),
8189
),
8290
(
8391
"os.date('!*t', 1584297428)",
@@ -122,7 +130,7 @@ mod test {
122130
"#,
123131
),
124132
(
125-
Value::Float(4.333),
133+
Value::from(4.333),
126134
r#"
127135
function (value)
128136
return value == 4.333
@@ -140,7 +148,7 @@ mod test {
140148
(
141149
Value::Map(
142150
vec![
143-
("x".into(), 1.into()),
151+
("x".into(), 1_i64.into()),
144152
("y".into(), "2".into()),
145153
(
146154
"nested".into(),
@@ -159,7 +167,7 @@ mod test {
159167
"#,
160168
),
161169
(
162-
Value::Array(vec![1.into(), "2".into(), 0.577_215_66.into()]),
170+
Value::Array(vec![1_i64.into(), "2".into(), 0.577_215_66.into()]),
163171
r#"
164172
function (value)
165173
return value[1] == 1 and

lib/vector-core/src/event/proto.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
use chrono::TimeZone;
2+
use ordered_float::NotNan;
23

34
use crate::{
45
event::{self, BTreeMap, WithMetadata},
@@ -325,7 +326,7 @@ fn decode_value(input: Value) -> Option<event::Value> {
325326
chrono::Utc.timestamp(ts.seconds, ts.nanos as u32),
326327
)),
327328
Some(value::Kind::Integer(value)) => Some(event::Value::Integer(value)),
328-
Some(value::Kind::Float(value)) => Some(event::Value::Float(value)),
329+
Some(value::Kind::Float(value)) => Some(event::Value::Float(NotNan::new(value).unwrap())),
329330
Some(value::Kind::Boolean(value)) => Some(event::Value::Boolean(value)),
330331
Some(value::Kind::Map(map)) => decode_map(map.fields),
331332
Some(value::Kind::Array(array)) => decode_array(array.items),
@@ -370,7 +371,7 @@ fn encode_value(value: event::Value) -> Value {
370371
nanos: ts.timestamp_subsec_nanos() as i32,
371372
})),
372373
event::Value::Integer(value) => Some(value::Kind::Integer(value)),
373-
event::Value::Float(value) => Some(value::Kind::Float(value)),
374+
event::Value::Float(value) => Some(value::Kind::Float(value.into_inner())),
374375
event::Value::Boolean(value) => Some(value::Kind::Boolean(value)),
375376
event::Value::Map(fields) => Some(value::Kind::Map(encode_map(fields))),
376377
event::Value::Array(items) => Some(value::Kind::Array(encode_array(items))),

lib/vector-core/src/event/test/common.rs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -562,7 +562,13 @@ impl Arbitrary for Value {
562562
Value::Bytes(Bytes::from(bytes))
563563
}
564564
1 => Value::Integer(i64::arbitrary(g)),
565-
2 => Value::Float(f64::arbitrary(g) % MAX_F64_SIZE),
565+
2 => {
566+
let mut f = f64::arbitrary(g) % MAX_F64_SIZE;
567+
if f.is_nan() {
568+
f = 0.0;
569+
}
570+
Value::from(f)
571+
}
566572
3 => Value::Boolean(bool::arbitrary(g)),
567573
4 => Value::Timestamp(datetime(g)),
568574
5 => {

0 commit comments

Comments
 (0)