eon 0.2.0

Use the Eon config format with serde
Documentation
// Update snapshot tests by running:
//
// `cargo insta test --all-features --accept`

#![expect(
    clippy::approx_constant,
    clippy::excessive_precision,
    clippy::lossy_float_literal
)]

use std::str::FromStr as _;

use eon::Value;

#[track_caller]
fn test_roundtrip_value(value: impl Into<Value>) {
    let value = value.into();
    let formatted = value.format(&Default::default());
    let parsed = Value::from_str(&formatted).expect("Failed to parse formatted value");
    assert!(
        value == parsed,
        "Roundtrip failed for {value:?}, formatted as {formatted}, parsed as {parsed:?}"
    );
}

#[track_caller]
fn test_roundtrip_eon(eon: &str) {
    let value = Value::from_str(eon).expect("Failed to parse Eon value");
    let serialized = value.format(&Default::default());
    assert_eq!(eon, serialized, "Roundtrip failed. Value {value:?}");
}

#[track_caller]
fn test_serialize(value: impl Into<Value>, expected: &str) {
    let value = value.into();
    let formatted = value.format(&Default::default());
    assert_eq!(formatted, expected, "Serialization failed for: {value}");
}

#[track_caller]
fn test_f64(eon: &str, expected: f64) {
    let output = Value::from_str(eon)
        .expect("Failed to parse number")
        .as_number()
        .expect("Expected a number")
        .as_f64()
        .expect("Expected an f64");
    assert_eq!(output, expected, "Failed to parse f64: {eon} != {expected}");
}

#[track_caller]
fn test_i128(eon: &str, expected: i128) {
    let value = Value::from_str(eon).expect("Failed to parse number");
    let number = value
        .as_number()
        .expect("Expected a number")
        .as_i128()
        .expect("Expected an i128");
    assert_eq!(
        number, expected,
        "Expected {eon} to parse as {expected}, but got {value:?}"
    );
}

#[test]
fn test_numbers() {
    test_roundtrip_value(0.1);
    test_roundtrip_value(3.14);
    test_roundtrip_value(3.14000010490417);
    test_roundtrip_value(1234567890123456_i128);

    test_serialize(3.14, "3.14");
    test_serialize(3.14_f32, "3.14");
}

#[test]
fn test_roundtrip_string() {
    test_roundtrip_eon("42");
    test_roundtrip_eon("-42");
    test_roundtrip_eon("9223372036854775807");
    test_roundtrip_eon("-9223372036854775808");
    test_roundtrip_eon("0.0");
    test_roundtrip_eon("-0.0");
    test_roundtrip_eon("1.0");
    test_roundtrip_eon("-1.0");
    test_roundtrip_eon("5e-324");
    test_roundtrip_eon("2.225073858507201e-308");
    test_roundtrip_eon("2.2250738585072014e-308");
    test_roundtrip_eon("1.7976931348623157e308");
    test_roundtrip_eon("3.14");
}

