|
16 | 16 | //! [`Arc`]: https://doc.rust-lang.org/std/sync/struct.Arc.html
|
17 | 17 |
|
18 | 18 | use crate::{bindings, Error, Result};
|
19 |
| -use alloc::alloc::{alloc, dealloc}; |
| 19 | +use alloc::{ |
| 20 | + alloc::{alloc, dealloc}, |
| 21 | + vec::Vec, |
| 22 | +}; |
20 | 23 | use core::{
|
21 | 24 | alloc::Layout,
|
22 | 25 | cell::UnsafeCell,
|
23 |
| - convert::AsRef, |
| 26 | + convert::{AsRef, TryFrom}, |
24 | 27 | marker::{PhantomData, Unsize},
|
25 | 28 | mem::ManuallyDrop,
|
26 | 29 | ops::Deref,
|
@@ -265,6 +268,44 @@ impl<T: ?Sized> Drop for Ref<T> {
|
265 | 268 | }
|
266 | 269 | }
|
267 | 270 |
|
| 271 | +impl<T> TryFrom<Vec<T>> for Ref<[T]> { |
| 272 | + type Error = Error; |
| 273 | + |
| 274 | + fn try_from(mut v: Vec<T>) -> Result<Self> { |
| 275 | + let value_layout = Layout::array::<T>(v.len())?; |
| 276 | + let layout = Layout::new::<RefInner<()>>() |
| 277 | + .extend(value_layout)? |
| 278 | + .0 |
| 279 | + .pad_to_align(); |
| 280 | + // SAFETY: The layout size is guaranteed to be non-zero because `RefInner` contains the |
| 281 | + // reference count. |
| 282 | + let ptr = NonNull::new(unsafe { alloc(layout) }).ok_or(Error::ENOMEM)?; |
| 283 | + let inner = |
| 284 | + core::ptr::slice_from_raw_parts_mut(ptr.as_ptr() as _, v.len()) as *mut RefInner<[T]>; |
| 285 | + |
| 286 | + // SAFETY: Just an FFI call that returns a `refcount_t` initialised to 1. |
| 287 | + let count = UnsafeCell::new(unsafe { bindings::REFCOUNT_INIT(1) }); |
| 288 | + // SAFETY: `inner.refcount` is writable and properly aligned. |
| 289 | + unsafe { core::ptr::addr_of_mut!((*inner).refcount).write(count) }; |
| 290 | + // SAFETY: The contents of `v` as readable and properly aligned; `inner.data` is writable |
| 291 | + // and properly aligned. There is no overlap between the two because `inner` is a new |
| 292 | + // allocation. |
| 293 | + unsafe { |
| 294 | + core::ptr::copy_nonoverlapping( |
| 295 | + v.as_ptr(), |
| 296 | + core::ptr::addr_of_mut!((*inner).data) as *mut [T] as *mut T, |
| 297 | + v.len(), |
| 298 | + ) |
| 299 | + }; |
| 300 | + // SAFETY: We're setting the new length to zero, so it is <= to capacity, and old_len..0 is |
| 301 | + // an empty range (so satisfies vacuously the requirement of being initialised). |
| 302 | + unsafe { v.set_len(0) }; |
| 303 | + // SAFETY: We just created `inner` with a reference count of 1, which is owned by the new |
| 304 | + // `Ref` object. |
| 305 | + Ok(unsafe { Self::from_inner(NonNull::new(inner).unwrap()) }) |
| 306 | + } |
| 307 | +} |
| 308 | + |
268 | 309 | /// A borrowed [`Ref`] with manually-managed lifetime.
|
269 | 310 | ///
|
270 | 311 | /// # Invariants
|
|
0 commit comments