Skip to content

Commit ca269b1

Browse files
authored
Rollup merge of #97233 - c410-f3r:assert-lib, r=scottmcm
[RFC 2011] Library code CC #96496 Based on https://github.com/dtolnay/case-studies/tree/master/autoref-specialization. Basically creates two traits with the same method name. One trait is generic over any `T` and the other is specialized to any `T: Printable`. The compiler will then call the corresponding trait method through auto reference. ```rust fn main() { let mut a = Capture::new(); let mut b = Capture::new(); (&Wrapper(&1i32)).try_capture(&mut a); // `try_capture` from `TryCapturePrintable` (&Wrapper(&vec![1i32])).try_capture(&mut b); // `try_capture` from `TryCaptureGeneric` assert_eq!(format!("{:?}", a), "1"); assert_eq!(format!("{:?}", b), "N/A"); } ``` r? `@scottmcm`
2 parents c12a36a + 664e8a9 commit ca269b1

File tree

4 files changed

+149
-0
lines changed

4 files changed

+149
-0
lines changed

library/core/src/asserting.rs

+109
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
// Contains the machinery necessary to print useful `assert!` messages. Not intended for public
2+
// usage, not even nightly use-cases.
3+
//
4+
// Based on https://github.com/dtolnay/case-studies/tree/master/autoref-specialization. When
5+
// 'specialization' is robust enough (5 years? 10 years? Never?), `Capture` can be specialized
6+
// to [Printable].
7+
8+
#![allow(missing_debug_implementations)]
9+
#![doc(hidden)]
10+
#![unstable(feature = "generic_assert_internals", issue = "44838")]
11+
12+
use crate::{
13+
fmt::{Debug, Formatter},
14+
marker::PhantomData,
15+
};
16+
17+
// ***** TryCapture - Generic *****
18+
19+
/// Marker used by [Capture]
20+
#[unstable(feature = "generic_assert_internals", issue = "44838")]
21+
pub struct TryCaptureWithoutDebug;
22+
23+
/// Catches an arbitrary `E` and modifies `to` accordingly
24+
#[unstable(feature = "generic_assert_internals", issue = "44838")]
25+
pub trait TryCaptureGeneric<E, M> {
26+
/// Similar to [TryCapturePrintable] but generic to any `E`.
27+
fn try_capture(&self, to: &mut Capture<E, M>);
28+
}
29+
30+
impl<E> TryCaptureGeneric<E, TryCaptureWithoutDebug> for &Wrapper<&E> {
31+
#[inline]
32+
fn try_capture(&self, _: &mut Capture<E, TryCaptureWithoutDebug>) {}
33+
}
34+
35+
impl<E> Debug for Capture<E, TryCaptureWithoutDebug> {
36+
fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), core::fmt::Error> {
37+
f.write_str("N/A")
38+
}
39+
}
40+
41+
// ***** TryCapture - Printable *****
42+
43+
/// Marker used by [Capture]
44+
#[unstable(feature = "generic_assert_internals", issue = "44838")]
45+
pub struct TryCaptureWithDebug;
46+
47+
/// Catches an arbitrary `E: Printable` and modifies `to` accordingly
48+
#[unstable(feature = "generic_assert_internals", issue = "44838")]
49+
pub trait TryCapturePrintable<E, M> {
50+
/// Similar as [TryCaptureGeneric] but specialized to any `E: Printable`.
51+
fn try_capture(&self, to: &mut Capture<E, M>);
52+
}
53+
54+
impl<E> TryCapturePrintable<E, TryCaptureWithDebug> for Wrapper<&E>
55+
where
56+
E: Printable,
57+
{
58+
#[inline]
59+
fn try_capture(&self, to: &mut Capture<E, TryCaptureWithDebug>) {
60+
to.elem = Some(*self.0);
61+
}
62+
}
63+
64+
impl<E> Debug for Capture<E, TryCaptureWithDebug>
65+
where
66+
E: Printable,
67+
{
68+
fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), core::fmt::Error> {
69+
match self.elem {
70+
None => f.write_str("N/A"),
71+
Some(ref value) => Debug::fmt(value, f),
72+
}
73+
}
74+
}
75+
76+
// ***** Others *****
77+
78+
/// All possible captured `assert!` elements
79+
///
80+
/// # Types
81+
///
82+
/// * `E`: **E**lement that is going to be displayed.
83+
/// * `M`: **M**arker used to differentiate [Capture]s in regards to [Debug].
84+
#[unstable(feature = "generic_assert_internals", issue = "44838")]
85+
pub struct Capture<E, M> {
86+
// If None, then `E` does not implements [Printable] or `E` wasn't evaluated (`assert!( ... )`
87+
// short-circuited).
88+
//
89+
// If Some, then `E` implements [Printable] and was evaluated.
90+
pub elem: Option<E>,
91+
phantom: PhantomData<M>,
92+
}
93+
94+
impl<M, T> Capture<M, T> {
95+
#[inline]
96+
pub const fn new() -> Self {
97+
Self { elem: None, phantom: PhantomData }
98+
}
99+
}
100+
101+
/// Necessary for the implementations of `TryCapture*`
102+
#[unstable(feature = "generic_assert_internals", issue = "44838")]
103+
pub struct Wrapper<T>(pub T);
104+
105+
/// Tells which elements can be copied and displayed
106+
#[unstable(feature = "generic_assert_internals", issue = "44838")]
107+
pub trait Printable: Copy + Debug {}
108+
109+
impl<T> Printable for T where T: Copy + Debug {}

