pelite\pe64/
ptr.rs

1/*!
2Typed virtual address.
3*/
4
5use std::{cmp, fmt, hash, mem, str};
6use std::marker::PhantomData;
7
8use crate::Pod;
9
10use super::image::{Va, SignedVa};
11
12/// Typed virtual address.
13#[repr(transparent)]
14pub struct Ptr<T: ?Sized = ()> {
15	va: Va,
16	marker: PhantomData<fn() -> T>
17}
18
19impl<T: ?Sized> Ptr<T> {
20	// Work around unstable const fn features
21	const MARKER: PhantomData<fn() -> T> = PhantomData;
22	/// Null pointer constant.
23	pub const NULL: Ptr<T> = Ptr { va: 0, marker: PhantomData };
24	/// Creates a null pointer.
25	pub const fn null() -> Ptr<T> {
26		Ptr::NULL
27	}
28	/// Returns true if the pointer is null.
29	pub const fn is_null(self) -> bool {
30		self.va == 0
31	}
32	/// Constructs a pointer with an offset.
33	pub const fn member(va: Va, offset: u32) -> Ptr<T> {
34		let va = va + offset as Va;
35		Ptr { va, marker: Self::MARKER }
36	}
37	/// Casts the pointer to a different type keeping the pointer address fixed.
38	pub const fn cast<U: ?Sized>(self) -> Ptr<U> {
39		Ptr { va: self.va, marker: Ptr::<U>::MARKER }
40	}
41	/// Offsets and casts the pointer.
42	///
43	/// Because the type of the current and the target may be unrelated, this is a byte offset.
44	///
45	/// # Examples
46	///
47	/// ```
48	/// use pelite::pe64::Ptr;
49	///
50	/// #[repr(C)]
51	/// struct Composite {
52	/// 	int: i32,
53	/// 	float: f32,
54	/// }
55	///
56	/// let p: Ptr<Composite> = Ptr::from(0x2000);
57	/// let target = p.offset::<f32>(4);
58	///
59	/// assert_eq!(target, Ptr::from(0x2004));
60	/// ```
61	pub const fn offset<U: ?Sized>(self, offset: SignedVa) -> Ptr<U> {
62		let va = self.va.wrapping_add(offset as Va);
63		Ptr { va, marker: Ptr::<U>::MARKER }
64	}
65	/// Returns the raw integer, type ascription helper.
66	pub const fn into_raw(self) -> Va {
67		self.va
68	}
69	/// Formats the pointer.
70	fn fmt(self) -> [u8; mem::size_of::<Va>() * 2 + 2] {
71		let mut s = [0; mem::size_of::<Va>() * 2 + 2];
72		s[0] = b'0';
73		s[1] = b'x';
74		let mut va = self.va;
75		for i in 0..mem::size_of::<Va>() * 2 {
76			va = va.rotate_left(4);
77			let digit = (va & 0xf) as u8;
78			let chr = if digit < 10 { b'0' + digit } else { b'a' + (digit - 10) };
79			s[i + 2] = chr;
80		}
81		return s;
82	}
83}
84impl<T> Ptr<[T]> {
85	/// Decays the pointer from `[T]` to `T`.
86	pub const fn decay(self) -> Ptr<T> {
87		Ptr { va: self.va, marker: Ptr::<T>::MARKER }
88	}
89	/// Pointer arithmetic, gets the pointer of an element at the specified index.
90	pub const fn at(self, i: usize) -> Ptr<T> {
91		let va = self.va + (i * mem::size_of::<T>()) as Va;
92		Ptr { va, marker: Ptr::<T>::MARKER }
93	}
94}
95
96unsafe impl<T: ?Sized> Pod for Ptr<T> where Ptr<T>: 'static {}
97
98impl<T: ?Sized> Copy for Ptr<T> {}
99impl<T: ?Sized> Clone for Ptr<T> {
100	fn clone(&self) -> Ptr<T> {
101		*self
102	}
103}
104impl<T: ?Sized> Default for Ptr<T> {
105	fn default() -> Ptr<T> {
106		Ptr::NULL
107	}
108}
109impl<T: ?Sized> Eq for Ptr<T> {}
110impl<T: ?Sized> PartialEq for Ptr<T> {
111	fn eq(&self, rhs: &Ptr<T>) -> bool {
112		self.va == rhs.va
113	}
114}
115impl<T: ?Sized> PartialOrd for Ptr<T> {
116	fn partial_cmp(&self, rhs: &Ptr<T>) -> Option<cmp::Ordering> {
117		self.va.partial_cmp(&rhs.va)
118	}
119}
120impl<T: ?Sized> Ord for Ptr<T> {
121	fn cmp(&self, rhs: &Ptr<T>) -> cmp::Ordering {
122		self.va.cmp(&rhs.va)
123	}
124}
125impl<T: ?Sized> hash::Hash for Ptr<T> {
126	fn hash<H: hash::Hasher>(&self, state: &mut H) {
127		self.va.hash(state)
128	}
129}
130impl<T: ?Sized> From<Va> for Ptr<T> {
131	fn from(va: Va) -> Ptr<T> {
132		Ptr { va, marker: PhantomData }
133	}
134}
135impl<T: ?Sized> From<Ptr<T>> for Va {
136	fn from(ptr: Ptr<T>) -> Va {
137		ptr.va
138	}
139}
140impl<T: ?Sized> AsRef<Va> for Ptr<T> {
141	fn as_ref(&self) -> &Va {
142		&self.va
143	}
144}
145impl<T: ?Sized> AsMut<Va> for Ptr<T> {
146	fn as_mut(&mut self) -> &mut Va {
147		&mut self.va
148	}
149}
150impl<T: ?Sized> fmt::Debug for Ptr<T> {
151	fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
152		let buf = Ptr::fmt(*self);
153		f.write_str(unsafe { str::from_utf8_unchecked(&buf) })
154	}
155}
156impl<T: ?Sized> fmt::UpperHex for Ptr<T> {
157	fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
158		self.va.fmt(f)
159	}
160}
161impl<T: ?Sized> fmt::LowerHex for Ptr<T> {
162	fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
163		self.va.fmt(f)
164	}
165}
166impl<T: ?Sized> fmt::Display for Ptr<T> {
167	fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
168		let buf = Ptr::fmt(*self);
169		f.write_str(unsafe { str::from_utf8_unchecked(&buf) })
170	}
171}
172
173#[cfg(feature = "serde")]
174impl<T: ?Sized> serde::Serialize for Ptr<T> {
175	fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
176		branch! {
177			pe32 { serializer.serialize_u32(self.va) }
178			pe64 { serializer.serialize_u64(self.va) }
179		}
180	}
181}