osom_lib_primitives/
length.rs1use core::{convert::Infallible, fmt::Display};
4
5use osom_lib_reprc::macros::reprc;
6use osom_lib_try_clone::TryClone;
7
8#[reprc]
13#[repr(transparent)]
14#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Copy, Default)]
15#[must_use]
16pub struct Length {
17 size: u32,
18}
19
20#[reprc]
22#[repr(u8)]
23#[derive(Debug, PartialEq, Eq, Clone, Copy)]
24pub enum LengthError {
25 Negative = 0,
27
28 OutOfMaxRange = 1,
30}
31
32impl Display for LengthError {
33 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
34 match self {
35 LengthError::Negative => write!(f, "LengthError::Negative"),
36 LengthError::OutOfMaxRange => write!(f, "LengthError::OutOfMaxRange"),
37 }
38 }
39}
40
41impl Length {
42 pub const SAFE_MARGIN: u32 = 2048;
49
50 pub const MAX_LENGTH: Self = const {
53 const I32_MAX: u32 = i32::MAX as u32;
54 assert!(Self::SAFE_MARGIN >= 64, "SAFE_MARGIN has to be at least 64.");
55 assert!(
56 Self::SAFE_MARGIN < I32_MAX,
57 "SAFE_MARGIN has to be smaller than i32::MAX"
58 );
59 unsafe { Self::new_unchecked(I32_MAX - Self::SAFE_MARGIN) }
60 };
61
62 pub const ZERO: Self = unsafe { Self::new_unchecked(0) };
64
65 pub const ONE: Self = unsafe { Self::new_unchecked(1) };
67
68 #[inline(always)]
76 pub const unsafe fn new_unchecked(value: u32) -> Self {
77 Self { size: value }
78 }
79
80 #[inline(always)]
86 pub const fn try_from_u32(value: u32) -> Result<Self, LengthError> {
87 if value > Self::MAX_LENGTH.as_u32() {
88 Err(LengthError::OutOfMaxRange)
89 } else {
90 Ok(unsafe { Self::new_unchecked(value) })
91 }
92 }
93
94 #[inline(always)]
100 pub const fn try_from_usize(value: usize) -> Result<Self, LengthError> {
101 #[allow(clippy::cast_possible_truncation)]
102 if value > Self::MAX_LENGTH.as_usize() {
103 Err(LengthError::OutOfMaxRange)
104 } else {
105 Ok(unsafe { Self::new_unchecked(value as u32) })
106 }
107 }
108
109 #[inline(always)]
115 pub const fn try_from_i32(value: i32) -> Result<Self, LengthError> {
116 if value < 0 {
117 return Err(LengthError::Negative);
118 }
119
120 #[allow(clippy::cast_sign_loss)]
121 let value = value as u32;
122
123 Self::try_from_u32(value)
124 }
125
126 #[inline(always)]
128 #[must_use]
129 pub const fn as_u32(&self) -> u32 {
130 self.size
131 }
132
133 #[inline(always)]
135 #[must_use]
136 pub const fn as_usize(&self) -> usize {
137 self.size as usize
138 }
139}
140
141impl TryClone for Length {
142 type Error = Infallible;
143 fn try_clone(&self) -> Result<Self, Self::Error> {
144 Ok(*self)
145 }
146}
147
148impl TryFrom<i32> for Length {
149 type Error = LengthError;
150
151 fn try_from(value: i32) -> Result<Self, Self::Error> {
152 Self::try_from_i32(value)
153 }
154}
155
156impl TryFrom<u32> for Length {
157 type Error = LengthError;
158
159 fn try_from(value: u32) -> Result<Self, Self::Error> {
160 Self::try_from_u32(value)
161 }
162}
163
164impl TryFrom<usize> for Length {
165 type Error = LengthError;
166
167 fn try_from(value: usize) -> Result<Self, Self::Error> {
168 Self::try_from_usize(value)
169 }
170}
171
172impl From<Length> for u32 {
173 fn from(value: Length) -> Self {
174 value.as_u32()
175 }
176}
177
178impl From<Length> for usize {
179 fn from(value: Length) -> Self {
180 value.as_usize()
181 }
182}
183
184impl core::fmt::Display for Length {
185 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
186 self.as_u32().fmt(f)
187 }
188}
189
190const _: () = const {
191 assert!(size_of::<Length>() == 4, "Length is expected to be of size 4");
192};