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}