osom_primitives/
offset.rs1#![allow(clippy::cast_possible_truncation, clippy::cast_sign_loss, clippy::cast_possible_wrap)]
2use crate::length::Length;
3
4#[repr(transparent)]
9#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Copy, Default)]
10#[must_use]
11pub struct Offset {
12 value: i32,
13}
14
15#[repr(C)]
17#[derive(Debug, PartialEq, Eq, Clone, Copy)]
18pub enum OffsetError {
19 AboveMaxRange = 0,
21
22 BelowMinRange = 1,
24}
25
26impl Offset {
27 const SAFE_MARGIN: i32 = const {
28 assert!(Length::SAFE_MARGIN < i32::MAX as u32);
29 Length::SAFE_MARGIN as i32
30 };
31
32 pub const MAX_OFFSET: Offset = const {
34 assert!(Self::SAFE_MARGIN >= 64, "SAFE_MARGIN has to be at least 64.");
35 assert!(
36 Self::SAFE_MARGIN < i32::MAX,
37 "SAFE_MARGIN has to be smaller than i32::MAX"
38 );
39 unsafe { Offset::new_unchecked(i32::MAX - Self::SAFE_MARGIN) }
40 };
41
42 pub const MIN_OFFSET: Offset = const {
44 assert!(Self::SAFE_MARGIN >= 64, "SAFE_MARGIN has to be at least 64.");
45 assert!(
46 Self::SAFE_MARGIN < i32::MAX,
47 "SAFE_MARGIN has to be smaller than i32::MAX"
48 );
49 unsafe { Offset::new_unchecked(i32::MIN + Self::SAFE_MARGIN) }
50 };
51
52 pub const ZERO: Self = unsafe { Self::new_unchecked(0) };
54
55 pub const ONE: Self = unsafe { Self::new_unchecked(1) };
57
58 pub const MINUS_ONE: Self = unsafe { Self::new_unchecked(-1) };
60
61 #[inline(always)]
69 pub const unsafe fn new_unchecked(value: i32) -> Self {
70 Self { value }
71 }
72
73 #[inline(always)]
79 pub const fn try_from_i32(value: i32) -> Result<Self, OffsetError> {
80 if value < Self::MIN_OFFSET.as_i32() {
81 Err(OffsetError::BelowMinRange)
82 } else if value > Self::MAX_OFFSET.as_i32() {
83 Err(OffsetError::AboveMaxRange)
84 } else {
85 Ok(unsafe { Self::new_unchecked(value) })
86 }
87 }
88
89 #[inline(always)]
95 pub const fn try_from_u32(value: u32) -> Result<Self, OffsetError> {
96 if value > Self::MAX_OFFSET.as_i32() as u32 {
97 return Err(OffsetError::AboveMaxRange);
98 }
99
100 let value = value as i32;
101
102 Self::try_from_i32(value)
103 }
104
105 #[inline(always)]
107 #[must_use]
108 pub const fn as_i32(&self) -> i32 {
109 self.value
110 }
111
112 #[inline(always)]
114 #[must_use]
115 pub const fn as_isize(&self) -> isize {
116 self.value as isize
117 }
118}
119
120impl TryFrom<i32> for Offset {
121 type Error = OffsetError;
122
123 fn try_from(value: i32) -> Result<Self, Self::Error> {
124 Self::try_from_i32(value)
125 }
126}
127
128impl TryFrom<u32> for Offset {
129 type Error = OffsetError;
130
131 fn try_from(value: u32) -> Result<Self, Self::Error> {
132 Self::try_from_u32(value)
133 }
134}
135
136impl TryFrom<isize> for Offset {
137 type Error = OffsetError;
138
139 fn try_from(value: isize) -> Result<Self, Self::Error> {
140 if value > Offset::MAX_OFFSET.as_isize() {
141 Err(OffsetError::AboveMaxRange)
142 } else if value < Offset::MIN_OFFSET.as_isize() {
143 Err(OffsetError::BelowMinRange)
144 } else {
145 let value = value as i32;
146
147 Ok(unsafe { Self::new_unchecked(value) })
148 }
149 }
150}
151
152impl From<Offset> for i32 {
153 fn from(value: Offset) -> Self {
154 value.as_i32()
155 }
156}
157
158impl From<Offset> for isize {
159 fn from(value: Offset) -> Self {
160 value.as_isize()
161 }
162}
163
164impl core::fmt::Display for Offset {
165 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
166 self.as_i32().fmt(f)
167 }
168}
169
170const _: () = const {
171 assert!(
172 size_of::<Offset>() == size_of::<Length>(),
173 "Offset and length have to be of the same size"
174 );
175 assert!(
176 align_of::<Offset>() == align_of::<Length>(),
177 "Offset and length have to have the same alignment"
178 );
179};