|
4 | 4 |
|
5 | 5 | use alloc::{alloc::Layout, string::String}; |
6 | 6 | use core::{ |
7 | | - mem::{align_of, forget}, |
| 7 | + mem::align_of, |
8 | 8 | ops::{Deref, DerefMut}, |
9 | 9 | ptr::NonNull, |
10 | 10 | }; |
@@ -167,30 +167,63 @@ impl DerefMut for BoxedString { |
167 | 167 | } |
168 | 168 |
|
169 | 169 | impl From<String> for BoxedString { |
| 170 | + #[allow(unsafe_code, unused_mut)] |
170 | 171 | fn from(mut s: String) -> Self { |
171 | 172 | if s.is_empty() { |
172 | 173 | Self::new(s.capacity()) |
173 | 174 | } else { |
174 | | - // If the `String`'s buffer isn't word aligned, we can't reuse it. |
175 | | - if check_alignment(s.as_ptr()) { |
176 | | - return Self::from_str(s.capacity(), &s); |
| 175 | + #[cfg(has_allocator)] |
| 176 | + { |
| 177 | + // TODO: Use String::into_raw_parts when stabilised, meanwhile let's get unsafe |
| 178 | + let len = s.len(); |
| 179 | + let cap = s.capacity(); |
| 180 | + #[allow(unsafe_code)] |
| 181 | + let ptr = unsafe { NonNull::new_unchecked(s.as_mut_ptr()) }; |
| 182 | + let old_layout = Layout::array::<u8>(cap).unwrap(); |
| 183 | + |
| 184 | + use alloc::alloc::Allocator; |
| 185 | + let allocator = alloc::alloc::Global; |
| 186 | + if let Ok(aligned_ptr) = |
| 187 | + unsafe { allocator.grow(ptr, old_layout, Self::layout_for(cap)) } |
| 188 | + { |
| 189 | + core::mem::forget(s); |
| 190 | + Self { |
| 191 | + cap, |
| 192 | + len, |
| 193 | + ptr: aligned_ptr.cast(), |
| 194 | + } |
| 195 | + } else { |
| 196 | + Self::from_str(cap, &s) |
| 197 | + } |
177 | 198 | } |
178 | | - // TODO: Use String::into_raw_parts when stabilised, meanwhile let's get unsafe |
179 | | - let len = s.len(); |
180 | | - let cap = s.capacity(); |
181 | | - #[allow(unsafe_code)] |
182 | | - let ptr = unsafe { NonNull::new_unchecked(s.as_mut_ptr()) }; |
183 | | - forget(s); |
184 | | - Self { cap, len, ptr } |
| 199 | + #[cfg(not(has_allocator))] |
| 200 | + Self::from_str(s.capacity(), &s) |
185 | 201 | } |
186 | 202 | } |
187 | 203 | } |
188 | 204 |
|
189 | 205 | impl From<BoxedString> for String { |
| 206 | + #[allow(unsafe_code)] |
190 | 207 | fn from(s: BoxedString) -> Self { |
191 | | - #[allow(unsafe_code)] |
192 | | - let out = unsafe { String::from_raw_parts(s.ptr.as_ptr(), s.len(), s.capacity()) }; |
193 | | - forget(s); |
194 | | - out |
| 208 | + #[cfg(has_allocator)] |
| 209 | + { |
| 210 | + let ptr = s.ptr; |
| 211 | + let cap = s.cap; |
| 212 | + let len = s.len; |
| 213 | + let new_layout = Layout::array::<u8>(cap).unwrap(); |
| 214 | + |
| 215 | + use alloc::alloc::Allocator; |
| 216 | + let allocator = alloc::alloc::Global; |
| 217 | + if let Ok(aligned_ptr) = |
| 218 | + unsafe { allocator.grow(ptr, BoxedString::layout_for(cap), new_layout) } |
| 219 | + { |
| 220 | + core::mem::forget(s); |
| 221 | + unsafe { String::from_raw_parts(aligned_ptr.as_ptr().cast(), len, cap) } |
| 222 | + } else { |
| 223 | + String::from(s.deref()) |
| 224 | + } |
| 225 | + } |
| 226 | + #[cfg(not(has_allocator))] |
| 227 | + String::from(s.deref()) |
195 | 228 | } |
196 | 229 | } |
0 commit comments