use std::{cmp, fmt, hash, mem, str};
use std::marker::PhantomData;
use crate::Pod;
use super::image::{Va, SignedVa};
#[repr(transparent)]
pub struct Ptr<T: ?Sized = ()> {
va: Va,
marker: PhantomData<fn() -> T>
}
impl<T: ?Sized> Ptr<T> {
const MARKER: PhantomData<fn() -> T> = PhantomData;
pub const NULL: Ptr<T> = Ptr { va: 0, marker: PhantomData };
pub const fn null() -> Ptr<T> {
Ptr::NULL
}
pub const fn is_null(self) -> bool {
self.va == 0
}
pub const fn member(va: Va, offset: u32) -> Ptr<T> {
let va = va + offset as Va;
Ptr { va, marker: Self::MARKER }
}
pub const fn cast<U: ?Sized>(self) -> Ptr<U> {
Ptr { va: self.va, marker: Ptr::<U>::MARKER }
}
pub const fn offset<U: ?Sized>(self, offset: SignedVa) -> Ptr<U> {
let va = self.va.wrapping_add(offset as Va);
Ptr { va, marker: Ptr::<U>::MARKER }
}
pub const fn into_raw(self) -> Va {
self.va
}
fn fmt(self) -> [u8; mem::size_of::<Va>() * 2 + 2] {
let mut s = [0; mem::size_of::<Va>() * 2 + 2];
s[0] = b'0';
s[1] = b'x';
let mut va = self.va;
for i in 0..mem::size_of::<Va>() * 2 {
va = va.rotate_left(4);
let digit = (va & 0xf) as u8;
let chr = if digit < 10 { b'0' + digit } else { b'a' + (digit - 10) };
s[i + 2] = chr;
}
return s;
}
}
impl<T> Ptr<[T]> {
pub const fn decay(self) -> Ptr<T> {
Ptr { va: self.va, marker: Ptr::<T>::MARKER }
}
pub const fn at(self, i: usize) -> Ptr<T> {
let va = self.va + (i * mem::size_of::<T>()) as Va;
Ptr { va, marker: Ptr::<T>::MARKER }
}
}
unsafe impl<T: ?Sized> Pod for Ptr<T> where Ptr<T>: 'static {}
impl<T: ?Sized> Copy for Ptr<T> {}
impl<T: ?Sized> Clone for Ptr<T> {
fn clone(&self) -> Ptr<T> {
*self
}
}
impl<T: ?Sized> Default for Ptr<T> {
fn default() -> Ptr<T> {
Ptr::NULL
}
}
impl<T: ?Sized> Eq for Ptr<T> {}
impl<T: ?Sized> PartialEq for Ptr<T> {
fn eq(&self, rhs: &Ptr<T>) -> bool {
self.va == rhs.va
}
}
impl<T: ?Sized> PartialOrd for Ptr<T> {
fn partial_cmp(&self, rhs: &Ptr<T>) -> Option<cmp::Ordering> {
self.va.partial_cmp(&rhs.va)
}
}
impl<T: ?Sized> Ord for Ptr<T> {
fn cmp(&self, rhs: &Ptr<T>) -> cmp::Ordering {
self.va.cmp(&rhs.va)
}
}
impl<T: ?Sized> hash::Hash for Ptr<T> {
fn hash<H: hash::Hasher>(&self, state: &mut H) {
self.va.hash(state)
}
}
impl<T: ?Sized> From<Va> for Ptr<T> {
fn from(va: Va) -> Ptr<T> {
Ptr { va, marker: PhantomData }
}
}
impl<T: ?Sized> From<Ptr<T>> for Va {
fn from(ptr: Ptr<T>) -> Va {
ptr.va
}
}
impl<T: ?Sized> AsRef<Va> for Ptr<T> {
fn as_ref(&self) -> &Va {
&self.va
}
}
impl<T: ?Sized> AsMut<Va> for Ptr<T> {
fn as_mut(&mut self) -> &mut Va {
&mut self.va
}
}
impl<T: ?Sized> fmt::Debug for Ptr<T> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let buf = Ptr::fmt(*self);
f.write_str(unsafe { str::from_utf8_unchecked(&buf) })
}
}
impl<T: ?Sized> fmt::UpperHex for Ptr<T> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
self.va.fmt(f)
}
}
impl<T: ?Sized> fmt::LowerHex for Ptr<T> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
self.va.fmt(f)
}
}
impl<T: ?Sized> fmt::Display for Ptr<T> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let buf = Ptr::fmt(*self);
f.write_str(unsafe { str::from_utf8_unchecked(&buf) })
}
}
#[cfg(feature = "serde")]
impl<T: ?Sized> serde::Serialize for Ptr<T> {
fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
branch! {
pe32 { serializer.serialize_u32(self.va) }
pe64 { serializer.serialize_u64(self.va) }
}
}
}