1
use ron;
2
use serde::{Deserialize, Serialize};
3

            
4
// NOTE:
5
// std::ops::RangeToInclusive and RangeFull do not have stable serde support out of the box.
6
// We use `serde(remote = "...")` to define how these std types should be serialized/deserialized.
7

            
8
#[derive(PartialEq, Deserialize, Serialize, Debug)]
9
#[serde(remote = "std::ops::RangeToInclusive")]
10
struct RangeToInclusive<T> {
11
    end: T,
12
}
13

            
14
#[derive(PartialEq, Deserialize, Serialize, Debug)]
15
#[serde(remote = "std::ops::RangeFull")]
16
struct RangeFull;
17

            
18
#[derive(PartialEq, Deserialize, Serialize, Debug)]
19
struct RangeTest {
20
    a: std::ops::Range<i32>,
21
    b: std::ops::RangeInclusive<i32>,
22
    c: std::ops::Range<f32>,
23
    d: std::ops::RangeInclusive<f32>,
24
}
25

            
26
#[test]
27
4
fn test_ranges() {
28
4
    let ranges = RangeTest {
29
4
        a: 0..5,
30
4
        b: 1..=3,
31
4
        c: 0.6..4.3,
32
4
        d: 0.3..=5.7,
33
4
    };
34

            
35
4
    let ser = ron::to_string(&ranges).unwrap();
36
4
    assert_eq!(
37
        ser,
38
        "(a:(start:0,end:5),b:(start:1,end:3),c:(start:0.6,end:4.3),d:(start:0.3,end:5.7))"
39
    );
40

            
41
4
    assert_eq!(
42
4
        ron::ser::to_string_pretty(
43
4
            &ranges,
44
4
            ron::ser::PrettyConfig::new()
45
4
                .compact_ranges(true)
46
4
                .new_line("")
47
4
                .indentor("")
48
4
                .separator("")
49
4
                .compact_structs(true)
50
        )
51
4
        .unwrap(),
52
        "(a:0..5,b:1..=3,c:0.6..4.3,d:0.3..=5.7)"
53
    );
54

            
55
4
    let de: RangeTest = ron::from_str(&ser).unwrap();
56
4
    assert_eq!(de, ranges);
57
4
}
58

            
59
#[test]
60
4
fn test_range_integer_bases() {
61
4
    assert_eq!(
62
4
        ron::from_str::<std::ops::Range<u8>>("0b0000..0b0101").unwrap(),
63
        0..5
64
    );
65
4
    assert_eq!(
66
4
        ron::from_str::<std::ops::Range<u8>>("0o0..0o5").unwrap(),
67
        0..5
68
    );
69
4
    assert_eq!(
70
4
        ron::from_str::<std::ops::Range<u8>>("0x0..0x5").unwrap(),
71
        0..5
72
    );
73

            
74
4
    assert_eq!(
75
4
        ron::from_str::<std::ops::Range<u8>>("b'\\x00'..b'\\x05'").unwrap(),
76
        0..5
77
    );
78
4
    assert_eq!(
79
4
        ron::from_str::<std::ops::RangeInclusive<u8>>("b'A'..=b'Z'").unwrap(),
80
        b'A'..=b'Z'
81
    );
82

            
83
4
    assert_eq!(
84
4
        ron::from_str::<std::ops::RangeTo<u8>>("..0b0101").unwrap(),
85
        ..5
86
    );
87
4
    assert_eq!(
88
4
        ron::from_str::<std::ops::RangeFrom<u8>>("0b0000..").unwrap(),
89
        0..
90
    );
91
4
}
92

            
93
#[derive(PartialEq, Deserialize, Serialize, Debug)]
94
#[serde(untagged)]
95
enum MaybeRange {
96
    Range(std::ops::Range<i32>),
97
    RangeFrom(std::ops::RangeFrom<i32>),
98
    #[serde(with = "RangeFull")]
99
    RangeFull(std::ops::RangeFull),
100
    Value(i32),
101
}
102

            
103
#[test]
104
4
fn test_range_untagged() {
105
4
    assert_eq!(
106
4
        ron::from_str::<MaybeRange>("0..5").unwrap(),
107
        MaybeRange::Range(0..5)
108
    );
109
4
    assert_eq!(
110
4
        ron::from_str::<MaybeRange>("0..").unwrap(),
111
        MaybeRange::RangeFrom(0..)
112
    );
113
4
    assert_eq!(
114
4
        ron::from_str::<MaybeRange>("42").unwrap(),
115
        MaybeRange::Value(42)
116
    );
117
4
}
118

            
119
#[derive(PartialEq, Deserialize, Serialize, Debug)]
120
struct UnclosedRangeTest {
121
    a: std::ops::RangeFrom<i32>,
122
    b: std::ops::RangeTo<i32>,
123
    #[serde(with = "RangeToInclusive")]
124
    c: std::ops::RangeToInclusive<i32>,
125
    d: std::ops::RangeFrom<f32>,
126
    e: std::ops::RangeTo<f32>,
127
    #[serde(with = "RangeToInclusive")]
128
    f: std::ops::RangeToInclusive<f32>,
129
    #[serde(with = "RangeFull")]
130
    g: std::ops::RangeFull,
131
}
132

            
133
#[test]
134
4
fn test_unclosed_ranges() {
135
4
    let ranges = UnclosedRangeTest {
136
4
        a: 2..,
137
4
        b: ..3,
138
4
        c: ..=3,
139
4
        d: 1.5..,
140
4
        e: ..2.3,
141
4
        f: ..=2.3,
142
4
        g: ..,
143
4
    };
144

            
145
4
    let ser = ron::to_string(&ranges).unwrap();
146
4
    assert_eq!(
147
        ser,
148
        "(a:(start:2),b:(end:3),c:(end:3),d:(start:1.5),e:(end:2.3),f:(end:2.3),g:())"
149
    );
150

            
151
4
    assert_eq!(
152
4
        ron::ser::to_string_pretty(
153
4
            &ranges,
154
4
            ron::ser::PrettyConfig::new()
155
4
                .compact_ranges(true)
156
4
                .new_line("")
157
4
                .indentor("")
158
4
                .separator("")
159
4
                .compact_structs(true)
160
        )
161
4
        .unwrap(),
162
        "(a:2..,b:..3,c:..=3,d:1.5..,e:..2.3,f:..=2.3,g:..)"
163
    );
164

            
165
4
    let de: UnclosedRangeTest = ron::from_str(&ser).unwrap();
166
4
    assert_eq!(de, ranges);
167
4
}
168

            
169
#[test]
170
4
fn test_string_range() {
171
4
    assert!(ron::from_str::<std::ops::Range<&str>>("\"x\"..\"h\"").is_err());
172
4
    assert!(ron::from_str::<std::ops::Range<i32>>("\"x\"..\"h\"").is_err());
173

            
174
4
    let str_range = "a".."z";
175
4
    let ser = ron::to_string(&str_range).unwrap();
176
4
    assert_eq!(ser, r#"(start:"a",end:"z")"#);
177

            
178
4
    let pretty_compact = ron::ser::to_string_pretty(
179
4
        &str_range,
180
4
        ron::ser::PrettyConfig::new()
181
4
            .compact_ranges(true)
182
4
            .new_line("")
183
4
            .indentor("")
184
4
            .separator("")
185
4
            .compact_structs(true),
186
    )
187
4
    .unwrap();
188

            
189
4
    assert_eq!(pretty_compact, r#"(start:"a",end:"z")"#);
190
4
}
191

            
192
#[test]
193
4
fn test_inf_nan_ranges() {
194
4
    let r = ron::from_str::<std::ops::RangeFrom<f32>>("inff32..").unwrap();
195
4
    assert!(r.start.is_infinite() && r.start.is_sign_positive());
196

            
197
4
    let r = ron::from_str::<std::ops::RangeFrom<f32>>("NaNf32..").unwrap();
198
4
    assert!(r.start.is_nan());
199

            
200
4
    let r = ron::from_str::<std::ops::RangeFrom<f64>>("inff64..").unwrap();
201
4
    assert!(r.start.is_infinite() && r.start.is_sign_positive());
202

            
203
4
    let r = ron::from_str::<std::ops::RangeFrom<f64>>("NaNf64..").unwrap();
204
4
    assert!(r.start.is_nan());
205

            
206
4
    let r = ron::from_str::<std::ops::Range<f32>>("(start:inf,end:NaN)").unwrap();
207
4
    assert!(r.start.is_infinite() && r.start.is_sign_positive());
208
4
    assert!(r.end.is_nan());
209

            
210
4
    let r = ron::from_str::<std::ops::RangeInclusive<f32>>("(start:NaN,end:inf)").unwrap();
211
4
    assert!(r.start().is_nan());
212
4
    assert!(r.end().is_infinite());
213
4
}
214

            
215
// Untagged enum where RangeFull comes after RangeTo and Value
216
#[derive(PartialEq, Deserialize, Serialize, Debug)]
217
#[serde(untagged)]
218
enum MaybeRangeOrValue {
219
    Range(std::ops::Range<i32>),
220
    RangeFrom(std::ops::RangeFrom<i32>),
221
    RangeTo(std::ops::RangeTo<i32>),
222
    Value(i32),
223
    #[serde(with = "RangeFull")]
224
    RangeFull(std::ops::RangeFull),
225
}
226

            
227
#[test]
228
4
fn test_range_full_whitespace_lookahead() {
229
    // In deserialize_any context, `..` deserializes as a unit value
230
4
    assert_eq!(ron::from_str::<ron::Value>("..").unwrap(), ron::Value::Unit);
231

            
232
    // `.. 5` is invalid: `..` consumes the range-full token, but `5` is trailing garbage
233
4
    assert!(ron::from_str::<ron::Value>(".. 5").is_err());
234

            
235
    // Untagged enum: `.. 5` must not silently match as RangeFull/unit variant,
236
    // because `5` is trailing garbage after `..`
237
4
    assert!(ron::from_str::<MaybeRange>(".. 5").is_err());
238

            
239
4
    assert_eq!(
240
4
        ron::from_str::<MaybeRangeOrValue>("..5").unwrap(),
241
        MaybeRangeOrValue::RangeTo(..5)
242
    );
243

            
244
    // Untagged enum where RangeFull comes after Value: `.. 5` is invalid RON
245
    // regardless of variant order — `..` is not a valid prefix for integers
246
4
    assert!(ron::from_str::<MaybeRangeOrValue>(".. 5").is_err());
247

            
248
4
    assert_eq!(
249
4
        ron::from_str::<MaybeRangeOrValue>("..").unwrap(),
250
        MaybeRangeOrValue::RangeFull(std::ops::RangeFull)
251
    );
252

            
253
    // Untagged enum: plain `..` correctly matches the RangeFull variant
254
4
    assert_eq!(
255
4
        ron::from_str::<MaybeRange>("..").unwrap(),
256
        MaybeRange::RangeFull(std::ops::RangeFull)
257
    );
258
4
}