osom_lib_primitives/
offset.rs1#![allow(clippy::cast_possible_truncation, clippy::cast_sign_loss, clippy::cast_possible_wrap)]
4use osom_lib_reprc::macros::reprc;
5
6use crate::length::Length;
7
8#[reprc]
13#[repr(transparent)]
14#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Copy, Default)]
15#[must_use]
16pub struct Offset {
17 value: i32,
18}
19
20#[reprc]
22#[repr(u8)]
23#[derive(Debug, PartialEq, Eq, Clone, Copy)]
24pub enum OffsetError {
25 AboveMaxRange = 0,
27
28 BelowMinRange = 1,
30}
31
32impl Offset {
33 const SAFE_MARGIN: i32 = const {
34 assert!(Length::SAFE_MARGIN < i32::MAX as u32);
35 Length::SAFE_MARGIN as i32
36 };
37
38 pub const MAX_OFFSET: Offset = const {
40 assert!(Self::SAFE_MARGIN >= 64, "SAFE_MARGIN has to be at least 64.");
41 assert!(
42 Self::SAFE_MARGIN < i32::MAX,
43 "SAFE_MARGIN has to be smaller than i32::MAX"
44 );
45 unsafe { Offset::new_unchecked(i32::MAX - Self::SAFE_MARGIN) }
46 };
47
48 pub const MIN_OFFSET: Offset = const {
50 assert!(Self::SAFE_MARGIN >= 64, "SAFE_MARGIN has to be at least 64.");
51 assert!(
52 Self::SAFE_MARGIN < i32::MAX,
53 "SAFE_MARGIN has to be smaller than i32::MAX"
54 );
55 unsafe { Offset::new_unchecked(i32::MIN + Self::SAFE_MARGIN) }
56 };
57
58 pub const ZERO: Self = unsafe { Self::new_unchecked(0) };
60
61 pub const ONE: Self = unsafe { Self::new_unchecked(1) };
63
64 pub const MINUS_ONE: Self = unsafe { Self::new_unchecked(-1) };
66
67 #[inline(always)]
75 pub const unsafe fn new_unchecked(value: i32) -> Self {
76 Self { value }
77 }
78
79 #[inline(always)]
85 pub const fn try_from_i32(value: i32) -> Result<Self, OffsetError> {
86 if value < Self::MIN_OFFSET.as_i32() {
87 Err(OffsetError::BelowMinRange)
88 } else if value > Self::MAX_OFFSET.as_i32() {
89 Err(OffsetError::AboveMaxRange)
90 } else {
91 Ok(unsafe { Self::new_unchecked(value) })
92 }
93 }
94
95 #[inline(always)]
101 pub const fn try_from_u32(value: u32) -> Result<Self, OffsetError> {
102 if value > Self::MAX_OFFSET.as_i32() as u32 {
103 return Err(OffsetError::AboveMaxRange);
104 }
105
106 let value = value as i32;
107
108 Self::try_from_i32(value)
109 }
110
111 #[inline(always)]
113 #[must_use]
114 pub const fn as_i32(&self) -> i32 {
115 self.value
116 }
117
118 #[inline(always)]
120 #[must_use]
121 pub const fn as_isize(&self) -> isize {
122 self.value as isize
123 }
124}
125
126impl TryFrom<i32> for Offset {
127 type Error = OffsetError;
128
129 fn try_from(value: i32) -> Result<Self, Self::Error> {
130 Self::try_from_i32(value)
131 }
132}
133
134impl TryFrom<u32> for Offset {
135 type Error = OffsetError;
136
137 fn try_from(value: u32) -> Result<Self, Self::Error> {
138 Self::try_from_u32(value)
139 }
140}
141
142impl TryFrom<isize> for Offset {
143 type Error = OffsetError;
144
145 fn try_from(value: isize) -> Result<Self, Self::Error> {
146 if value > Offset::MAX_OFFSET.as_isize() {
147 Err(OffsetError::AboveMaxRange)
148 } else if value < Offset::MIN_OFFSET.as_isize() {
149 Err(OffsetError::BelowMinRange)
150 } else {
151 let value = value as i32;
152
153 Ok(unsafe { Self::new_unchecked(value) })
154 }
155 }
156}
157
158impl From<Offset> for i32 {
159 fn from(value: Offset) -> Self {
160 value.as_i32()
161 }
162}
163
164impl From<Offset> for isize {
165 fn from(value: Offset) -> Self {
166 value.as_isize()
167 }
168}
169
170impl core::fmt::Display for Offset {
171 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
172 self.as_i32().fmt(f)
173 }
174}
175
176const _: () = const {
177 assert!(
178 size_of::<Offset>() == size_of::<Length>(),
179 "Offset and length have to be of the same size"
180 );
181 assert!(
182 align_of::<Offset>() == align_of::<Length>(),
183 "Offset and length have to have the same alignment"
184 );
185};