Rollup merge of #95005 - ssomers:btree_static_assert, r=thomcc

BTree: evaluate static type-related check at compile time

`assert`s like the ones replaced here would only go off when you run the right test cases, if the code were ever incorrectly changed such that rhey would trigger. But [inspired on a nice forum question](https://users.rust-lang.org/t/compile-time-const-generic-parameter-check/69202), they can be checked at compile time.
This commit is contained in:
Guillaume Gomez 2022-08-26 14:08:43 +02:00 committed by GitHub
commit e3148dc7c4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

View File

@ -318,7 +318,7 @@ impl<BorrowType: marker::BorrowType, K, V, Type> NodeRef<BorrowType, K, V, Type>
pub fn ascend( pub fn ascend(
self, self,
) -> Result<Handle<NodeRef<BorrowType, K, V, marker::Internal>, marker::Edge>, Self> { ) -> Result<Handle<NodeRef<BorrowType, K, V, marker::Internal>, marker::Edge>, Self> {
assert!(BorrowType::PERMITS_TRAVERSAL); let _ = BorrowType::TRAVERSAL_PERMIT;
// We need to use raw pointers to nodes because, if BorrowType is marker::ValMut, // We need to use raw pointers to nodes because, if BorrowType is marker::ValMut,
// there might be outstanding mutable references to values that we must not invalidate. // there might be outstanding mutable references to values that we must not invalidate.
let leaf_ptr: *const _ = Self::as_leaf_ptr(&self); let leaf_ptr: *const _ = Self::as_leaf_ptr(&self);
@ -1003,7 +1003,7 @@ impl<BorrowType: marker::BorrowType, K, V>
/// `edge.descend().ascend().unwrap()` and `node.ascend().unwrap().descend()` should /// `edge.descend().ascend().unwrap()` and `node.ascend().unwrap().descend()` should
/// both, upon success, do nothing. /// both, upon success, do nothing.
pub fn descend(self) -> NodeRef<BorrowType, K, V, marker::LeafOrInternal> { pub fn descend(self) -> NodeRef<BorrowType, K, V, marker::LeafOrInternal> {
assert!(BorrowType::PERMITS_TRAVERSAL); let _ = BorrowType::TRAVERSAL_PERMIT;
// We need to use raw pointers to nodes because, if BorrowType is // We need to use raw pointers to nodes because, if BorrowType is
// marker::ValMut, there might be outstanding mutable references to // marker::ValMut, there might be outstanding mutable references to
// values that we must not invalidate. There's no worry accessing the // values that we must not invalidate. There's no worry accessing the
@ -1666,15 +1666,17 @@ pub enum Dying {}
pub struct ValMut<'a>(PhantomData<&'a mut ()>); pub struct ValMut<'a>(PhantomData<&'a mut ()>);
pub trait BorrowType { pub trait BorrowType {
// Whether node references of this borrow type allow traversing // If node references of this borrow type allow traversing to other
// to other nodes in the tree. // nodes in the tree, this constant can be evaluated. Thus reading it
const PERMITS_TRAVERSAL: bool = true; // serves as a compile-time assertion.
const TRAVERSAL_PERMIT: () = ();
} }
impl BorrowType for Owned { impl BorrowType for Owned {
// Traversal isn't needed, it happens using the result of `borrow_mut`. // Reject evaluation, because traversal isn't needed. Instead traversal
// happens using the result of `borrow_mut`.
// By disabling traversal, and only creating new references to roots, // By disabling traversal, and only creating new references to roots,
// we know that every reference of the `Owned` type is to a root node. // we know that every reference of the `Owned` type is to a root node.
const PERMITS_TRAVERSAL: bool = false; const TRAVERSAL_PERMIT: () = panic!();
} }
impl BorrowType for Dying {} impl BorrowType for Dying {}
impl<'a> BorrowType for Immut<'a> {} impl<'a> BorrowType for Immut<'a> {}