1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
use crate::ser;
use num_traits::float::FloatCore;
/// Format as float string, make changes to be sure valid YAML float (zmij may render 4e-6 and not 4.0e-6)
use std::fmt::Write;
use zmij::Float;
/// Format as float string, make changes to be sure valid YAML float
pub(crate) fn push_float_string<F: Float + FloatCore>(
target: &mut String,
f: F,
) -> ser::Result<()> {
if f.is_nan() {
target.push_str(".nan");
} else if f.is_infinite() {
if f.is_sign_positive() {
target.push_str(".inf");
} else {
target.push_str("-.inf");
}
} else {
let mut buf = zmij::Buffer::new();
// Branches .is_nan and .is_infinite are already covered above
let s = buf.format_finite(f);
target.reserve(s.len() + 3);
// YAML 1.1 float requires:
// - a decimal point in the mantissa (avoid integers being parsed as int)
// - a sign (+ or -) in the exponent (when exponent is present)
if let Some(exp_pos) = s.find('e').or_else(|| s.find('E')) {
// 1) Write mantissa, ensuring it has a decimal point.
if !s[..exp_pos].contains('.') {
// "4e-6" -> "4.0e-6"
target.push_str(&s[..exp_pos]);
target.push_str(".0");
} else {
target.push_str(&s[..exp_pos]);
}
// 2) Write exponent marker.
target.push_str(&s[exp_pos..=exp_pos]);
// 3) Ensure exponent sign.
if !matches!(s.as_bytes().get(exp_pos + 1), Some(b'+' | b'-')) {
// "1e6" -> "1e+6"
target.push('+');
}
target.push_str(&s[exp_pos + 1..]);
} else if !s.contains('.') {
// No decimal and no exponent: append .0
target.push_str(s);
target.push_str(".0");
} else {
target.push_str(s);
}
}
Ok(())
}
/// Format as float string, make changes to be sure valid YAML float
pub(crate) fn write_float_string<F: Float + FloatCore, W: Write>(
target: &mut W,
f: F,
) -> ser::Result<()> {
if f.is_nan() {
target.write_str(".nan")?;
} else if f.is_infinite() {
if f.is_sign_positive() {
target.write_str(".inf")?;
} else {
target.write_str("-.inf")?;
}
} else {
let mut buf = zmij::Buffer::new();
// Branches .is_nan and .is_infinite are already covered above
let s = buf.format_finite(f);
// YAML 1.1 float requires:
// - a decimal point in the mantissa (avoid integers being parsed as int)
// - a sign (+ or -) in the exponent (when exponent is present)
if let Some(exp_pos) = s.find('e').or_else(|| s.find('E')) {
// 1) Write mantissa, ensuring it has a decimal point.
if !s[..exp_pos].contains('.') {
// "4e-6" -> "4.0e-6"
target.write_str(&s[..exp_pos])?;
target.write_str(".0")?;
} else {
target.write_str(&s[..exp_pos])?;
}
// 2) Write exponent marker.
target.write_str(&s[exp_pos..=exp_pos])?;
// 3) Ensure exponent sign.
if !matches!(s.as_bytes().get(exp_pos + 1), Some(b'+' | b'-')) {
// "1e6" -> "1e+6"
target.write_char('+')?;
}
target.write_str(&s[exp_pos + 1..])?;
} else if !s.contains('.') {
// No decimal and no exponent: append .0
target.write_str(s)?;
target.write_str(".0")?;
} else {
target.write_str(s)?;
}
}
Ok(())
}