Skip to content

Commit a2e7f8b

Browse files
committedSep 7, 2024
Add NonNull convenience methods to Box
1 parent 2699de6 commit a2e7f8b

File tree

1 file changed

+223
-0
lines changed

1 file changed

+223
-0
lines changed
 

‎alloc/src/boxed.rs

+223
Original file line numberDiff line numberDiff line change
@@ -1059,6 +1059,59 @@ impl<T: ?Sized> Box<T> {
10591059
pub unsafe fn from_raw(raw: *mut T) -> Self {
10601060
unsafe { Self::from_raw_in(raw, Global) }
10611061
}
1062+
1063+
/// Constructs a box from a `NonNull` pointer.
1064+
///
1065+
/// After calling this function, the `NonNull` pointer is owned by
1066+
/// the resulting `Box`. Specifically, the `Box` destructor will call
1067+
/// the destructor of `T` and free the allocated memory. For this
1068+
/// to be safe, the memory must have been allocated in accordance
1069+
/// with the [memory layout] used by `Box` .
1070+
///
1071+
/// # Safety
1072+
///
1073+
/// This function is unsafe because improper use may lead to
1074+
/// memory problems. For example, a double-free may occur if the
1075+
/// function is called twice on the same `NonNull` pointer.
1076+
///
1077+
/// The safety conditions are described in the [memory layout] section.
1078+
///
1079+
/// # Examples
1080+
///
1081+
/// Recreate a `Box` which was previously converted to a `NonNull`
1082+
/// pointer using [`Box::into_non_null`]:
1083+
/// ```
1084+
/// #![feature(box_vec_non_null)]
1085+
///
1086+
/// let x = Box::new(5);
1087+
/// let non_null = Box::into_non_null(x);
1088+
/// let x = unsafe { Box::from_non_null(non_null) };
1089+
/// ```
1090+
/// Manually create a `Box` from scratch by using the global allocator:
1091+
/// ```
1092+
/// #![feature(box_vec_non_null)]
1093+
///
1094+
/// use std::alloc::{alloc, Layout};
1095+
/// use std::ptr::NonNull;
1096+
///
1097+
/// unsafe {
1098+
/// let non_null = NonNull::new(alloc(Layout::new::<i32>()).cast::<i32>())
1099+
/// .expect("allocation failed");
1100+
/// // In general .write is required to avoid attempting to destruct
1101+
/// // the (uninitialized) previous contents of `non_null`.
1102+
/// non_null.write(5);
1103+
/// let x = Box::from_non_null(non_null);
1104+
/// }
1105+
/// ```
1106+
///
1107+
/// [memory layout]: self#memory-layout
1108+
/// [`Layout`]: crate::Layout
1109+
#[unstable(feature = "box_vec_non_null", reason = "new API", issue = "none")]
1110+
#[inline]
1111+
#[must_use = "call `drop(Box::from_non_null(ptr))` if you intend to drop the `Box`"]
1112+
pub unsafe fn from_non_null(ptr: NonNull<T>) -> Self {
1113+
unsafe { Self::from_raw(ptr.as_ptr()) }
1114+
}
10621115
}
10631116