library/core/src/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -310,6 +310,7 @@ pub mod ops;
310310
pub mod any;
311311
pub mod array;
312312
pub mod ascii;
313+
pub mod asserting;
313314
#[unstable(feature = "async_iterator", issue = "79024")]
314315
pub mod async_iter;
315316
pub mod cell;

library/core/tests/asserting.rs

+37
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
use core::asserting::{Capture, TryCaptureGeneric, TryCapturePrintable, Wrapper};
2+
3+
macro_rules! test {
4+
($test_name:ident, $elem:expr, $captured_elem:expr, $output:literal) => {
5+
#[test]
6+
fn $test_name() {
7+
let elem = $elem;
8+
let mut capture = Capture::new();
9+
assert!(capture.elem == None);
10+
(&Wrapper(&elem)).try_capture(&mut capture);
11+
assert!(capture.elem == $captured_elem);
12+
assert_eq!(format!("{:?}", capture), $output);
13+
}
14+
};
15+
}
16+
17+
#[derive(Debug, PartialEq)]
18+
struct NoCopy;
19+
20+
#[derive(PartialEq)]
21+
struct NoCopyNoDebug;
22+
23+
#[derive(Clone, Copy, PartialEq)]
24+
struct NoDebug;
25+
26+
test!(
27+
capture_with_non_copyable_and_non_debugabble_elem_has_correct_params,
28+
NoCopyNoDebug,
29+
None,
30+
"N/A"
31+
);
32+
33+
test!(capture_with_non_copyable_elem_has_correct_params, NoCopy, None, "N/A");
34+
35+
test!(capture_with_non_debugabble_elem_has_correct_params, NoDebug, None, "N/A");
36+
37+
test!(capture_with_copyable_and_debugabble_elem_has_correct_params, 1i32, Some(1i32), "1");

library/core/tests/lib.rs

+2
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535
#![feature(float_minimum_maximum)]
3636
#![feature(future_join)]
3737
#![feature(future_poll_fn)]
38+
#![feature(generic_assert_internals)]
3839
#![feature(array_try_from_fn)]
3940
#![feature(hasher_prefixfree_extras)]
4041
#![feature(hashmap_internals)]
@@ -104,6 +105,7 @@ mod alloc;
104105
mod any;
105106
mod array;
106107
mod ascii;
108+
mod asserting;
107109
mod atomic;
108110
mod bool;
109111
mod cell;

0 commit comments

Comments
 (0)