osom_lib_primitives/
length.rs1use osom_lib_reprc::macros::reprc;
4
5#[reprc]
10#[repr(transparent)]
11#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Copy, Default)]
12#[must_use]
13pub struct Length {
14 size: u32,
15}
16
17#[reprc]
19#[repr(u8)]
20#[derive(Debug, PartialEq, Eq, Clone, Copy)]
21pub enum LengthError {
22 Negative = 0,
24
25 OutOfMaxRange = 1,
27}
28
29impl Length {
30 pub const SAFE_MARGIN: u32 = 2048;
37
38 pub const MAX_LENGTH: Self = const {
41 const I32_MAX: u32 = i32::MAX as u32;
42 assert!(Self::SAFE_MARGIN >= 64, "SAFE_MARGIN has to be at least 64.");
43 assert!(
44 Self::SAFE_MARGIN < I32_MAX,
45 "SAFE_MARGIN has to be smaller than i32::MAX"
46 );
47 unsafe { Self::new_unchecked(I32_MAX - Self::SAFE_MARGIN) }
48 };
49
50 pub const ZERO: Self = unsafe { Self::new_unchecked(0) };
52
53 pub const ONE: Self = unsafe { Self::new_unchecked(1) };
55
56 #[inline(always)]
64 pub const unsafe fn new_unchecked(value: u32) -> Self {
65 Self { size: value }
66 }
67
68 #[inline(always)]
74 pub const fn try_from_u32(value: u32) -> Result<Self, LengthError> {
75 if value > Self::MAX_LENGTH.as_u32() {
76 Err(LengthError::OutOfMaxRange)
77 } else {
78 Ok(unsafe { Self::new_unchecked(value) })
79 }
80 }
81
82 #[inline(always)]
88 pub const fn try_from_usize(value: usize) -> Result<Self, LengthError> {
89 #[allow(clippy::cast_possible_truncation)]
90 if value > Self::MAX_LENGTH.as_usize() {
91 Err(LengthError::OutOfMaxRange)
92 } else {
93 Ok(unsafe { Self::new_unchecked(value as u32) })
94 }
95 }
96
97 #[inline(always)]
103 pub const fn try_from_i32(value: i32) -> Result<Self, LengthError> {
104 if value < 0 {
105 return Err(LengthError::Negative);
106 }
107
108 #[allow(clippy::cast_sign_loss)]
109 let value = value as u32;
110
111 Self::try_from_u32(value)
112 }
113
114 #[inline(always)]
116 #[must_use]
117 pub const fn as_u32(&self) -> u32 {
118 self.size
119 }
120
121 #[inline(always)]
123 #[must_use]
124 pub const fn as_usize(&self) -> usize {
125 self.size as usize
126 }
127}
128
129impl TryFrom<i32> for Length {
130 type Error = LengthError;
131
132 fn try_from(value: i32) -> Result<Self, Self::Error> {
133 Self::try_from_i32(value)
134 }
135}
136
137impl TryFrom<u32> for Length {
138 type Error = LengthError;
139
140 fn try_from(value: u32) -> Result<Self, Self::Error> {
141 Self::try_from_u32(value)
142 }
143}
144
145impl TryFrom<usize> for Length {
146 type Error = LengthError;
147
148 fn try_from(value: usize) -> Result<Self, Self::Error> {
149 Self::try_from_usize(value)
150 }
151}
152
153impl From<Length> for u32 {
154 fn from(value: Length) -> Self {
155 value.as_u32()
156 }
157}
158
159impl From<Length> for usize {
160 fn from(value: Length) -> Self {
161 value.as_usize()
162 }
163}
164
165impl core::fmt::Display for Length {
166 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
167 self.as_u32().fmt(f)
168 }
169}
170
171const _: () = const {
172 assert!(size_of::<Length>() == 4, "Length is expected to be of size 4");
173};