#[test]
fn test_f64s() {
    // Tests from https://github.com/miloyip/nativejson-benchmark
    test_f64("0.0", 0.0);
    test_f64("-0.0", -0.0);
    test_f64("1.0", 1.0);
    test_f64("-1.0", -1.0);
    test_f64("1.5", 1.5);
    test_f64("-1.5", -1.5);
    test_f64("3.1416", 3.1416);
    test_f64("1E10", 1E10);
    test_f64("1e10", 1e10);
    test_f64("1E+10", 1E+10);
    test_f64("1E-10", 1E-10);
    test_f64("-1E10", -1E10);
    test_f64("-1e10", -1e10);
    test_f64("-1E+10", -1E+10);
    test_f64("-1E-10", -1E-10);
    test_f64("1.234E+10", 1.234E+10);
    test_f64("1.234E-10", 1.234E-10);
    test_f64("1.79769e+308", 1.79769e+308);
    test_f64("2.22507e-308", 2.22507e-308);
    test_f64("-1.79769e+308", -1.79769e+308);
    test_f64("-2.22507e-308", -2.22507e-308);
    test_f64("4.9406564584124654e-324", 4.9406564584124654e-324); // minimum denormal
    test_f64("2.2250738585072009e-308", 2.2250738585072009e-308); // Max subnormal f64
    test_f64("2.2250738585072014e-308", 2.2250738585072014e-308); // Min normal positive f64
    test_f64("1.7976931348623157e+308", 1.7976931348623157e+308); // Max f64
    test_f64("1e-10000", 0.0); // must underflow
    test_f64("18446744073709551616", 18446744073709551616.0); // 2^64 (max of uint64_t + 1, force to use f64)
    test_i128("-9223372036854775809", -9223372036854775809); // -2^63 - 1(min of int64_t + 1, force to use f64)
    test_f64("0.9868011474609375", 0.9868011474609375);
    test_f64("123e34", 123e34); // Fast Path Cases In Disguise
    test_f64("45913141877270640000.0", 45913141877270640000.0);
    test_f64("2.2250738585072011e-308", 2.2250738585072011e-308);
    test_f64("1e-00011111111111", 0.0);
    test_f64("-1e-00011111111111", -0.0);
    test_f64("1e-214748363", 0.0);
    test_f64("1e-214748364", 0.0);
    test_f64("1e-21474836311", 0.0);
    test_f64("0.017976931348623157e+310", 1.7976931348623157e+308); // Max f64 in another form

    // Since
    // abs((2^-1022 - 2^-1074) - 2.2250738585072012e-308) = 3.109754131239141401123495768877590405345064751974375599... ¡Á 10^-324
    // abs((2^-1022) - 2.2250738585072012e-308) = 1.830902327173324040642192159804623318305533274168872044... ¡Á 10 ^ -324
    // So 2.2250738585072012e-308 should round to 2^-1022 = 2.2250738585072014e-308
    test_f64("2.2250738585072012e-308", 2.2250738585072014e-308);

    // More closer to normal/subnormal boundary
    // boundary = 2^-1022 - 2^-1075 = 2.225073858507201136057409796709131975934819546351645648... ¡Á 10^-308
    test_f64(
        "2.22507385850720113605740979670913197593481954635164564e-308",
        2.2250738585072009e-308,
    );
    test_f64(
        "2.22507385850720113605740979670913197593481954635164565e-308",
        2.2250738585072014e-308,
    );

    // 1.0 is in (1.0 - 2^-54, 1.0 + 2^-53)
    // 1.0 - 2^-54 = 0.999999999999999944488848768742172978818416595458984375
    test_f64(
        "0.999999999999999944488848768742172978818416595458984375",
        1.0,
    ); // round to even
    test_f64(
        "0.999999999999999944488848768742172978818416595458984374",
        0.99999999999999989,
    ); // previous f64
    test_f64(
        "0.999999999999999944488848768742172978818416595458984376",
        1.0,
    ); // next f64
    // 1.0 + 2^-53 = 1.00000000000000011102230246251565404236316680908203125
    test_f64(
        "1.00000000000000011102230246251565404236316680908203125",
        1.0,
    ); // round to even
    test_f64(
        "1.00000000000000011102230246251565404236316680908203124",
        1.0,
    ); // previous f64
    test_f64(
        "1.00000000000000011102230246251565404236316680908203126",
        1.00000000000000022,
    ); // next f64

    // Numbers from https://github.com/floitsch/double-conversion/blob/master/test/cctest/test-strtod.cc

    test_f64("72057594037927928.0", 72057594037927928.0);
    test_f64("72057594037927936.0", 72057594037927936.0);
    test_f64("72057594037927932.0", 72057594037927936.0);
    test_f64("7205759403792793199999e-5", 72057594037927928.0);
    test_f64("7205759403792793200001e-5", 72057594037927936.0);

    test_f64("9223372036854774784.0", 9223372036854774784.0);
    test_f64("9223372036854775808.0", 9223372036854775808.0);
    test_f64("9223372036854775296.0", 9223372036854775808.0);
    test_f64("922337203685477529599999e-5", 9223372036854774784.0);
    test_f64("922337203685477529600001e-5", 9223372036854775808.0);

    test_i128(
        "10141204801825834086073718800384",
        10141204801825834086073718800384,
    );
    test_i128(
        "10141204801825835211973625643008",
        10141204801825835211973625643008,
    );
    test_i128(
        "10141204801825834649023672221696",
        10141204801825834649023672221696,
    );
    test_f64(
        "1014120480182583464902367222169599999e-5",
        10141204801825834086073718800384.0,
    );
    test_f64(
        "1014120480182583464902367222169600001e-5",
        10141204801825835211973625643008.0,
    );

    test_f64(
        "5708990770823838890407843763683279797179383808",
        5708990770823838890407843763683279797179383808.0,
    );
    test_f64(
        "5708990770823839524233143877797980545530986496",
        5708990770823839524233143877797980545530986496.0,
    );
    test_f64(
        "5708990770823839207320493820740630171355185152",
        5708990770823839524233143877797980545530986496.0,
    );
    test_f64(
        "5708990770823839207320493820740630171355185151999e-3",
        5708990770823838890407843763683279797179383808.0,
    );
    test_f64(
        "5708990770823839207320493820740630171355185152001e-3",
        5708990770823839524233143877797980545530986496.0,
    );

    test_f64(&format!("1{}", "0".repeat(308)), 1E308);

    // Cover trimming
    test_f64(
        "2.225073858507201136057409796709131975934819546351645648023426109724822222021076945516529523908135087914149158913039621106870086438694594645527657207407820621743379988141063267329253552286881372149012981122451451889849057222307285255133155755015914397476397983411801999323962548289017107081850690630666655994938275772572015763062690663332647565300009245888316433037779791869612049497390377829704905051080609940730262937128958950003583799967207254304360284078895771796150945516748243471030702609144621572289880258182545180325707018860872113128079512233426288368622321503775666622503982534335974568884423900265498198385487948292206894721689831099698365846814022854243330660339850886445804001034933970427567186443383770486037861622771738545623065874679014086723327636718751234567890123456789012345678901e-308",
        2.2250738585072014e-308,
    );
}