1use crate::cglue::ReprCString;
6use crate::dataview::Pod;
7use crate::error::PartialResult;
8use crate::mem::MemoryView;
9use crate::prelude::PartialError;
10use crate::types::{imem, umem, Address, ByteSwap, PrimitiveAddress};
11
12use std::convert::TryInto;
13use std::marker::PhantomData;
14use std::mem::size_of;
15use std::{cmp, fmt, hash, ops};
16
17pub type Pointer32<T> = Pointer<u32, T>;
18pub type Pointer64<T> = Pointer<u64, T>;
19
20const _: [(); std::mem::size_of::<Pointer32<()>>()] = [(); std::mem::size_of::<u32>()];
21const _: [(); std::mem::size_of::<Pointer64<()>>()] = [(); std::mem::size_of::<u64>()];
22
23#[repr(transparent)]
92#[cfg_attr(feature = "serde", derive(::serde::Serialize))]
93pub struct Pointer<U: Sized, T: ?Sized = ()> {
94 pub inner: U,
95 phantom_data: PhantomData<fn() -> T>,
96}
97unsafe impl<U: Pod, T: ?Sized + 'static> Pod for Pointer<U, T> {}
98
99impl<U: PrimitiveAddress, T: ?Sized> Pointer<U, T> {
100 const PHANTOM_DATA: PhantomData<fn() -> T> = PhantomData;
101
102 #[inline]
112 pub fn null() -> Self {
113 Pointer {
114 inner: U::null(),
115 phantom_data: PhantomData,
116 }
117 }
118
119 #[inline]
130 pub fn is_null(self) -> bool {
131 self.inner.is_null()
132 }
133
134 #[inline]
145 pub fn non_null(self) -> Option<Pointer<U, T>> {
146 if self.is_null() {
147 None
148 } else {
149 Some(self)
150 }
151 }
152
153 #[inline]
165 pub fn to_umem(self) -> umem {
166 self.inner.to_umem()
167 }
168
169 #[inline]
171 pub fn address(&self) -> Address {
172 Address::from(self.inner)
173 }
174}
175
176impl<U: PrimitiveAddress, T: Sized> Pointer<U, T> {
177 pub fn offset(self, count: imem) -> Self {
197 let pointee_size = U::from_umem(size_of::<T>() as umem);
198 assert!(U::null() < pointee_size && pointee_size <= PrimitiveAddress::max());
199
200 if count >= 0 {
201 self.inner
202 .wrapping_add(U::from_umem(pointee_size.to_umem() * count as umem))
203 .into()
204 } else {
205 self.inner
206 .wrapping_sub(U::from_umem(pointee_size.to_umem() * (-count) as umem))
207 .into()
208 }
209 }
210
211 pub fn offset_from(self, origin: Self) -> imem {
234 let pointee_size: imem = size_of::<T>().try_into().unwrap();
235 let offset = self.inner.to_imem().wrapping_sub(origin.inner.to_imem());
236 offset / pointee_size as imem
237 }
238
239 #[allow(clippy::should_implement_trait)]
260 pub fn add(self, count: umem) -> Self {
261 self.offset(count as imem)
262 }
263
264 #[allow(clippy::should_implement_trait)]
286 pub fn sub(self, count: umem) -> Self {
287 self.offset((count as imem).wrapping_neg())
288 }
289}
290
291impl<U: PrimitiveAddress, T: Pod + ?Sized> Pointer<U, T> {
293 pub fn read_into<M: MemoryView>(self, mem: &mut M, out: &mut T) -> PartialResult<()> {
294 mem.read_ptr_into(self, out)
295 }
296}
297
298impl<U: PrimitiveAddress, T: Pod + Sized> Pointer<U, T> {
299 pub fn read<M: MemoryView>(self, mem: &mut M) -> PartialResult<T> {
300 mem.read_ptr(self)
301 }
302
303 pub fn write<M: MemoryView>(self, mem: &mut M, data: &T) -> PartialResult<()> {
304 mem.write_ptr(self, data)
305 }
306}
307
308impl<U: PrimitiveAddress> Pointer<U, ReprCString> {
310 pub fn read_utf8<M: MemoryView>(
311 self,
312 mem: &mut M,
313 max_length: usize,
314 ) -> PartialResult<ReprCString> {
315 match mem.read_utf8(self.inner.to_umem().into(), max_length) {
316 Ok(s) => Ok(s.into()),
317 Err(PartialError::Error(e)) => Err(PartialError::Error(e)),
318 Err(PartialError::PartialVirtualRead(s)) => {
319 Err(PartialError::PartialVirtualRead(s.into()))
320 }
321 Err(PartialError::PartialVirtualWrite(s)) => {
322 Err(PartialError::PartialVirtualWrite(s.into()))
323 }
324 }
325 }
326
327 pub fn read_utf8_lossy<M: MemoryView>(
328 self,
329 mem: &mut M,
330 max_length: usize,
331 ) -> PartialResult<ReprCString> {
332 match mem.read_utf8_lossy(self.inner.to_umem().into(), max_length) {
333 Ok(s) => Ok(s.into()),
334 Err(PartialError::Error(e)) => Err(PartialError::Error(e)),
335 Err(PartialError::PartialVirtualRead(s)) => {
336 Err(PartialError::PartialVirtualRead(s.into()))
337 }
338 Err(PartialError::PartialVirtualWrite(s)) => {
339 Err(PartialError::PartialVirtualWrite(s.into()))
340 }
341 }
342 }
343}
344
345impl<U: PrimitiveAddress, T> Pointer<U, [T]> {
346 pub fn decay(self) -> Pointer<U, T> {
347 Pointer {
348 inner: self.inner,
349 phantom_data: Pointer::<U, T>::PHANTOM_DATA,
350 }
351 }
352
353 pub fn at(self, i: umem) -> Pointer<U, T> {
354 let inner = self
355 .inner
356 .wrapping_add(U::from_umem(size_of::<T>() as umem * i));
357 Pointer {
358 inner,
359 phantom_data: Pointer::<U, T>::PHANTOM_DATA,
360 }
361 }
362}
363
364impl<U: PrimitiveAddress, T: ?Sized> Copy for Pointer<U, T> {}
365impl<U: PrimitiveAddress, T: ?Sized> Clone for Pointer<U, T> {
366 #[inline(always)]
367 fn clone(&self) -> Pointer<U, T> {
368 *self
369 }
370}
371impl<U: PrimitiveAddress, T: ?Sized> Default for Pointer<U, T> {
372 #[inline(always)]
373 fn default() -> Pointer<U, T> {
374 Pointer::null()
375 }
376}
377impl<U: PrimitiveAddress, T: ?Sized> Eq for Pointer<U, T> {}
378impl<U: PrimitiveAddress, T: ?Sized> PartialEq for Pointer<U, T> {
379 #[inline(always)]
380 fn eq(&self, rhs: &Pointer<U, T>) -> bool {
381 self.inner == rhs.inner
382 }
383}
384impl<U: PrimitiveAddress, T: ?Sized> PartialOrd for Pointer<U, T> {
385 #[inline(always)]
386 fn partial_cmp(&self, rhs: &Pointer<U, T>) -> Option<cmp::Ordering> {
387 Some(self.cmp(rhs))
388 }
389}
390impl<U: PrimitiveAddress, T: ?Sized> Ord for Pointer<U, T> {
391 #[inline(always)]
392 fn cmp(&self, rhs: &Pointer<U, T>) -> cmp::Ordering {
393 self.inner.cmp(&rhs.inner)
394 }
395}
396impl<U: PrimitiveAddress, T: ?Sized> hash::Hash for Pointer<U, T> {
397 #[inline(always)]
398 fn hash<H: hash::Hasher>(&self, state: &mut H) {
399 self.inner.hash(state)
400 }
401}
402impl<U: PrimitiveAddress, T: ?Sized> AsRef<U> for Pointer<U, T> {
403 #[inline(always)]
404 fn as_ref(&self) -> &U {
405 &self.inner
406 }
407}
408impl<U: PrimitiveAddress, T: ?Sized> AsMut<U> for Pointer<U, T> {
409 #[inline(always)]
410 fn as_mut(&mut self) -> &mut U {
411 &mut self.inner
412 }
413}
414
415impl<U: PrimitiveAddress, T: ?Sized> From<U> for Pointer<U, T> {
417 #[inline(always)]
418 fn from(address: U) -> Pointer<U, T> {
419 Pointer {
420 inner: address,
421 phantom_data: PhantomData,
422 }
423 }
424}
425
426impl<T: ?Sized> From<Address> for Pointer64<T> {
427 #[inline(always)]
428 fn from(address: Address) -> Pointer64<T> {
429 Pointer {
430 inner: address.to_umem() as u64,
431 phantom_data: PhantomData,
432 }
433 }
434}
435
436impl<U: Into<Address>, T: ?Sized> From<Pointer<U, T>> for umem {
438 #[inline(always)]
439 fn from(ptr: Pointer<U, T>) -> umem {
440 let address: Address = ptr.inner.into();
441 address.to_umem()
442 }
443}
444
445impl<U: PrimitiveAddress, T> ops::Add<umem> for Pointer<U, T> {
447 type Output = Pointer<U, T>;
448 #[inline(always)]
449 fn add(self, other: umem) -> Pointer<U, T> {
450 let address = self.inner + U::from_umem(size_of::<T>() as umem * other);
451 Pointer {
452 inner: address,
453 phantom_data: self.phantom_data,
454 }
455 }
456}
457impl<U: PrimitiveAddress, T> ops::Sub<umem> for Pointer<U, T> {
458 type Output = Pointer<U, T>;
459 #[inline(always)]
460 fn sub(self, other: umem) -> Pointer<U, T> {
461 let address = self.inner - U::from_umem(size_of::<T>() as umem * other);
462 Pointer {
463 inner: address,
464 phantom_data: self.phantom_data,
465 }
466 }
467}
468
469#[cfg(feature = "64_bit_mem")]
470impl<U: PrimitiveAddress, T> ops::Add<usize> for Pointer<U, T> {
471 type Output = Pointer<U, T>;
472 #[inline(always)]
473 fn add(self, other: usize) -> Pointer<U, T> {
474 self + other as umem
475 }
476}
477#[cfg(feature = "64_bit_mem")]
478impl<U: PrimitiveAddress, T> ops::Sub<usize> for Pointer<U, T> {
479 type Output = Pointer<U, T>;
480 #[inline(always)]
481 fn sub(self, other: usize) -> Pointer<U, T> {
482 self - other as umem
483 }
484}
485
486impl<U: PrimitiveAddress, T: ?Sized> fmt::Debug for Pointer<U, T> {
487 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
488 write!(f, "{:x}", self.inner)
489 }
490}
491impl<U: PrimitiveAddress, T: ?Sized> fmt::UpperHex for Pointer<U, T> {
492 #[inline(always)]
493 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
494 write!(f, "{:X}", self.inner)
495 }
496}
497impl<U: PrimitiveAddress, T: ?Sized> fmt::LowerHex for Pointer<U, T> {
498 #[inline(always)]
499 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
500 write!(f, "{:x}", self.inner)
501 }
502}
503impl<U: PrimitiveAddress, T: ?Sized> fmt::Display for Pointer<U, T> {
504 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
505 write!(f, "{:x}", self.inner)
506 }
507}
508
509impl<U: PrimitiveAddress, T: ?Sized + 'static> ByteSwap for Pointer<U, T> {
510 fn byte_swap(&mut self) {
511 self.inner.byte_swap();
512 }
513}
514
515#[cfg(test)]
516mod tests {
517 use super::*;
518
519 #[test]
520 fn offset32() {
521 let ptr8 = Pointer32::<u8>::from(0x1000u32);
522 assert_eq!(ptr8.offset(3).to_umem(), 0x1003);
523 assert_eq!(ptr8.offset(-5).to_umem(), 0xFFB);
524
525 let ptr16 = Pointer32::<u16>::from(0x1000u32);
526 assert_eq!(ptr16.offset(3).to_umem(), 0x1006);
527 assert_eq!(ptr16.offset(-5).to_umem(), 0xFF6);
528
529 let ptr32 = Pointer32::<u32>::from(0x1000u32);
530 assert_eq!(ptr32.offset(3).to_umem(), 0x100C);
531 assert_eq!(ptr32.offset(-5).to_umem(), 0xFEC);
532 }
533
534 #[test]
535 fn offset64() {
536 let ptr8 = Pointer64::<u8>::from(0x1000u64);
537 assert_eq!(ptr8.offset(3).to_umem(), 0x1003);
538 assert_eq!(ptr8.offset(-5).to_umem(), 0xFFB);
539
540 let ptr16 = Pointer64::<u16>::from(0x1000u64);
541 assert_eq!(ptr16.offset(3).to_umem(), 0x1006);
542 assert_eq!(ptr16.offset(-5).to_umem(), 0xFF6);
543
544 let ptr32 = Pointer64::<u32>::from(0x1000u64);
545 assert_eq!(ptr32.offset(3).to_umem(), 0x100C);
546 assert_eq!(ptr32.offset(-5).to_umem(), 0xFEC);
547
548 let ptr64 = Pointer64::<u64>::from(0x1000u64);
549 assert_eq!(ptr64.offset(3).to_umem(), 0x1018);
550 assert_eq!(ptr64.offset(-5).to_umem(), 0xFD8);
551 }
552
553 #[test]
554 fn offset_from() {
555 let ptr1 = Pointer64::<u16>::from(0x1000u64);
556 let ptr2 = Pointer64::<u16>::from(0x1008u64);
557
558 assert_eq!(ptr2.offset_from(ptr1), 4);
559 assert_eq!(ptr1.offset_from(ptr2), -4);
560 }
561}