Skip to content

Commit

Permalink
Merge pull request torvalds#467 from wedsonaf/ref-from-vec
Browse files Browse the repository at this point in the history
rust: implement `TryFrom<Vec<T>>` for `Ref<[T]>`.
  • Loading branch information
wedsonaf authored Oct 14, 2021
2 parents f109dd8 + 5294e75 commit 9027821
Show file tree
Hide file tree
Showing 2 changed files with 53 additions and 3 deletions.
11 changes: 10 additions & 1 deletion rust/kernel/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,10 @@

use crate::str::CStr;
use crate::{bindings, c_types};
use alloc::{alloc::AllocError, collections::TryReserveError};
use alloc::{
alloc::{AllocError, LayoutError},
collections::TryReserveError,
};
use core::convert::From;
use core::fmt;
use core::num::TryFromIntError;
Expand Down Expand Up @@ -385,6 +388,12 @@ impl From<TryReserveError> for Error {
}
}

impl From<LayoutError> for Error {
fn from(_: LayoutError) -> Error {
Error::ENOMEM
}
}

/// A [`Result`] with an [`Error`] error type.
///
/// To be used as the return type for functions that may fail.
Expand Down
45 changes: 43 additions & 2 deletions rust/kernel/sync/arc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,14 @@
//! [`Arc`]: https://doc.rust-lang.org/std/sync/struct.Arc.html

use crate::{bindings, Error, Result};
use alloc::alloc::{alloc, dealloc};
use alloc::{
alloc::{alloc, dealloc},
vec::Vec,
};
use core::{
alloc::Layout,
cell::UnsafeCell,
convert::AsRef,
convert::{AsRef, TryFrom},
marker::{PhantomData, Unsize},
mem::ManuallyDrop,
ops::Deref,
Expand Down Expand Up @@ -265,6 +268,44 @@ impl<T: ?Sized> Drop for Ref<T> {
}
}

impl<T> TryFrom<Vec<T>> for Ref<[T]> {
type Error = Error;

fn try_from(mut v: Vec<T>) -> Result<Self> {
let value_layout = Layout::array::<T>(v.len())?;
let layout = Layout::new::<RefInner<()>>()
.extend(value_layout)?
.0
.pad_to_align();
// SAFETY: The layout size is guaranteed to be non-zero because `RefInner` contains the
// reference count.
let ptr = NonNull::new(unsafe { alloc(layout) }).ok_or(Error::ENOMEM)?;
let inner =
core::ptr::slice_from_raw_parts_mut(ptr.as_ptr() as _, v.len()) as *mut RefInner<[T]>;

// SAFETY: Just an FFI call that returns a `refcount_t` initialised to 1.
let count = UnsafeCell::new(unsafe { bindings::REFCOUNT_INIT(1) });
// SAFETY: `inner.refcount` is writable and properly aligned.
unsafe { core::ptr::addr_of_mut!((*inner).refcount).write(count) };
// SAFETY: The contents of `v` as readable and properly aligned; `inner.data` is writable
// and properly aligned. There is no overlap between the two because `inner` is a new
// allocation.
unsafe {
core::ptr::copy_nonoverlapping(
v.as_ptr(),
core::ptr::addr_of_mut!((*inner).data) as *mut [T] as *mut T,
v.len(),
)
};
// SAFETY: We're setting the new length to zero, so it is <= to capacity, and old_len..0 is
// an empty range (so satisfies vacuously the requirement of being initialised).
unsafe { v.set_len(0) };
// SAFETY: We just created `inner` with a reference count of 1, which is owned by the new
// `Ref` object.
Ok(unsafe { Self::from_inner(NonNull::new(inner).unwrap()) })
}
}

/// A borrowed [`Ref`] with manually-managed lifetime.
///
/// # Invariants
Expand Down

0 comments on commit 9027821

Please sign in to comment.