Skip to content

Commit 5294e75

Browse files
committed
rust: implement TryFrom<Vec<T>> for Ref<[T]>.
This allows the conversion from a vector to a reference-counted array. A similar conversion is currently used in binder to convert to an `Arc`-based array; we'll switch it to be `Ref`-based. Signed-off-by: Wedson Almeida Filho <[email protected]>
1 parent f109dd8 commit 5294e75

File tree

2 files changed

+53
-3
lines changed

2 files changed

+53
-3
lines changed

rust/kernel/error.rs

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,10 @@
66
77
use crate::str::CStr;
88
use crate::{bindings, c_types};
9-
use alloc::{alloc::AllocError, collections::TryReserveError};
9+
use alloc::{
10+
alloc::{AllocError, LayoutError},
11+
collections::TryReserveError,
12+
};
1013
use core::convert::From;
1114
use core::fmt;
1215
use core::num::TryFromIntError;
@@ -385,6 +388,12 @@ impl From<TryReserveError> for Error {
385388
}
386389
}
387390

391+
impl From<LayoutError> for Error {
392+
fn from(_: LayoutError) -> Error {
393+
Error::ENOMEM
394+
}
395+
}
396+
388397
/// A [`Result`] with an [`Error`] error type.
389398
///
390399
/// To be used as the return type for functions that may fail.

rust/kernel/sync/arc.rs

Lines changed: 43 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,14 @@
1616
//! [`Arc`]: https://doc.rust-lang.org/std/sync/struct.Arc.html
1717
1818
use crate::{bindings, Error, Result};
19-
use alloc::alloc::{alloc, dealloc};
19+
use alloc::{
20+
alloc::{alloc, dealloc},
21+
vec::Vec,
22+
};
2023
use core::{
2124
alloc::Layout,
2225
cell::UnsafeCell,
23-
convert::AsRef,
26+
convert::{AsRef, TryFrom},
2427
marker::{PhantomData, Unsize},
2528
mem::ManuallyDrop,
2629
ops::Deref,
@@ -265,6 +268,44 @@ impl<T: ?Sized> Drop for Ref<T> {
265268
}
266269
}
267270

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+
268309
/// A borrowed [`Ref`] with manually-managed lifetime.
269310
///
270311
/// # Invariants

0 commit comments

Comments
 (0)