commonlibsse_ng\rel/offset.rs
1// C++ Original code
2// - ref: https://github.com/SARDONYX-forks/CommonLibVR/blob/ng/include/REL/Offset.h
3// SPDX-FileCopyrightText: (C) 2018 Ryan-rsm-McKenzie
4// SPDX-License-Identifier: MIT
5
6use core::num::NonZeroUsize;
7
8use crate::rel::ResolvableAddress;
9use crate::rel::id::DataBaseError;
10use crate::rel::module::ModuleState;
11
12/// Represents an offset that can be used to compute an absolute address.
13///
14/// This struct wraps a `usize` value, which directly corresponds to an offset.
15///
16/// ```
17/// use commonlibsse_ng::rel::offset::Offset;
18/// use commonlibsse_ng::rel::ResolvableAddress as _;
19///
20/// let offset = Offset::new(0x1000);
21/// assert_eq!(offset.offset().unwrap(), core::num::NonZero::new(0x1000).unwrap());
22/// ```
23#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
24#[repr(transparent)]
25pub struct Offset(usize);
26
27impl Offset {
28 /// Creates a new `Offset` instance with the given value.
29 ///
30 /// # Note
31 /// Return an error when trying to get the offset and it is 0
32 #[inline]
33 pub const fn new(offset: usize) -> Self {
34 Self(offset)
35 }
36}
37
38impl ResolvableAddress for Offset {
39 /// Get the offset.
40 ///
41 /// # Errors
42 /// Returns an error if the offset is 0.
43 #[inline]
44 fn offset(&self) -> Result<NonZeroUsize, DataBaseError> {
45 NonZeroUsize::new(self.0).ok_or(DataBaseError::SpecifiedZeroOffset)
46 }
47}
48
49/// Represents an offset that varies depending on the runtime environment.
50///
51/// This struct holds three possible offset values, each corresponding to a
52/// different runtime: Special Edition (`se_offset`), Anniversary Edition (`ae_offset`),
53/// and Virtual Reality (`vr_offset`).
54///
55/// The appropriate offset is selected based on the current runtime.
56///
57/// # Example
58/// ```rust
59/// use commonlibsse_ng::rel::offset::VariantOffset;
60/// use commonlibsse_ng::rel::ResolvableAddress as _;
61///
62/// let variant_offset = VariantOffset::new(0x1000, 0x2000, 0x3000);
63/// // let offset = variant_offset.offset().unwrap();
64/// ```
65#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
66pub struct VariantOffset {
67 se_offset: u64,
68 ae_offset: u64,
69 vr_offset: u64,
70}
71
72impl VariantOffset {
73 /// Creates a new `VariantOffset` instance with specified offsets for each runtime.
74 ///
75 /// # Note
76 /// Return an error when trying to get the offset and it is 0
77 #[inline]
78 pub const fn new(se_offset: u64, ae_offset: u64, vr_offset: u64) -> Self {
79 Self { se_offset, ae_offset, vr_offset }
80 }
81}
82
83impl ResolvableAddress for VariantOffset {
84 /// Get the offset based on the current runtime.
85 ///
86 /// # Errors
87 /// - Returns an error if the module state is invalid or the runtime is unknown.
88 /// - Returns an error if the offset is 0.
89 #[inline]
90 fn offset(&self) -> Result<NonZeroUsize, DataBaseError> {
91 use crate::rel::module::Runtime;
92
93 let runtime = ModuleState::map_or_init(|module| module.runtime)?; // Derived Copy
94 let offset = match runtime {
95 Runtime::Ae => self.ae_offset,
96 Runtime::Se => self.se_offset,
97 Runtime::Vr => self.vr_offset,
98 } as usize;
99
100 NonZeroUsize::new(offset).ok_or(DataBaseError::SpecifiedZeroOffset)
101 }
102}