Skip to main content

nodedb_types/value/
float_text.rs

1// SPDX-License-Identifier: Apache-2.0
2
3//! PostgreSQL text and JSON forms of a float, including the non-finite
4//! values JSON numbers cannot hold.
5//!
6//! PostgreSQL renders a non-finite float as `NaN`, `Infinity` or
7//! `-Infinity`, and `to_json` renders it as that text in a JSON string.
8//! A JSON number cannot hold these values, and `serde_json` turns them into
9//! `null`. Every path that renders a float to text or JSON calls these
10//! functions instead.
11
12/// The PostgreSQL text of a non-finite float: `NaN`, `Infinity` or
13/// `-Infinity`. `None` for a finite float.
14pub fn non_finite_float_text(f: f64) -> Option<&'static str> {
15    (!f.is_finite()).then(|| non_finite_text(f))
16}
17
18/// A float as a JSON value. A finite float is a JSON number. A non-finite
19/// float is its PostgreSQL text in a JSON string, as `to_json` renders it.
20pub fn float_to_json(f: f64) -> serde_json::Value {
21    match serde_json::Number::from_f64(f) {
22        Some(n) => serde_json::Value::Number(n),
23        // `from_f64` refuses exactly the non-finite floats.
24        None => serde_json::Value::String(non_finite_text(f).to_owned()),
25    }
26}
27
28/// The PostgreSQL text of a float the caller knows is non-finite.
29fn non_finite_text(f: f64) -> &'static str {
30    if f.is_nan() {
31        "NaN"
32    } else if f > 0.0 {
33        "Infinity"
34    } else {
35        "-Infinity"
36    }
37}
38
39#[cfg(test)]
40mod tests {
41    use super::*;
42
43    #[test]
44    fn non_finite_floats_render_postgres_text() {
45        assert_eq!(non_finite_float_text(f64::NAN), Some("NaN"));
46        assert_eq!(non_finite_float_text(f64::INFINITY), Some("Infinity"));
47        assert_eq!(non_finite_float_text(f64::NEG_INFINITY), Some("-Infinity"));
48        assert_eq!(non_finite_float_text(1.5), None);
49        assert_eq!(non_finite_float_text(f64::MAX), None);
50    }
51
52    #[test]
53    fn non_finite_floats_are_json_strings() {
54        assert_eq!(float_to_json(f64::NAN), serde_json::json!("NaN"));
55        assert_eq!(float_to_json(f64::INFINITY), serde_json::json!("Infinity"));
56        assert_eq!(
57            float_to_json(f64::NEG_INFINITY),
58            serde_json::json!("-Infinity")
59        );
60        assert_eq!(float_to_json(2.5), serde_json::json!(2.5));
61    }
62}