Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[RFC 2011] Library code #97233

Merged
merged 1 commit into from
May 25, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
109 changes: 109 additions & 0 deletions library/core/src/asserting.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
// Contains the machinery necessary to print useful `assert!` messages. Not intended for public
// usage, not even nightly use-cases.
//
// Based on https://github.com/dtolnay/case-studies/tree/master/autoref-specialization. When
// 'specialization' is robust enough (5 years? 10 years? Never?), `Capture` can be specialized
// to [Printable].

#![allow(missing_debug_implementations)]
#![doc(hidden)]
#![unstable(feature = "generic_assert_internals", issue = "44838")]

use crate::{
fmt::{Debug, Formatter},
marker::PhantomData,
};

// ***** TryCapture - Generic *****

/// Marker used by [Capture]
#[unstable(feature = "generic_assert_internals", issue = "44838")]
pub struct TryCaptureWithoutDebug;

/// Catches an arbitrary `E` and modifies `to` accordingly
#[unstable(feature = "generic_assert_internals", issue = "44838")]
pub trait TryCaptureGeneric<E, M> {
/// Similar to [TryCapturePrintable] but generic to any `E`.
fn try_capture(&self, to: &mut Capture<E, M>);
}

impl<E> TryCaptureGeneric<E, TryCaptureWithoutDebug> for &Wrapper<&E> {
#[inline]
fn try_capture(&self, _: &mut Capture<E, TryCaptureWithoutDebug>) {}
}

impl<E> Debug for Capture<E, TryCaptureWithoutDebug> {
fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), core::fmt::Error> {
f.write_str("N/A")
}
}

// ***** TryCapture - Printable *****

/// Marker used by [Capture]
#[unstable(feature = "generic_assert_internals", issue = "44838")]
pub struct TryCaptureWithDebug;

/// Catches an arbitrary `E: Printable` and modifies `to` accordingly
#[unstable(feature = "generic_assert_internals", issue = "44838")]
pub trait TryCapturePrintable<E, M> {
/// Similar as [TryCaptureGeneric] but specialized to any `E: Printable`.
fn try_capture(&self, to: &mut Capture<E, M>);
}

impl<E> TryCapturePrintable<E, TryCaptureWithDebug> for Wrapper<&E>
where
E: Printable,
{
#[inline]
fn try_capture(&self, to: &mut Capture<E, TryCaptureWithDebug>) {
to.elem = Some(*self.0);
}
}

impl<E> Debug for Capture<E, TryCaptureWithDebug>
where
E: Printable,
{
fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), core::fmt::Error> {
match self.elem {
None => f.write_str("N/A"),
Some(ref value) => Debug::fmt(value, f),
}
}
}

// ***** Others *****

/// All possible captured `assert!` elements
///
/// # Types
///
/// * `E`: **E**lement that is going to be displayed.
/// * `M`: **M**arker used to differentiate [Capture]s in regards to [Debug].
#[unstable(feature = "generic_assert_internals", issue = "44838")]
pub struct Capture<E, M> {
// If None, then `E` does not implements [Printable] or `E` wasn't evaluated (`assert!( ... )`
// short-circuited).
//
// If Some, then `E` implements [Printable] and was evaluated.
pub elem: Option<E>,
phantom: PhantomData<M>,
}

impl<M, T> Capture<M, T> {
#[inline]
pub const fn new() -> Self {
Self { elem: None, phantom: PhantomData }
}
}

/// Necessary for the implementations of `TryCapture*`
#[unstable(feature = "generic_assert_internals", issue = "44838")]
pub struct Wrapper<T>(pub T);
c410-f3r marked this conversation as resolved.
Show resolved Hide resolved

/// Tells which elements can be copied and displayed
#[unstable(feature = "generic_assert_internals", issue = "44838")]
pub trait Printable: Copy + Debug {}

impl<T> Printable for T where T: Copy + Debug {}
1 change: 1 addition & 0 deletions library/core/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -310,6 +310,7 @@ pub mod ops;
pub mod any;
pub mod array;
pub mod ascii;
pub mod asserting;
scottmcm marked this conversation as resolved.
Show resolved Hide resolved
#[unstable(feature = "async_iterator", issue = "79024")]
pub mod async_iter;
pub mod cell;
Expand Down
37 changes: 37 additions & 0 deletions library/core/tests/asserting.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
use core::asserting::{Capture, TryCaptureGeneric, TryCapturePrintable, Wrapper};

macro_rules! test {
($test_name:ident, $elem:expr, $captured_elem:expr, $output:literal) => {
#[test]
fn $test_name() {
let elem = $elem;
let mut capture = Capture::new();
assert!(capture.elem == None);
(&Wrapper(&elem)).try_capture(&mut capture);
assert!(capture.elem == $captured_elem);
assert_eq!(format!("{:?}", capture), $output);
}
};
}

#[derive(Debug, PartialEq)]
struct NoCopy;

#[derive(PartialEq)]
struct NoCopyNoDebug;

#[derive(Clone, Copy, PartialEq)]
struct NoDebug;

test!(
capture_with_non_copyable_and_non_debugabble_elem_has_correct_params,
NoCopyNoDebug,
None,
"N/A"
);

test!(capture_with_non_copyable_elem_has_correct_params, NoCopy, None, "N/A");

test!(capture_with_non_debugabble_elem_has_correct_params, NoDebug, None, "N/A");

test!(capture_with_copyable_and_debugabble_elem_has_correct_params, 1i32, Some(1i32), "1");
2 changes: 2 additions & 0 deletions library/core/tests/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
#![feature(float_minimum_maximum)]
#![feature(future_join)]
#![feature(future_poll_fn)]
#![feature(generic_assert_internals)]
#![feature(array_try_from_fn)]
#![feature(hasher_prefixfree_extras)]
#![feature(hashmap_internals)]
Expand Down Expand Up @@ -104,6 +105,7 @@ mod alloc;
mod any;
mod array;
mod ascii;
mod asserting;
mod atomic;
mod bool;
mod cell;
Expand Down