plain/
methods.rs

1
2use core::{mem, slice};
3
4use {Error, Plain};
5
6/// Check if a byte slice is aligned suitably for type T.
7#[inline]
8pub fn is_aligned<T>(bytes: &[u8]) -> bool {
9    ((bytes.as_ptr() as usize) % mem::align_of::<T>()) == 0
10}
11
12#[inline(always)]
13fn check_alignment<T>(bytes: &[u8]) -> Result<(), Error> {
14    if is_aligned::<T>(bytes) {
15        Ok(())
16    } else {
17        Err(Error::BadAlignment)
18    }
19}
20
21#[inline(always)]
22fn check_length<T>(bytes: &[u8], len: usize) -> Result<(), Error> {
23    if mem::size_of::<T>() > 0 && (bytes.len() / mem::size_of::<T>()) < len {
24        Err(Error::TooShort)
25    } else {
26        Ok(())
27    }
28}
29
30/// Interpret data as bytes. Not safe for data with padding.
31#[inline(always)]
32pub unsafe fn as_bytes<S>(s: &S) -> &[u8]
33where
34    S: ?Sized,
35{
36    let bptr = s as *const S as *const u8;
37    let bsize = mem::size_of_val(s);
38    slice::from_raw_parts(bptr, bsize)
39}
40
41/// Interpret data as mutable bytes.
42/// Reading is not safe for data with padding. Writing is ok.
43#[inline(always)]
44pub unsafe fn as_mut_bytes<S>(s: &mut S) -> &mut [u8]
45where
46    S: Plain + ?Sized,
47{
48    let bptr = s as *mut S as *mut u8;
49    let bsize = mem::size_of_val(s);
50    slice::from_raw_parts_mut(bptr, bsize)
51}
52
53/// Safely converts a byte slice to a reference.
54///
55/// However, if the byte slice is not long enough
56/// to contain target type, or if it doesn't
57/// satisfy the type's alignment requirements,
58/// the function returns an error.
59///
60/// The function will not fail when the
61/// byte slice is longer than necessary, since it is
62/// a common practice to interpret the beginning of
63/// a slice as a fixed-size header.
64///
65/// In many cases it is preferrable to allocate
66/// a value/slice of the target type and use
67/// [`copy_from_bytes()`](fn.copy_from_bytes.html) to copy
68/// data instead. That way, any issues with alignment
69/// are implicitly avoided.
70///
71#[inline]
72pub fn from_bytes<T>(bytes: &[u8]) -> Result<&T, Error>
73where
74    T: Plain,
75{
76    try!(check_alignment::<T>(bytes));
77    try!(check_length::<T>(bytes, 1));
78    Ok(unsafe { &*(bytes.as_ptr() as *const T) })
79}
80
81/// Similar to [`from_bytes()`](fn.from_bytes.html),
82/// except that the output is a slice of T, instead
83/// of a reference to a single T. All concerns about
84/// alignment also apply here, but size is handled
85/// differently.
86///
87/// The result slice's length is set to be
88/// `bytes.len() / size_of::<T>()`, and there
89/// are no requirements for input size. I.e.
90/// the result may be empty slice, and the input
91/// slice doesn't necessarily have to end on `T`'s
92/// boundary. The latter has pragmatic reasons: If the
93/// length of the array is not known in advance,
94/// e.g. if it's terminated by a special element,
95/// it's perfectly legal to turn the whole rest
96/// of data into `&[T]` and set the proper length
97/// after inspecting the array.
98///
99/// In many cases it is preferrable to allocate
100/// a value/slice of the target type and use
101/// [`copy_from_bytes()`](fn.copy_from_bytes.html) to copy
102/// data instead. That way, any issues with alignment
103/// are implicitly avoided.
104///
105#[inline]
106pub fn slice_from_bytes<T>(bytes: &[u8]) -> Result<&[T], Error>
107where
108    T: Plain,
109{
110    let len = bytes.len() / mem::size_of::<T>();
111    slice_from_bytes_len(bytes, len)
112}
113
114
115/// Same as [`slice_from_bytes()`](fn.slice_from_bytes.html),
116/// except that it takes explicit length of the result slice.
117///
118/// If the input slice cannot satisfy the length, returns error.
119/// The input slice is allowed to be longer than necessary.
120///
121#[inline]
122pub fn slice_from_bytes_len<T>(bytes: &[u8], len: usize) -> Result<&[T], Error>
123where
124    T: Plain,
125{
126    try!(check_alignment::<T>(bytes));
127    try!(check_length::<T>(bytes, len));
128    Ok(unsafe {
129        slice::from_raw_parts(bytes.as_ptr() as *const T, len)
130    })
131}
132
133/// See [`from_bytes()`](fn.from_bytes.html).
134///
135/// Does the same, except with mutable references.
136///
137#[inline]
138pub fn from_mut_bytes<T>(bytes: &mut [u8]) -> Result<&mut T, Error>
139where
140    T: Plain,
141{
142    try!(check_alignment::<T>(bytes));
143    try!(check_length::<T>(bytes, 1));
144    Ok(unsafe { &mut *(bytes.as_mut_ptr() as *mut T) })
145}
146
147/// See [`slice_from_bytes()`](fn.slice_from_bytes.html).
148///
149/// Does the same, except with mutable references.
150///
151#[inline]
152pub fn slice_from_mut_bytes<T>(bytes: &mut [u8]) -> Result<&mut [T], Error>
153where
154    T: Plain,
155{
156    let len = bytes.len() / mem::size_of::<T>();
157    slice_from_mut_bytes_len(bytes, len)
158}
159
160/// See [`slice_from_bytes_len()`](fn.slice_from_bytes_len.html).
161///
162/// Does the same, except with mutable references.
163///
164#[inline]
165pub fn slice_from_mut_bytes_len<T>(bytes: &mut [u8], len: usize) -> Result<&mut [T], Error>
166where
167    T: Plain,
168{
169    try!(check_alignment::<T>(bytes));
170    try!(check_length::<T>(bytes, len));
171    Ok(unsafe {
172        slice::from_raw_parts_mut(bytes.as_ptr() as *mut T, len)
173    })
174}
175
176/// Copies data from a byte slice into existing memory.
177/// Suitable when [`from_bytes()`](fn.from_bytes.html) would normally
178/// be used, but the data is not aligned properly in memory.
179///
180/// For an example how to use it, see crate-level documentation.
181///
182#[inline]
183pub fn copy_from_bytes<T>(into: &mut T, bytes: &[u8]) -> Result<(), Error>
184where
185    T: Plain + ?Sized,
186{
187    let sz = mem::size_of_val(into);
188
189    if bytes.len() < sz {
190        return Err(Error::TooShort);
191    }
192
193    unsafe {
194        as_mut_bytes(into).copy_from_slice(&bytes[..sz]);
195    }
196
197    Ok(())
198}