@@ -68,6 +68,33 @@ pub trait Align {
6868 /// Required memory alignment for this type
6969 fn alignment ( ) -> usize ;
7070
71+ /// Calculate the offset from `val` necessary to make it aligned,
72+ /// rounding up. For example, if `val` is 1 and the alignment is 8,
73+ /// this will return 7. Returns 0 if `val == 0`.
74+ fn offset_up_to_alignment ( val : usize ) -> usize {
75+ assert ! ( Self :: alignment( ) != 0 ) ;
76+ let r = val % Self :: alignment ( ) ;
77+ if r == 0 {
78+ 0
79+ } else {
80+ Self :: alignment ( ) - r
81+ }
82+ }
83+
84+ /// Round `val` up so that it is aligned.
85+ fn round_up_to_alignment ( val : usize ) -> usize {
86+ val + Self :: offset_up_to_alignment ( val)
87+ }
88+
89+ /// Get a subslice of `buf` where the address of the first element
90+ /// is aligned. Returns `None` if no element of the buffer is
91+ /// aligned.
92+ fn align_buf ( buf : & mut [ u8 ] ) -> Option < & mut [ u8 ] > {
93+ let addr = buf. as_ptr ( ) as usize ;
94+ let offset = Self :: offset_up_to_alignment ( addr) ;
95+ buf. get_mut ( offset..)
96+ }
97+
7198 /// Assert that some storage is correctly aligned for this type
7299 fn assert_aligned ( storage : & mut [ u8 ] ) {
73100 if !storage. is_empty ( ) {
@@ -97,3 +124,49 @@ pub use self::strs::{CStr16, CStr8, FromSliceWithNulError, FromStrWithBufError};
97124mod owned_strs;
98125#[ cfg( feature = "exts" ) ]
99126pub use self :: owned_strs:: { CString16 , FromStrError } ;
127+
128+ #[ cfg( test) ]
129+ mod tests {
130+ use super :: * ;
131+
132+ #[ test]
133+ fn test_alignment ( ) {
134+ struct X { }
135+
136+ impl Align for X {
137+ fn alignment ( ) -> usize {
138+ 4
139+ }
140+ }
141+
142+ assert_eq ! ( X :: offset_up_to_alignment( 0 ) , 0 ) ;
143+ assert_eq ! ( X :: offset_up_to_alignment( 1 ) , 3 ) ;
144+ assert_eq ! ( X :: offset_up_to_alignment( 2 ) , 2 ) ;
145+ assert_eq ! ( X :: offset_up_to_alignment( 3 ) , 1 ) ;
146+ assert_eq ! ( X :: offset_up_to_alignment( 4 ) , 0 ) ;
147+ assert_eq ! ( X :: offset_up_to_alignment( 5 ) , 3 ) ;
148+ assert_eq ! ( X :: offset_up_to_alignment( 6 ) , 2 ) ;
149+ assert_eq ! ( X :: offset_up_to_alignment( 7 ) , 1 ) ;
150+ assert_eq ! ( X :: offset_up_to_alignment( 8 ) , 0 ) ;
151+
152+ assert_eq ! ( X :: round_up_to_alignment( 0 ) , 0 ) ;
153+ assert_eq ! ( X :: round_up_to_alignment( 1 ) , 4 ) ;
154+ assert_eq ! ( X :: round_up_to_alignment( 2 ) , 4 ) ;
155+ assert_eq ! ( X :: round_up_to_alignment( 3 ) , 4 ) ;
156+ assert_eq ! ( X :: round_up_to_alignment( 4 ) , 4 ) ;
157+ assert_eq ! ( X :: round_up_to_alignment( 5 ) , 8 ) ;
158+ assert_eq ! ( X :: round_up_to_alignment( 6 ) , 8 ) ;
159+ assert_eq ! ( X :: round_up_to_alignment( 7 ) , 8 ) ;
160+ assert_eq ! ( X :: round_up_to_alignment( 8 ) , 8 ) ;
161+
162+ // Get an intentionally mis-aligned buffer.
163+ let mut buffer = [ 0u8 ; 16 ] ;
164+ let mut buffer = & mut buffer[ ..] ;
165+ if ( buffer. as_ptr ( ) as usize ) % X :: alignment ( ) == 0 {
166+ buffer = & mut buffer[ 1 ..] ;
167+ }
168+
169+ let buffer = X :: align_buf ( buffer) . unwrap ( ) ;
170+ X :: assert_aligned ( buffer) ;
171+ }
172+ }
0 commit comments