10641117
impl<T: ?Sized, A: Allocator> Box<T, A> {
@@ -1116,6 +1169,61 @@ impl<T: ?Sized, A: Allocator> Box<T, A> {
11161169
Box(unsafe { Unique::new_unchecked(raw) }, alloc)
11171170
}
11181171

1172+
/// Constructs a box from a `NonNull` pointer in the given allocator.
1173+
///
1174+
/// After calling this function, the `NonNull` pointer is owned by
1175+
/// the resulting `Box`. Specifically, the `Box` destructor will call
1176+
/// the destructor of `T` and free the allocated memory. For this
1177+
/// to be safe, the memory must have been allocated in accordance
1178+
/// with the [memory layout] used by `Box` .
1179+
///
1180+
/// # Safety
1181+
///
1182+
/// This function is unsafe because improper use may lead to
1183+
/// memory problems. For example, a double-free may occur if the
1184+
/// function is called twice on the same raw pointer.
1185+
///
1186+
///
1187+
/// # Examples
1188+
///
1189+
/// Recreate a `Box` which was previously converted to a `NonNull` pointer
1190+
/// using [`Box::into_non_null_with_allocator`]:
1191+
/// ```
1192+
/// #![feature(allocator_api, box_vec_non_null)]
1193+
///
1194+
/// use std::alloc::System;
1195+
///
1196+
/// let x = Box::new_in(5, System);
1197+
/// let (non_null, alloc) = Box::into_non_null_with_allocator(x);
1198+
/// let x = unsafe { Box::from_non_null_in(non_null, alloc) };
1199+
/// ```
1200+
/// Manually create a `Box` from scratch by using the system allocator:
1201+
/// ```
1202+
/// #![feature(allocator_api, box_vec_non_null, slice_ptr_get)]
1203+
///
1204+
/// use std::alloc::{Allocator, Layout, System};
1205+
///
1206+
/// unsafe {
1207+
/// let non_null = System.allocate(Layout::new::<i32>())?.cast::<i32>();
1208+
/// // In general .write is required to avoid attempting to destruct
1209+
/// // the (uninitialized) previous contents of `non_null`.
1210+
/// non_null.write(5);
1211+
/// let x = Box::from_non_null_in(non_null, System);
1212+
/// }
1213+
/// # Ok::<(), std::alloc::AllocError>(())
1214+
/// ```
1215+
///
1216+
/// [memory layout]: self#memory-layout
1217+
/// [`Layout`]: crate::Layout
1218+
#[unstable(feature = "allocator_api", issue = "32838")]
1219+
// #[unstable(feature = "box_vec_non_null", reason = "new API", issue = "none")]
1220+
#[rustc_const_unstable(feature = "const_box", issue = "92521")]
1221+
#[inline]
1222+
pub const unsafe fn from_non_null_in(raw: NonNull<T>, alloc: A) -> Self {
1223+
// SAFETY: guaranteed by the caller.
1224+
unsafe { Box::from_raw_in(raw.as_ptr(), alloc) }
1225+
}
1226+
11191227
/// Consumes the `Box`, returning a wrapped raw pointer.
11201228
///
11211229
/// The pointer will be properly aligned and non-null.
@@ -1171,6 +1279,66 @@ impl<T: ?Sized, A: Allocator> Box<T, A> {
11711279
unsafe { addr_of_mut!(*&mut *Self::into_raw_with_allocator(b).0) }
11721280
}
11731281

1282+
/// Consumes the `Box`, returning a wrapped `NonNull` pointer.
1283+
///
1284+
/// The pointer will be properly aligned.
1285+
///
1286+
/// After calling this function, the caller is responsible for the
1287+
/// memory previously managed by the `Box`. In particular, the
1288+
/// caller should properly destroy `T` and release the memory, taking
1289+
/// into account the [memory layout] used by `Box`. The easiest way to
1290+
/// do this is to convert the `NonNull` pointer back into a `Box` with the
1291+
/// [`Box::from_non_null`] function, allowing the `Box` destructor to
1292+
/// perform the cleanup.
1293+
///
1294+
/// Note: this is an associated function, which means that you have
1295+
/// to call it as `Box::into_non_null(b)` instead of `b.into_non_null()`.
1296+
/// This is so that there is no conflict with a method on the inner type.
1297+
///
1298+
/// # Examples
1299+
/// Converting the `NonNull` pointer back into a `Box` with [`Box::from_non_null`]
1300+
/// for automatic cleanup:
1301+
/// ```
1302+
/// #![feature(box_vec_non_null)]
1303+
///
1304+
/// let x = Box::new(String::from("Hello"));
1305+
/// let non_null = Box::into_non_null(x);
1306+
/// let x = unsafe { Box::from_non_null(non_null) };
1307+
/// ```
1308+
/// Manual cleanup by explicitly running the destructor and deallocating
1309+
/// the memory:
1310+
/// ```
1311+
/// #![feature(box_vec_non_null)]
1312+
///
1313+
/// use std::alloc::{dealloc, Layout};
1314+
///
1315+
/// let x = Box::new(String::from("Hello"));
1316+
/// let non_null = Box::into_non_null(x);
1317+
/// unsafe {
1318+
/// non_null.drop_in_place();
1319+
/// dealloc(non_null.as_ptr().cast::<u8>(), Layout::new::<String>());
1320+
/// }
1321+
/// ```
1322+
/// Note: This is equivalent to the following:
1323+
/// ```
1324+
/// #![feature(box_vec_non_null)]
1325+
///
1326+
/// let x = Box::new(String::from("Hello"));
1327+
/// let non_null = Box::into_non_null(x);
1328+
/// unsafe {
1329+
/// drop(Box::from_non_null(non_null));
1330+
/// }
1331+
/// ```
1332+
///
1333+
/// [memory layout]: self#memory-layout
1334+
#[must_use = "losing the pointer will leak memory"]
1335+
#[unstable(feature = "box_vec_non_null", reason = "new API", issue = "none")]
1336+
#[inline]
1337+
pub fn into_non_null(b: Self) -> NonNull<T> {
1338+
// SAFETY: `Box` is guaranteed to be non-null.
1339+
unsafe { NonNull::new_unchecked(Self::into_raw(b)) }
1340+
}
1341+
11741342
/// Consumes the `Box`, returning a wrapped raw pointer and the allocator.
11751343
///
11761344
/// The pointer will be properly aligned and non-null.
@@ -1232,6 +1400,61 @@ impl<T: ?Sized, A: Allocator> Box<T, A> {
12321400
(ptr, alloc)
12331401
}
12341402

1403+
/// Consumes the `Box`, returning a wrapped `NonNull` pointer and the allocator.
1404+
///
1405+
/// The pointer will be properly aligned.
1406+
///
1407+
/// After calling this function, the caller is responsible for the
1408+
/// memory previously managed by the `Box`. In particular, the
1409+
/// caller should properly destroy `T` and release the memory, taking
1410+
/// into account the [memory layout] used by `Box`. The easiest way to
1411+
/// do this is to convert the `NonNull` pointer back into a `Box` with the
1412+
/// [`Box::from_non_null_in`] function, allowing the `Box` destructor to
1413+
/// perform the cleanup.
1414+
///
1415+
/// Note: this is an associated function, which means that you have
1416+
/// to call it as `Box::into_non_null_with_allocator(b)` instead of
1417+
/// `b.into_non_null_with_allocator()`. This is so that there is no
1418+
/// conflict with a method on the inner type.
1419+
///
1420+
/// # Examples
1421+
/// Converting the `NonNull` pointer back into a `Box` with
1422+
/// [`Box::from_non_null_in`] for automatic cleanup:
1423+
/// ```
1424+
/// #![feature(allocator_api, box_vec_non_null)]
1425+
///
1426+
/// use std::alloc::System;
1427+
///
1428+
/// let x = Box::new_in(String::from("Hello"), System);
1429+
/// let (non_null, alloc) = Box::into_non_null_with_allocator(x);
1430+
/// let x = unsafe { Box::from_non_null_in(non_null, alloc) };
1431+
/// ```
1432+
/// Manual cleanup by explicitly running the destructor and deallocating
1433+
/// the memory:
1434+
/// ```
1435+
/// #![feature(allocator_api, box_vec_non_null)]
1436+
///
1437+
/// use std::alloc::{Allocator, Layout, System};
1438+
///
1439+
/// let x = Box::new_in(String::from("Hello"), System);
1440+
/// let (non_null, alloc) = Box::into_non_null_with_allocator(x);
1441+
/// unsafe {
1442+
/// non_null.drop_in_place();
1443+
/// alloc.deallocate(non_null.cast::<u8>(), Layout::new::<String>());
1444+
/// }
1445+
/// ```
1446+
///
1447+
/// [memory layout]: self#memory-layout
1448+
#[must_use = "losing the pointer will leak memory"]
1449+
#[unstable(feature = "allocator_api", issue = "32838")]
1450+
// #[unstable(feature = "box_vec_non_null", reason = "new API", issue = "none")]
1451+
#[inline]
1452+
pub fn into_non_null_with_allocator(b: Self) -> (NonNull<T>, A) {
1453+
let (ptr, alloc) = Box::into_raw_with_allocator(b);
1454+
// SAFETY: `Box` is guaranteed to be non-null.
1455+
unsafe { (NonNull::new_unchecked(ptr), alloc) }
1456+
}
1457+
12351458
#[unstable(
12361459
feature = "ptr_internals",
12371460
issue = "none",

0 commit comments

Comments
 (0)