#![no_std]
use core::cmp::Ordering;
use core::convert::AsRef;
use core::fmt::{Debug, Display, Formatter};
use core::hash::{Hash, Hasher};
use core::ops::{Deref, DerefMut};
use core::ptr;
#[repr(transparent)]
#[derive(Copy, Clone, Default)]
pub struct ByAddress<T>(pub T)
where
T: ?Sized + Deref;
impl<T> ByAddress<T>
where
T: ?Sized + Deref,
{
fn addr(&self) -> *const T::Target {
&*self.0
}
pub fn from_ref(r: &T) -> &Self {
unsafe {
&*(r as *const T as *const Self)
}
}
}
struct DebugAdapter<'a, T>(&'a T)
where
T: ?Sized + Deref + Debug;
impl<'a, T> Debug for DebugAdapter<'a, T>
where
T: ?Sized + Deref + Debug,
{
fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
self.0.fmt(f)?;
f.write_str(" @ ")?;
(self.0.deref() as *const T::Target).fmt(f)?;
Ok(())
}
}
impl<T> Debug for ByAddress<T>
where
T: ?Sized + Deref + Debug,
{
fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
f.debug_tuple("ByAddress")
.field(&DebugAdapter(&self.0))
.finish()
}
}
impl<T> Display for ByAddress<T>
where
T: ?Sized + Deref + Display,
{
fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
self.0.fmt(f)
}
}
impl<T> PartialEq for ByAddress<T>
where
T: ?Sized + Deref,
{
fn eq(&self, other: &Self) -> bool {
ptr::eq(self.addr(), other.addr())
}
}
impl<T> Eq for ByAddress<T> where T: ?Sized + Deref {}
impl<T> Ord for ByAddress<T>
where
T: ?Sized + Deref,
{
fn cmp(&self, other: &Self) -> Ordering {
self.addr().cmp(&other.addr())
}
}
impl<T> PartialOrd for ByAddress<T>
where
T: ?Sized + Deref,
{
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.addr().cmp(&other.addr()))
}
}
impl<T> Hash for ByAddress<T>
where
T: ?Sized + Deref,
{
fn hash<H: Hasher>(&self, state: &mut H) {
self.addr().hash(state)
}
}
impl<T> Deref for ByAddress<T>
where
T: ?Sized + Deref,
{
type Target = T;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl<T> DerefMut for ByAddress<T>
where
T: ?Sized + Deref,
{
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.0
}
}
impl<T, U> AsRef<U> for ByAddress<T>
where
T: ?Sized + Deref + AsRef<U>,
{
fn as_ref(&self) -> &U {
self.0.as_ref()
}
}
impl<T, U> AsMut<U> for ByAddress<T>
where
T: ?Sized + Deref + AsMut<U>,
{
fn as_mut(&mut self) -> &mut U {
self.0.as_mut()
}
}
impl<T> From<T> for ByAddress<T>
where
T: Deref,
{
fn from(t: T) -> ByAddress<T> {
ByAddress(t)
}
}
#[repr(transparent)]
#[derive(Copy, Clone, Default)]
pub struct ByThinAddress<T>(pub T)
where
T: ?Sized + Deref;
impl<T> ByThinAddress<T>
where
T: ?Sized + Deref,
{
fn addr(&self) -> *const T::Target {
&*self.0
}
pub fn from_ref(r: &T) -> &Self {
unsafe {
&*(r as *const T as *const Self)
}
}
}
impl<T> Debug for ByThinAddress<T>
where
T: ?Sized + Deref + Debug,
{
fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
f.debug_tuple("ByThinAddress")
.field(&DebugAdapter(&self.0))
.finish()
}
}
impl<T> Display for ByThinAddress<T>
where
T: ?Sized + Deref + Display,
{
fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
self.0.fmt(f)
}
}
impl<T> PartialEq for ByThinAddress<T>
where
T: ?Sized + Deref,
{
fn eq(&self, other: &Self) -> bool {
core::ptr::eq(self.addr() as *const (), other.addr() as *const _)
}
}
impl<T> Eq for ByThinAddress<T> where T: ?Sized + Deref {}
impl<T> Ord for ByThinAddress<T>
where
T: ?Sized + Deref,
{
fn cmp(&self, other: &Self) -> Ordering {
(self.addr() as *const ()).cmp(&(other.addr() as *const ()))
}
}
impl<T> PartialOrd for ByThinAddress<T>
where
T: ?Sized + Deref,
{
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some((self.addr() as *const ()).cmp(&(other.addr() as *const ())))
}
}
impl<T> Hash for ByThinAddress<T>
where
T: ?Sized + Deref,
{
fn hash<H: Hasher>(&self, state: &mut H) {
(self.addr() as *const ()).hash(state)
}
}
impl<T> Deref for ByThinAddress<T>
where
T: ?Sized + Deref,
{
type Target = T;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl<T> DerefMut for ByThinAddress<T>
where
T: ?Sized + Deref,
{
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.0
}
}
impl<T, U> AsRef<U> for ByThinAddress<T>
where
T: ?Sized + Deref + AsRef<U>,
{
fn as_ref(&self) -> &U {
self.0.as_ref()
}
}
#[cfg(test)]
mod tests {
extern crate std;
use std::format;
use crate::{ByAddress, ByThinAddress};
trait A: std::fmt::Debug {
fn test(&self) {}
}
trait B: A {
fn test2(&self) {}
}
#[derive(Debug)]
struct Test {}
impl A for Test {}
impl B for Test {}
fn force_vtable<O: B>(v: &O) -> &dyn A {
v
}
#[test]
fn test_thin_ptr_fail() {
let t = Test {};
let tr1: &dyn A = &t;
let tr2: &dyn A = force_vtable(&t);
let a = ByAddress(tr1);
let b = ByAddress(tr2);
assert_ne!(a, b);
}
#[test]
fn test_thin_ptr_success() {
let t = Test {};
let tr1: &dyn A = &t;
let tr2: &dyn A = force_vtable(&t);
let a = ByThinAddress(tr1);
let b = ByThinAddress(tr2);
assert_eq!(a, b);
}
#[test]
fn test_debug() {
let x = &1;
let b = ByAddress(x);
let expected = format!("ByAddress(1 @ {:p})", x);
let actual = format!("{:?}", b);
assert_eq!(expected, actual);
let t = ByThinAddress(x);
let expected = format!("ByThinAddress(1 @ {:p})", x);
let actual = format!("{:?}", t);
assert_eq!(expected, actual);
}
}