Lines
100 %
Functions
Branches
use ron;
use serde::{Deserialize, Serialize};
// NOTE:
// std::ops::RangeToInclusive and RangeFull do not have stable serde support out of the box.
// We use `serde(remote = "...")` to define how these std types should be serialized/deserialized.
#[derive(PartialEq, Deserialize, Serialize, Debug)]
#[serde(remote = "std::ops::RangeToInclusive")]
struct RangeToInclusive<T> {
end: T,
}
#[serde(remote = "std::ops::RangeFull")]
struct RangeFull;
struct RangeTest {
a: std::ops::Range<i32>,
b: std::ops::RangeInclusive<i32>,
c: std::ops::Range<f32>,
d: std::ops::RangeInclusive<f32>,
#[test]
fn test_ranges() {
let ranges = RangeTest {
a: 0..5,
b: 1..=3,
c: 0.6..4.3,
d: 0.3..=5.7,
};
let ser = ron::to_string(&ranges).unwrap();
assert_eq!(
ser,
"(a:(start:0,end:5),b:(start:1,end:3),c:(start:0.6,end:4.3),d:(start:0.3,end:5.7))"
);
ron::ser::to_string_pretty(
&ranges,
ron::ser::PrettyConfig::new()
.compact_ranges(true)
.new_line("")
.indentor("")
.separator("")
.compact_structs(true)
)
.unwrap(),
"(a:0..5,b:1..=3,c:0.6..4.3,d:0.3..=5.7)"
let de: RangeTest = ron::from_str(&ser).unwrap();
assert_eq!(de, ranges);
fn test_range_integer_bases() {
ron::from_str::<std::ops::Range<u8>>("0b0000..0b0101").unwrap(),
0..5
ron::from_str::<std::ops::Range<u8>>("0o0..0o5").unwrap(),
ron::from_str::<std::ops::Range<u8>>("0x0..0x5").unwrap(),
ron::from_str::<std::ops::Range<u8>>("b'\\x00'..b'\\x05'").unwrap(),
ron::from_str::<std::ops::RangeInclusive<u8>>("b'A'..=b'Z'").unwrap(),
b'A'..=b'Z'
ron::from_str::<std::ops::RangeTo<u8>>("..0b0101").unwrap(),
..5
ron::from_str::<std::ops::RangeFrom<u8>>("0b0000..").unwrap(),
0..
#[serde(untagged)]
enum MaybeRange {
Range(std::ops::Range<i32>),
RangeFrom(std::ops::RangeFrom<i32>),
#[serde(with = "RangeFull")]
RangeFull(std::ops::RangeFull),
Value(i32),
fn test_range_untagged() {
ron::from_str::<MaybeRange>("0..5").unwrap(),
MaybeRange::Range(0..5)
ron::from_str::<MaybeRange>("0..").unwrap(),
MaybeRange::RangeFrom(0..)
ron::from_str::<MaybeRange>("42").unwrap(),
MaybeRange::Value(42)
struct UnclosedRangeTest {
a: std::ops::RangeFrom<i32>,
b: std::ops::RangeTo<i32>,
#[serde(with = "RangeToInclusive")]
c: std::ops::RangeToInclusive<i32>,
d: std::ops::RangeFrom<f32>,
e: std::ops::RangeTo<f32>,
f: std::ops::RangeToInclusive<f32>,
g: std::ops::RangeFull,
fn test_unclosed_ranges() {
let ranges = UnclosedRangeTest {
a: 2..,
b: ..3,
c: ..=3,
d: 1.5..,
e: ..2.3,
f: ..=2.3,
g: ..,
"(a:(start:2),b:(end:3),c:(end:3),d:(start:1.5),e:(end:2.3),f:(end:2.3),g:())"
"(a:2..,b:..3,c:..=3,d:1.5..,e:..2.3,f:..=2.3,g:..)"
let de: UnclosedRangeTest = ron::from_str(&ser).unwrap();
fn test_string_range() {
assert!(ron::from_str::<std::ops::Range<&str>>("\"x\"..\"h\"").is_err());
assert!(ron::from_str::<std::ops::Range<i32>>("\"x\"..\"h\"").is_err());
let str_range = "a".."z";
let ser = ron::to_string(&str_range).unwrap();
assert_eq!(ser, r#"(start:"a",end:"z")"#);
let pretty_compact = ron::ser::to_string_pretty(
&str_range,
.compact_structs(true),
.unwrap();
assert_eq!(pretty_compact, r#"(start:"a",end:"z")"#);
fn test_inf_nan_ranges() {
let r = ron::from_str::<std::ops::RangeFrom<f32>>("inff32..").unwrap();
assert!(r.start.is_infinite() && r.start.is_sign_positive());
let r = ron::from_str::<std::ops::RangeFrom<f32>>("NaNf32..").unwrap();
assert!(r.start.is_nan());
let r = ron::from_str::<std::ops::RangeFrom<f64>>("inff64..").unwrap();
let r = ron::from_str::<std::ops::RangeFrom<f64>>("NaNf64..").unwrap();
let r = ron::from_str::<std::ops::Range<f32>>("(start:inf,end:NaN)").unwrap();
assert!(r.end.is_nan());
let r = ron::from_str::<std::ops::RangeInclusive<f32>>("(start:NaN,end:inf)").unwrap();
assert!(r.start().is_nan());
assert!(r.end().is_infinite());
// Untagged enum where RangeFull comes after RangeTo and Value
enum MaybeRangeOrValue {
RangeTo(std::ops::RangeTo<i32>),
fn test_range_full_whitespace_lookahead() {
// In deserialize_any context, `..` deserializes as a unit value
assert_eq!(ron::from_str::<ron::Value>("..").unwrap(), ron::Value::Unit);
// `.. 5` is invalid: `..` consumes the range-full token, but `5` is trailing garbage
assert!(ron::from_str::<ron::Value>(".. 5").is_err());
// Untagged enum: `.. 5` must not silently match as RangeFull/unit variant,
// because `5` is trailing garbage after `..`
assert!(ron::from_str::<MaybeRange>(".. 5").is_err());
ron::from_str::<MaybeRangeOrValue>("..5").unwrap(),
MaybeRangeOrValue::RangeTo(..5)
// Untagged enum where RangeFull comes after Value: `.. 5` is invalid RON
// regardless of variant order — `..` is not a valid prefix for integers
assert!(ron::from_str::<MaybeRangeOrValue>(".. 5").is_err());
ron::from_str::<MaybeRangeOrValue>("..").unwrap(),
MaybeRangeOrValue::RangeFull(std::ops::RangeFull)
// Untagged enum: plain `..` correctly matches the RangeFull variant
ron::from_str::<MaybeRange>("..").unwrap(),
MaybeRange::RangeFull(std::ops::RangeFull)