1
//! Regression test: parsing number-heavy documents must stay linear.
2
//!
3
//! `Parser::next_bytes_is_float` used to call `find("..")` on the whole remaining
4
//! input while clamping the result to the current float-char run, which made every
5
//! number scan to EOF on documents containing no `..` at all — quadratic overall.
6
//!
7
//! The assertion is on *scaling*, not on absolute time, so it stays meaningful on
8
//! slow/noisy CI machines: doubling the input should roughly double the work
9
//! (ratio ~2). Before the fix the ratio is ~4. The threshold sits far from both.
10

            
11
use std::time::Instant;
12

            
13
12
fn seq_of_floats(n: usize) -> String {
14
12
    let mut s = String::from("[");
15
124000
    for i in 0..n {
16
124000
        if i > 0 {
17
123988
            s.push(',');
18
123988
        }
19
124000
        s.push_str("1234.5678");
20
    }
21
12
    s.push(']');
22
12
    s
23
12
}
24

            
25
12
fn parse_millis(n: usize) -> f64 {
26
12
    let src = seq_of_floats(n);
27
12
    let start = Instant::now();
28
    // No `black_box` (it needs Rust 1.66, MSRV is 1.64): the unwrapped
29
    // cross-crate `from_str` allocates, so the parse isn't optimized away.
30
12
    let _value: ron::Value = ron::from_str(&src).unwrap();
31
12
    let elapsed = start.elapsed().as_secs_f64() * 1000.0;
32
12
    elapsed
33
12
}
34

            
35
#[test]
36
4
fn parsing_many_floats_scales_linearly() {
37
    const N: usize = 10_000;
38

            
39
    // Warm up so allocator/caches don't skew the first sample.
40
4
    parse_millis(N / 10);
41

            
42
4
    let base = parse_millis(N);
43
4
    let double = parse_millis(N * 2);
44

            
45
    // Guard against a uselessly small denominator on a very fast machine.
46
4
    if base < 1.0 {
47
        return;
48
4
    }
49

            
50
4
    let ratio = double / base;
51
4
    assert!(
52
4
        ratio < 3.0,
53
        "parsing {} floats took {:.1}ms but {} floats took {:.1}ms (ratio {:.2}); \
54
         expected ~2 (linear), ~4 means the quadratic scan is back",
55
        N,
56
        base,
57
        N * 2,
58
        double,
59
        ratio
60
    );
61
4
}