Skip to content

Commit ba57201

Browse files
authored
Fix (again) non-exhaustive matching on Number (#568)
* Try to fix non-exhaustive Number enum (again) * Use compile_fail doctests * Adjust docs for the Number::__NonExhaustive variant * Add CHANGELOG entry
1 parent 27a26d6 commit ba57201

File tree

3 files changed

+62
-6
lines changed

3 files changed

+62
-6
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
1212

1313
- Breaking: Added `no_std` support via a new `std` feature (enabled by default). With default features disabled, you must enable the `std` feature to access `de::from_reader`, and the `std::io` operations on `Options`, such as `from_reader`, `from_reader_seed`, `to_io_writer`, and `to_io_writer_pretty` ([#567](https://github.com/ron-rs/ron/pull/567))
1414

15+
- Breaking: Fixed `ron::value::Number` to ensure it is non-exhaustive, to avoid breaking `match`es when feature unification enables more of its variants than expected ([#568](https://github.com/ron-rs/ron/pull/568))
16+
1517
## [0.10.1] - 2025-04-08
1618

1719
### API Changes

src/value/number.rs

Lines changed: 59 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,8 @@ use serde::{de::Visitor, Serialize, Serializer};
1717
/// <summary>Exhaustively matching on <code>Number</code> in tests</summary>
1818
///
1919
/// If you want to ensure that you exhaustively handle every variant, you can
20-
/// match on the hidden `Number::__NonExhaustive` variant.
20+
/// match on the hidden `Number::__NonExhaustive(x)` variant by using the
21+
/// `x.never() -> !` method.
2122
///
2223
/// <div class="warning">
2324
/// Matching on this variant means that your code may break when RON is
@@ -54,8 +55,61 @@ pub enum Number {
5455
}
5556

5657
mod private {
58+
#[derive(Debug, PartialEq, PartialOrd, Eq, Hash, Ord)]
59+
enum _Never {}
60+
5761
#[derive(Copy, Clone, Debug, PartialEq, PartialOrd, Eq, Hash, Ord)]
58-
pub enum Never {}
62+
pub struct Never {
63+
never: &'static _Never,
64+
}
65+
66+
impl Never {
67+
pub fn never(self) -> ! {
68+
match *self.never {}
69+
}
70+
}
71+
72+
#[cfg(not(feature = "integer128"))]
73+
/// ```compile_fail
74+
/// # use ron::Number;
75+
/// fn match_number(x: Number) {
76+
/// match x {
77+
/// Number::I8(v) => println!("i8: {}", v),
78+
/// Number::I16(v) => println!("i16: {}", v),
79+
/// Number::I32(v) => println!("i32: {}", v),
80+
/// Number::I64(v) => println!("i64: {}", v),
81+
/// Number::U8(v) => println!("u8: {}", v),
82+
/// Number::U16(v) => println!("u16: {}", v),
83+
/// Number::U32(v) => println!("u32: {}", v),
84+
/// Number::U64(v) => println!("u64: {}", v),
85+
/// Number::F32(v) => println!("f32: {}", v.0),
86+
/// Number::F64(v) => println!("f64: {}", v.0),
87+
/// }
88+
/// }
89+
/// ```
90+
fn _assert_non_exhaustive_check_fails_not_integer128() {}
91+
92+
#[cfg(feature = "integer128")]
93+
/// ```compile_fail
94+
/// # use ron::Number;
95+
/// fn match_number(x: Number) {
96+
/// match x {
97+
/// Number::I8(v) => println!("i8: {}", v),
98+
/// Number::I16(v) => println!("i16: {}", v),
99+
/// Number::I32(v) => println!("i32: {}", v),
100+
/// Number::I64(v) => println!("i64: {}", v),
101+
/// Number::I128(v) => println!("i128: {}", v),
102+
/// Number::U8(v) => println!("u8: {}", v),
103+
/// Number::U16(v) => println!("u16: {}", v),
104+
/// Number::U32(v) => println!("u32: {}", v),
105+
/// Number::U64(v) => println!("u64: {}", v),
106+
/// Number::U128(v) => println!("u128: {}", v),
107+
/// Number::F32(v) => println!("f32: {}", v.0),
108+
/// Number::F64(v) => println!("f64: {}", v.0),
109+
/// }
110+
/// }
111+
/// ```
112+
fn _assert_non_exhaustive_check_fails_integer128() {}
59113
}
60114

61115
impl Serialize for Number {
@@ -76,7 +130,7 @@ impl Serialize for Number {
76130
Self::F32(v) => serializer.serialize_f32(v.get()),
77131
Self::F64(v) => serializer.serialize_f64(v.get()),
78132
#[cfg(not(doc))]
79-
Self::__NonExhaustive(never) => match *never {},
133+
Self::__NonExhaustive(never) => never.never(),
80134
}
81135
}
82136
}
@@ -102,7 +156,7 @@ impl Number {
102156
Self::F32(v) => visitor.visit_f32(v.get()),
103157
Self::F64(v) => visitor.visit_f64(v.get()),
104158
#[cfg(not(doc))]
105-
Self::__NonExhaustive(never) => match *never {},
159+
Self::__NonExhaustive(never) => never.never(),
106160
}
107161
}
108162
}
@@ -255,7 +309,7 @@ impl Number {
255309
Self::F32(v) => f64::from(v.get()),
256310
Self::F64(v) => v.get(),
257311
#[cfg(not(doc))]
258-
Self::__NonExhaustive(never) => match never {},
312+
Self::__NonExhaustive(never) => never.never(),
259313
}
260314
}
261315
}

tests/564_exhaustive_number.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ fn exhaustive_number_match() {
1818
Number::F32(v) => println!("{}", v.0),
1919
Number::F64(v) => println!("{}", v.0),
2020
#[cfg(not(doc))]
21-
Number::__NonExhaustive(never) => match never {},
21+
Number::__NonExhaustive(never) => never.never(),
2222
}
2323
}
2424

0 commit comments

Comments
 (0)