mirror of
https://github.com/rust-lang/rust
synced 2024-10-02 23:04:50 +00:00
core: avoid extern
types in formatting infrastructure
This commit is contained in:
parent
2c9556d28a
commit
23d1cc4b84
|
@ -5,6 +5,7 @@
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::hint::unreachable_unchecked;
|
use crate::hint::unreachable_unchecked;
|
||||||
|
use crate::ptr::NonNull;
|
||||||
|
|
||||||
#[lang = "format_placeholder"]
|
#[lang = "format_placeholder"]
|
||||||
#[derive(Copy, Clone)]
|
#[derive(Copy, Clone)]
|
||||||
|
@ -66,7 +67,13 @@ pub(super) enum Flag {
|
||||||
|
|
||||||
#[derive(Copy, Clone)]
|
#[derive(Copy, Clone)]
|
||||||
enum ArgumentType<'a> {
|
enum ArgumentType<'a> {
|
||||||
Placeholder { value: &'a Opaque, formatter: fn(&Opaque, &mut Formatter<'_>) -> Result },
|
Placeholder {
|
||||||
|
// INVARIANT: if `formatter` had type `fn(&T, _) -> _` then `value`
|
||||||
|
// was derived from a `&T` with lifetime `'a`.
|
||||||
|
value: NonNull<()>,
|
||||||
|
formatter: unsafe fn(NonNull<()>, &mut Formatter<'_>) -> Result,
|
||||||
|
_lifetime: PhantomData<&'a ()>,
|
||||||
|
},
|
||||||
Count(usize),
|
Count(usize),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -90,21 +97,15 @@ pub struct Argument<'a> {
|
||||||
impl<'a> Argument<'a> {
|
impl<'a> Argument<'a> {
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn new<'b, T>(x: &'b T, f: fn(&T, &mut Formatter<'_>) -> Result) -> Argument<'b> {
|
fn new<'b, T>(x: &'b T, f: fn(&T, &mut Formatter<'_>) -> Result) -> Argument<'b> {
|
||||||
// SAFETY: `mem::transmute(x)` is safe because
|
Argument {
|
||||||
// 1. `&'b T` keeps the lifetime it originated with `'b`
|
// INVARIANT: this creates an `ArgumentType<'b>` from a `&'b T` and
|
||||||
// (so as to not have an unbounded lifetime)
|
// a `fn(&T, ...)`, so the invariant is maintained.
|
||||||
// 2. `&'b T` and `&'b Opaque` have the same memory layout
|
ty: ArgumentType::Placeholder {
|
||||||
// (when `T` is `Sized`, as it is here)
|
value: NonNull::from(x).cast(),
|
||||||
// `mem::transmute(f)` is safe since `fn(&T, &mut Formatter<'_>) -> Result`
|
// SAFETY: function pointers always have the same layout.
|
||||||
// and `fn(&Opaque, &mut Formatter<'_>) -> Result` have the same ABI
|
formatter: unsafe { mem::transmute(f) },
|
||||||
// (as long as `T` is `Sized`)
|
_lifetime: PhantomData,
|
||||||
unsafe {
|
},
|
||||||
Argument {
|
|
||||||
ty: ArgumentType::Placeholder {
|
|
||||||
formatter: mem::transmute(f),
|
|
||||||
value: mem::transmute(x),
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -162,7 +163,14 @@ pub fn from_usize(x: &usize) -> Argument<'_> {
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub(super) unsafe fn fmt(&self, f: &mut Formatter<'_>) -> Result {
|
pub(super) unsafe fn fmt(&self, f: &mut Formatter<'_>) -> Result {
|
||||||
match self.ty {
|
match self.ty {
|
||||||
ArgumentType::Placeholder { formatter, value } => formatter(value, f),
|
// SAFETY:
|
||||||
|
// Because of the invariant that if `formatter` had the type
|
||||||
|
// `fn(&T, _) -> _` then `value` has type `&'b T` where `'b` is
|
||||||
|
// the lifetime of the `ArgumentType`, and because references
|
||||||
|
// and `NonNull` are ABI-compatible, this is completely equivalent
|
||||||
|
// to calling the original function passed to `new` with the
|
||||||
|
// original reference, which is sound.
|
||||||
|
ArgumentType::Placeholder { formatter, value, .. } => unsafe { formatter(value, f) },
|
||||||
// SAFETY: the caller promised this.
|
// SAFETY: the caller promised this.
|
||||||
ArgumentType::Count(_) => unsafe { unreachable_unchecked() },
|
ArgumentType::Count(_) => unsafe { unreachable_unchecked() },
|
||||||
}
|
}
|
||||||
|
@ -208,7 +216,3 @@ pub unsafe fn new() -> Self {
|
||||||
Self { _private: () }
|
Self { _private: () }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
extern "C" {
|
|
||||||
type Opaque;
|
|
||||||
}
|
|
||||||
|
|
Loading…
Reference in a new issue