1use crate::aligned_bytes::{Alignment, Misaligned, A1, A2, A4, A8};
2use core::{borrow::Borrow, convert::TryFrom, fmt::Display, marker::PhantomData};
3
4#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
13pub struct AlignedOffset<A: Alignment>(usize, PhantomData<A>)
14where
15 Self: core::ops::BitOr,
16 <Self as core::ops::BitOr>::Output: Into<Self>;
17impl<A: Alignment> AlignedOffset<A> {
18 pub fn to_usize(&self) -> usize {
20 self.0
21 }
22 pub fn try_new(value: usize) -> Result<Self, Misaligned> {
29 if value % A::ALIGNMENT == 0 {
30 Ok(Self(value, PhantomData::<A> {}))
31 } else {
32 Err(Misaligned {})
33 }
34 }
35}
36
37pub fn align_offset<A: Alignment>(idx: usize) -> AlignedOffset<A> {
44 AlignedOffset::<A>(
45 (idx + A::ALIGNMENT - 1) & !(A::ALIGNMENT - 1),
46 PhantomData::<A> {},
47 )
48}
49
50impl<A: Alignment> Display for AlignedOffset<A> {
51 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
52 write!(f, "{}", self.0)
53 }
54}
55
56impl<A: Alignment> PartialEq<usize> for AlignedOffset<A> {
57 fn eq(&self, other: &usize) -> bool {
58 *other == self.0
59 }
60}
61impl<A: Alignment> PartialOrd<usize> for AlignedOffset<A> {
62 fn partial_cmp(&self, other: &usize) -> Option<core::cmp::Ordering> {
63 self.0.partial_cmp(other)
64 }
65}
66impl<A: Alignment> PartialEq<AlignedOffset<A>> for usize {
67 fn eq(&self, other: &AlignedOffset<A>) -> bool {
68 *self == other.0
69 }
70}
71impl<A: Alignment> PartialOrd<AlignedOffset<A>> for usize {
72 fn partial_cmp(&self, other: &AlignedOffset<A>) -> Option<core::cmp::Ordering> {
73 self.partial_cmp(&other.0)
74 }
75}
76impl<A: Alignment> TryFrom<usize> for AlignedOffset<A> {
77 type Error = Misaligned;
78 fn try_from(value: usize) -> Result<Self, Self::Error> {
79 Self::try_new(value)
80 }
81}
82impl<A: Alignment> Borrow<usize> for AlignedOffset<A> {
83 fn borrow(&self) -> &usize {
84 &self.0
85 }
86}
87impl<A: Alignment> From<AlignedOffset<A>> for usize {
88 fn from(value: AlignedOffset<A>) -> Self {
89 value.0
90 }
91}
92
93impl<A: Alignment> core::ops::BitOr for AlignedOffset<A> {
96 type Output = AlignedOffset<A>;
97 fn bitor(self, rhs: Self) -> Self::Output {
98 AlignedOffset::<A>(self.0 | rhs.0, PhantomData::<A> {})
101 }
102}
103
104impl<A: Alignment> core::ops::Add for AlignedOffset<A> {
107 type Output = AlignedOffset<A>;
108 fn add(self, rhs: Self) -> Self::Output {
109 AlignedOffset::<A>(self.0 + rhs.0, PhantomData::<A> {})
112 }
113}
114
115macro_rules! impl_bitor {
116 ($x:ty, $y:ty, $min:ty) => {
117 impl core::ops::BitOr<AlignedOffset<$x>> for AlignedOffset<$y> {
118 type Output = AlignedOffset<$min>;
119 fn bitor(self, rhs: AlignedOffset<$x>) -> AlignedOffset<$min> {
120 AlignedOffset::<$min>(self.0 | rhs.0, PhantomData::<$min> {})
123 }
124 }
125 };
126}
127macro_rules! narrowing {
128 ($big:ty, $small:ty) => {
129 impl_bitor!($big, $small, $small);
130 impl_bitor!($small, $big, $small);
131 impl From<AlignedOffset<$big>> for AlignedOffset<$small> {
132 fn from(v: AlignedOffset<$big>) -> Self {
133 AlignedOffset::<$small>(v.0, PhantomData)
134 }
135 }
136 };
137}
138
139narrowing!(A2, A1);
140narrowing!(A4, A1);
141narrowing!(A8, A1);
142narrowing!(A4, A2);
143narrowing!(A8, A2);
144narrowing!(A8, A4);
145
146#[cfg(test)]
147#[cfg(feature = "alloc")]
148mod tests {
149 use super::*;
150 use crate::aligned_bytes::{A2, A4};
151 use core::convert::TryInto;
152
153 #[test]
154 fn test() {
155 let x: Result<AlignedOffset<A2>, Misaligned> = 3usize.try_into();
156 assert!(x.is_err());
157
158 let x: AlignedOffset<A2> = 0usize.try_into().unwrap();
159 assert_eq!(x.to_usize(), 0usize);
160
161 let x: AlignedOffset<A4> = 8usize.try_into().unwrap();
162 assert_eq!(x.to_usize(), 8usize);
163
164 assert_eq!(align_offset::<A4>(0).to_usize(), 0);
165 assert_eq!(align_offset::<A4>(1).to_usize(), 4);
166 assert_eq!(align_offset::<A4>(4).to_usize(), 4);
167 assert_eq!(align_offset::<A4>(6).to_usize(), 8);
168 assert_eq!(align_offset::<A4>(7).to_usize(), 8);
169 assert_eq!(align_offset::<A4>(8).to_usize(), 8);
170 assert_eq!(align_offset::<A4>(9).to_usize(), 12);
171 }
172}