Skip to content

Commit 0b008f8

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 6c4400f commit 0b008f8

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;
@@ -204,6 +207,12 @@ impl From<TryReserveError> for Error {
204207
}
205208
}
206209

210+
impl From<LayoutError> for Error {
211+
fn from(_: LayoutError) -> Error {
212+
Error::ENOMEM
213+
}
214+
}
215+
207216
/// A [`Result`] with an [`Error`] error type.
208217
///
209218
/// 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,
@@ -271,6 +274,44 @@ impl<T: ?Sized> Drop for Ref<T> {
271274
}
272275
}
273276

277+
impl<T> TryFrom<Vec<T>> for Ref<[T]> {
278+
type Error = Error;
279+
280+
fn try_from(mut v: Vec<T>) -> Result<Self> {
281+
let value_layout = Layout::array::<T>(v.len())?;
282+
let layout = Layout::new::<RefInner<()>>()
283+
.extend(value_layout)?
284+
.0
285+
.pad_to_align();
286+
// SAFETY: The layout size is guaranteed to be non-zero because `RefInner` contains the
287+
// reference count.
288+
let ptr = NonNull::new(unsafe { alloc(layout) }).ok_or(Error::ENOMEM)?;
289+
let inner =
290+
core::ptr::slice_from_raw_parts_mut(ptr.as_ptr() as _, v.len()) as *mut RefInner<[T]>;
291+
292+
// SAFETY: Just an FFI call that returns a `refcount_t` initialised to 1.
293+
let count = UnsafeCell::new(unsafe { rust_helper_refcount_new() });
294+
// SAFETY: `inner.refcount` is writable and properly aligned.
295+
unsafe { core::ptr::addr_of_mut!((*inner).refcount).write(count) };
296+
// SAFETY: The contents of `v` as readable and properly aligned; `inner.data` is writable
297+
// and properly aligned. There is no overlap between the two because `inner` is a new
298+
// allocation.
299+
unsafe {
300+
core::ptr::copy_nonoverlapping(
301+
v.as_ptr(),
302+
core::ptr::addr_of_mut!((*inner).data) as *mut [T] as *mut T,
303+
v.len(),
304+
)
305+
};
306+
// SAFETY: We're setting the new length to zero, so it is <= to capacity, and old_len..0 is
307+
// an empty range (so satisfies vacuously the requirement of being initialised).
308+
unsafe { v.set_len(0) };
309+
// SAFETY: We just created `inner` with a reference count of 1, which is owned by the new
310+
// `Ref` object.
311+
Ok(unsafe { Self::from_inner(NonNull::new(inner).unwrap()) })
312+
}
313+
}
314+
274315
/// A borrowed [`Ref`] with manually-managed lifetime.
275316
///
276317
/// # Invariants

0 commit comments

Comments
 (0)