mju_bits/
storage.rs

1/*
2storage.rs - Implements generic storage supporting bitfield access
3
4Copyright 2019-2020 David Kern <david@mju.io>
5
6Licensed under the Apache License, Version 2.0 (the "License");
7you may not use this file except in compliance with the License.
8You may obtain a copy of the License at
9
10    http://www.apache.org/licenses/LICENSE-2.0
11
12Unless required by applicable law or agreed to in writing, software
13distributed under the License is distributed on an "AS IS" BASIS,
14WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15See the License for the specific language governing permissions and
16limitations under the License.
17*/
18
19//! Wrapper type for unsigned primitives allowing typed bitfield manipulation
20
21use core::convert::TryFrom;
22use core::fmt;
23use core::marker::PhantomData;
24use crate::bitfield::BitFieldTrait;
25
26/// Bitfield access functionality
27///
28/// Note: this trait is sealed against implementation outside this crate. This
29/// restriction will be lifted once the API has stabilized.
30
31pub trait BitFieldAccess : private::Sealed
32{
33    /// Returns a copy of `self` masked by `mask` and shifted right by `shift`
34    fn get_bitfield(&self, mask: Self, shift: u32) -> Self;
35
36    /// Shifts value left by `shift` and replaces bits in `self` using `mask`.
37    fn set_bitfield(&mut self, mask: Self, shift: u32, value: Self);
38}
39
40// seal the BitFieldAccess trait
41mod private {
42    pub trait Sealed {}
43
44    impl Sealed for u8 { }
45    impl Sealed for u16 { }
46    impl Sealed for u32 { }
47    impl Sealed for u64 { }
48    impl Sealed for usize { }
49}
50
51/// Stores a primitive value uniquely tagged with type `TMarker` and allows
52/// bitfield access to the value through specializations of the `BitField` type.
53#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug, Default)]
54pub struct Storage<TMarker, TData>
55where TData: BitFieldAccess
56{
57    /// The actual data
58    data: TData,
59
60    /// Zero-sized field to make the concrete struct type unique
61    owner: PhantomData<TMarker>
62}
63
64macro_rules! impl_storage {
65    ($type:ident) => {
66        impl<TMarker> Storage<TMarker, $type>
67        {
68            /// Construct a new Storage
69            pub fn new() -> Self {
70                Storage {
71                    data: $type::default(),
72                    owner: PhantomData,
73                }
74            }
75        
76            /// Gets the BitField value from storage
77            pub fn get<TBitField>(&self) -> $type
78            where
79                TBitField: BitFieldTrait<Owner=Self>
80            {
81                self.data.get_bitfield(TBitField::MASK as $type, TBitField::SHIFT)
82            }
83        
84            /// Sets the BitField value in storage
85            pub fn set<TBitField>(&mut self, value: $type)
86            where
87                TBitField: BitFieldTrait<Owner=Self>
88            {
89                self.data.set_bitfield(TBitField::MASK as $type, TBitField::SHIFT, value);
90            }
91        }
92
93        impl BitFieldAccess for $type {
94            fn get_bitfield(&self, mask: Self, shift: u32) -> Self {
95                (self & mask as $type).wrapping_shr(shift)
96            }
97        
98            fn set_bitfield(&mut self, mask: Self, shift: u32, field: Self) {
99                *self = *self & !mask as $type | (field.wrapping_shl(shift) & mask as $type);
100            }
101        }
102
103        impl<TMarker> fmt::Display for Storage<TMarker, $type>
104        {
105            fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
106                write!(f, "{}", self.data)
107            }
108        }
109
110        impl<TMarker> fmt::UpperHex for Storage<TMarker, $type>
111        {
112            fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
113                fmt::UpperHex::fmt(&self, f)
114            }
115        }
116
117        impl<TMarker> fmt::LowerHex for Storage<TMarker, $type>
118        {
119            fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
120                fmt::LowerHex::fmt(&self, f)
121            }
122        }
123
124        impl<TMarker> fmt::Octal for Storage<TMarker, $type>
125        {
126            fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
127                fmt::Octal::fmt(&self, f)
128            }
129        }
130
131        impl<TMarker> fmt::Binary for Storage<TMarker, $type>
132        {
133            fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
134                fmt::Binary::fmt(&self, f)
135            }
136        }
137    };
138}
139
140macro_rules! impl_from {
141    ($type:ident, $from:ident) => {
142        impl<TMarker> From<$from> for Storage<TMarker, $type>
143        {
144            fn from(value: $from) -> Self {
145                Self {
146                    data: value.into(),
147                    owner: PhantomData,
148                }
149            }
150        }
151    };
152}
153
154macro_rules! impl_tryfrom {
155    ($type:ident, $from:ident) => {
156        impl<TMarker> TryFrom<$from> for Storage<TMarker, $type>
157        {
158            type Error = <$type as TryFrom<$from>>::Error;
159
160            fn try_from(value: $from) -> Result<Self, <$type as TryFrom<$from>>::Error> {
161                Ok(Self {
162                    data: $type::try_from(value)?,
163                    owner: PhantomData,
164                })
165            }
166        }
167    };
168}
169
170impl_storage!(u8);
171impl_from!(u8, u8);
172impl_tryfrom!(u8, u16);
173impl_tryfrom!(u8, u32);
174impl_tryfrom!(u8, u64);
175impl_tryfrom!(u8, usize);
176
177impl_storage!(u16);
178impl_from!(u16, u8);
179impl_from!(u16, u16);
180impl_tryfrom!(u16, u32);
181impl_tryfrom!(u16, u64);
182impl_tryfrom!(u16, usize);
183
184impl_storage!(u32);
185impl_from!(u32, u8);
186impl_from!(u32, u16);
187impl_from!(u32, u32);
188impl_tryfrom!(u32, u64);
189impl_tryfrom!(u32, usize);
190
191impl_storage!(u64);
192impl_from!(u64, u8);
193impl_from!(u64, u16);
194impl_from!(u64, u32);
195impl_from!(u64, u64);
196impl_tryfrom!(u64, usize);
197
198impl_storage!(usize);
199impl_from!(usize, u8);
200impl_from!(usize, u16);
201impl_tryfrom!(usize, u32);
202impl_tryfrom!(usize, u64);
203impl_from!(usize, usize);
204
205#[cfg(test)]
206mod test {
207    use super::*;
208
209    #[test]
210    fn test_send() {
211        struct Marker;
212
213        fn assert_send<T: Send>() {}
214        assert_send::<Storage<Marker, u8>>();
215        assert_send::<Storage<Marker, u16>>();
216        assert_send::<Storage<Marker, u32>>();
217        assert_send::<Storage<Marker, u64>>();
218        assert_send::<Storage<Marker, usize>>();
219    }
220
221    #[test]
222    fn test_sync() {
223        struct Marker;
224
225        fn assert_sync<T: Sync>() {}
226        assert_sync::<Storage<Marker, u8>>();
227        assert_sync::<Storage<Marker, u16>>();
228        assert_sync::<Storage<Marker, u32>>();
229        assert_sync::<Storage<Marker, u64>>();
230        assert_sync::<Storage<Marker, usize>>();
231    }
232}