Received: by 2002:ab2:6309:0:b0:1fb:d597:ff75 with SMTP id s9csp447791lqt; Thu, 6 Jun 2024 08:12:13 -0700 (PDT) X-Forwarded-Encrypted: i=3; AJvYcCWwUFwZBz9O2LoDSn6AfWFLyHyumZuQIq6KKu2zZcp6LTUxGqFZYdYPfWYjolR6/mWq3Q3Gt2W4Cgc5a49KOF5Sw7S/dRhjjUsr50Qcfw== X-Google-Smtp-Source: AGHT+IF8HDbTZ8RAwkrdX99In/JEjl5QB8wy8JLcHLuAXe3NfO6C8Du7LD2qMnKBye+EZhgwfDV7 X-Received: by 2002:a1f:7c0f:0:b0:4eb:2232:6074 with SMTP id 71dfb90a1353d-4eb3a401e7cmr6140361e0c.4.1717686733412; Thu, 06 Jun 2024 08:12:13 -0700 (PDT) ARC-Seal: i=2; a=rsa-sha256; t=1717686733; cv=pass; d=google.com; s=arc-20160816; b=dqaLxI7kjU5vQCz0dhjnVkMi7Ih8JlqcCgpP73b/TuG1SDVP0dLu//mMViLARErjBq AriDVUP6GIoLbMqgkcxOGFxjz1dEKLZ6WwZRMiFZ8lnjJ24zZC3BnhFprA4i7SFYrBrJ x8S5yIYcHSk6eJC4aa63CMihPC8hq0kY415MZtPIZQQkpgCnPOemxhAg89wF97yCHMVi Ukxg3kPGOU/TZyuiwBAIdl3hN95Gmna0OJOf5aLoXYSHQZEQDk790MqZPZ4HaAbjA5TC zfEWHQxex3HTz4+OCfWQRNpsn8u7Ckh3u0/DJUdDea311CezCebzt8uFUANIiEaufXOW 083Q== ARC-Message-Signature: i=2; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=cc:to:from:subject:message-id:references:mime-version :list-unsubscribe:list-subscribe:list-id:precedence:in-reply-to:date :dkim-signature; bh=yVrgIvaHSGbHkrR8NyIHNZn//P+8xowqH7qWXONQdGk=; fh=1cv9Qk7BM7qnD6K9wM7tIjVRdCwqH9K6gfP3H4ggXNk=; b=wjn8UARtHsaUjsHYI1VQiKjCMmZXPDUv/+5NiH6bqBPcAGUgr3+xER90oN12kBnMlV XrEHu0QyK4k/4lK+QwDkSu9dtcN7QWFHfKJ9iPEMVVGoD/HrEgnp7xMvxW8bJZ43rH9d Pb6IPx1fd/OYSnVXHhqAG9DWcfM49GifxbFBNALJPLX/DHD7f8nyLdtP0oGD6UvTKgvg GVc2zer3zZRaMvcWhnaRQqJ+Op4vST0oAWQDrTiIly901fmRtpY1Dzfkhzaxt4uu/gY8 NehBJcttYaMVMHQmVoQKuI15NwMfOxbDN152v0VS/ogrhv5gZRELQNNnWFRNSDPVdE6W u78g==; dara=google.com ARC-Authentication-Results: i=2; mx.google.com; dkim=pass header.i=@google.com header.s=20230601 header.b=d5QJCqIq; arc=pass (i=1 spf=pass spfdomain=flex--mattgilbride.bounces.google.com dkim=pass dkdomain=google.com dmarc=pass fromdomain=google.com); spf=pass (google.com: domain of linux-kernel+bounces-204526-linux.lists.archive=gmail.com@vger.kernel.org designates 2604:1380:45d1:ec00::1 as permitted sender) smtp.mailfrom="linux-kernel+bounces-204526-linux.lists.archive=gmail.com@vger.kernel.org"; dmarc=pass (p=REJECT sp=REJECT dis=NONE) header.from=google.com Return-Path: Received: from ny.mirrors.kernel.org (ny.mirrors.kernel.org. [2604:1380:45d1:ec00::1]) by mx.google.com with ESMTPS id 71dfb90a1353d-4eb4ad68142si321506e0c.249.2024.06.06.08.12.13 for (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 06 Jun 2024 08:12:13 -0700 (PDT) Received-SPF: pass (google.com: domain of linux-kernel+bounces-204526-linux.lists.archive=gmail.com@vger.kernel.org designates 2604:1380:45d1:ec00::1 as permitted sender) client-ip=2604:1380:45d1:ec00::1; Authentication-Results: mx.google.com; dkim=pass header.i=@google.com header.s=20230601 header.b=d5QJCqIq; arc=pass (i=1 spf=pass spfdomain=flex--mattgilbride.bounces.google.com dkim=pass dkdomain=google.com dmarc=pass fromdomain=google.com); spf=pass (google.com: domain of linux-kernel+bounces-204526-linux.lists.archive=gmail.com@vger.kernel.org designates 2604:1380:45d1:ec00::1 as permitted sender) smtp.mailfrom="linux-kernel+bounces-204526-linux.lists.archive=gmail.com@vger.kernel.org"; dmarc=pass (p=REJECT sp=REJECT dis=NONE) header.from=google.com Received: from smtp.subspace.kernel.org (wormhole.subspace.kernel.org [52.25.139.140]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ny.mirrors.kernel.org (Postfix) with ESMTPS id 1396A1C24D67 for ; Thu, 6 Jun 2024 15:12:13 +0000 (UTC) Received: from localhost.localdomain (localhost.localdomain [127.0.0.1]) by smtp.subspace.kernel.org (Postfix) with ESMTP id 310171A0DE8; Thu, 6 Jun 2024 14:50:33 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b="d5QJCqIq" Received: from mail-yw1-f202.google.com (mail-yw1-f202.google.com [209.85.128.202]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id C40B81A01D7 for ; Thu, 6 Jun 2024 14:50:28 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.128.202 ARC-Seal:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1717685431; cv=none; b=IQ+3il0bG5fnG7KexkvqLjhzfokCPeJmR4rqZQXMe9Wh7ohAG1nN0tOLwaQCC4YfS9FzGVjSPUmlb6civIqHo4rsdzPpb+BjQavgbs0xCOCIPgDm9jnDv4+Veg5V+7OnGbu9cIer/Jso6JbAlRBt/TaTJ9fojYc9yQ9oeJkkoGU= ARC-Message-Signature:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1717685431; c=relaxed/simple; bh=6EG3QOfdwARKfFCejHHg6mBqrcpobBc7q9qUj/fnYvM=; h=Date:In-Reply-To:Mime-Version:References:Message-ID:Subject:From: To:Cc:Content-Type; b=Wnn9IwyBMAHfEra+hND3AaFJcq1vq2DDcSRnG74FKvm5niK0zd0jg5rjo/lGabcPI5b/6yEo1ZFpgKrmcX1m8GB7snO13Pt6Sy9tOY9UIP1KFFdoqR/ewOqfnd1k/XOwBA+pxqXgIlnE0GBh3brh27iPcGlfH/BiAOQfigJX+WI= ARC-Authentication-Results:i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com; spf=pass smtp.mailfrom=flex--mattgilbride.bounces.google.com; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b=d5QJCqIq; arc=none smtp.client-ip=209.85.128.202 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=flex--mattgilbride.bounces.google.com Received: by mail-yw1-f202.google.com with SMTP id 00721157ae682-62a248f46aaso16656677b3.0 for ; Thu, 06 Jun 2024 07:50:28 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20230601; t=1717685428; x=1718290228; darn=vger.kernel.org; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:from:to:cc:subject:date:message-id:reply-to; bh=yVrgIvaHSGbHkrR8NyIHNZn//P+8xowqH7qWXONQdGk=; b=d5QJCqIqAe5DNv8yHvmvjj3MVqBP6mobihQc9WyJ32qtLPkoj+4594GUZo4SER481j HS5EqgRla3BL2pt+z6v7Hq4Ogkg7phQNgfQxgFYr6ujytxiEjwHw2Aa4EvlqgYXypU0l Sg3pPf0mjnaQ66ZEiu8RITezm19caxk+/j2amyHtNhoFik6cL0Q4qIYqIn63BIR0p28/ ROyJEgu677bucUn/PaKUXA+AaSn6G/wSosxJFahexZCmHO8BhI5npi70mC8LduWXuFUk Lb+/wF9EUL2EUsHLZXmOIlyOxO/5yfxnEjqVuii2AdOnlSH39mTvDUcMZLEjXdhhJSN4 HMrw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1717685428; x=1718290228; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=yVrgIvaHSGbHkrR8NyIHNZn//P+8xowqH7qWXONQdGk=; b=IEMHGWSJ37HzzLXgsnNGcX+FGmuVbtmlSmkeZiZau0LrF6+oSrsLSM9isjJ6L8GA+8 POYX/XumcNAmDD+XOnuoSfZjz4U5BK7g6YuHL/IVMmCvtPO95hvtnlBjgsNuBvKhF2Lv S1q578N7J0+gu+6o/tGgD3zaG1arrsX+LDmf38rVLz3h0wrERQY1IrIbm4LaonOqs3cJ I7sF3NE350yn77HcZGff0mB6bv9f7Na775jKBbGMSoFO2GY2Y4q/f/my+R/ayxBMJWGa qyBUrbSDNxDHiSGgMx2qGhbdiikxU2Nj0UqPrV5wqHdgfAZGIm5wrtJxBovZdbBRAcOz FXlg== X-Forwarded-Encrypted: i=1; AJvYcCX9W3kf6Bjcyj3od+VQCzRlx4wuDtHTSJfFPgFBsLDEVkE4bNSArXE/LdhTqChagUvi5p2d19Qv9IRRnOmCu2EIutXWwgtO0Bs4qAss X-Gm-Message-State: AOJu0Yy9YDENvtaJeEMhgvQ/hovh/dsfWkGRPdzockwvGINwzfvpRnSc d7GMrv9/6wn6tkefi/0k8mzTc/8N7I2phH1khN3QeKB/vgFPTokabtdoqdgqdYbqtqdSgyjI88W D+XfcX6QdC2A8DIG/UK39YtBnjA== X-Received: from mattgilbride.c.googlers.com ([fda3:e722:ac3:cc00:2b:7d90:c0a8:2ac5]) (user=mattgilbride job=sendgmr) by 2002:a25:84cc:0:b0:dfa:57e8:a37 with SMTP id 3f1490d57ef6-dfacad239f1mr353011276.13.1717685427811; Thu, 06 Jun 2024 07:50:27 -0700 (PDT) Date: Thu, 06 Jun 2024 14:50:09 +0000 In-Reply-To: <20240606-b4-rbtree-v5-0-96fe1a0e97c0@google.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: Mime-Version: 1.0 References: <20240606-b4-rbtree-v5-0-96fe1a0e97c0@google.com> X-Mailer: b4 0.12.4 Message-ID: <20240606-b4-rbtree-v5-6-96fe1a0e97c0@google.com> Subject: [PATCH v5 6/6] rust: rbtree: add `RBTree::entry` From: Matt Gilbride To: Miguel Ojeda , Alex Gaynor , Wedson Almeida Filho , Boqun Feng , Gary Guo , "=?utf-8?q?Bj=C3=B6rn_Roy_Baron?=" , Benno Lossin , Andreas Hindborg , Alice Ryhl , Greg Kroah-Hartman , "=?utf-8?q?Arve_Hj=C3=B8nnev=C3=A5g?=" , Todd Kjos , Martijn Coenen , Joel Fernandes , Carlos Llamas , Suren Baghdasaryan , Christian Brauner Cc: Rob Landley , Davidlohr Bueso , Michel Lespinasse , rust-for-linux@vger.kernel.org, linux-kernel@vger.kernel.org, Matt Gilbride Content-Type: text/plain; charset="utf-8" From: Alice Ryhl This mirrors the entry API [1] from the Rust standard library on `RBTree`. This API can be used to access the entry at a specific key and make modifications depending on whether the key is vacant or occupied. This API is useful because it can often be used to avoid traversing the tree multiple times. This is used by binder to look up and conditionally access or insert a value, depending on whether it is there or not [2]. Link: https://doc.rust-lang.org/stable/std/collections/btree_map/enum.Entry.html [1] Link: https://android-review.googlesource.com/c/kernel/common/+/2849906 [2] Signed-off-by: Alice Ryhl Tested-by: Alice Ryhl Signed-off-by: Matt Gilbride --- rust/kernel/rbtree.rs | 295 +++++++++++++++++++++++++++++++++++++------------- 1 file changed, 221 insertions(+), 74 deletions(-) diff --git a/rust/kernel/rbtree.rs b/rust/kernel/rbtree.rs index cf90f23b20f6..228c5467d88c 100644 --- a/rust/kernel/rbtree.rs +++ b/rust/kernel/rbtree.rs @@ -297,12 +297,18 @@ pub fn try_create_and_insert( /// key/value pair). Returns [`None`] if a node with the same key didn't already exist. /// /// This function always succeeds. - pub fn insert(&mut self, RBTreeNode { node }: RBTreeNode) -> Option> { - let node = Box::into_raw(node); - // SAFETY: `node` is valid at least until we call `Box::from_raw`, which only happens when - // the node is removed or replaced. - let node_links = unsafe { addr_of_mut!((*node).links) }; + pub fn insert(&mut self, node: RBTreeNode) -> Option> { + match self.raw_entry(&node.node.key) { + RawEntry::Occupied(entry) => Some(entry.replace(node)), + RawEntry::Vacant(entry) => { + entry.insert(node); + None + } + } + } + fn raw_entry(&mut self, key: &K) -> RawEntry<'_, K, V> { + // The returned `RawEntry` is used to call either `rb_link_node` or `rb_replace_node`. // The parameters of `rb_link_node` are as follows: // - `node`: A pointer to an uninitialized node being inserted. // - `parent`: A pointer to an existing node in the tree. One of its child pointers must be @@ -322,61 +328,52 @@ pub fn insert(&mut self, RBTreeNode { node }: RBTreeNode) -> Option`. + let node = unsafe { container_of!(curr, Node, links) }; - // We need to determine whether `node` should be the left or right child of `parent`, - // so we will compare with the `key` field of `parent` a.k.a. `this` below. - // - // SAFETY: By the type invariant of `Self`, all non-null `rb_node` pointers stored in `self` - // point to the links field of `Node` objects. - let this = unsafe { container_of!(parent, Node, links) }; - - // SAFETY: `this` is a non-null node so it is valid by the type invariants. `node` is - // valid until the node is removed. - match unsafe { (*node).key.cmp(&(*this).key) } { - // We would like `node` to be the left child of `parent`. Move to this child to check - // whether we can use it, or continue searching, at the next iteration. - // - // SAFETY: `parent` is a non-null node so it is valid by the type invariants. - Ordering::Less => child_field_of_parent = unsafe { &mut (*parent).rb_left }, - // We would like `node` to be the right child of `parent`. Move to this child to check - // whether we can use it, or continue searching, at the next iteration. - // - // SAFETY: `parent` is a non-null node so it is valid by the type invariants. - Ordering::Greater => child_field_of_parent = unsafe { &mut (*parent).rb_right }, + // SAFETY: `node` is a non-null node so it is valid by the type invariants. + match key.cmp(unsafe { &(*node).key }) { + // SAFETY: `curr` is a non-null node so it is valid by the type invariants. + Ordering::Less => child_field_of_parent = unsafe { &mut (*curr).rb_left }, + // SAFETY: `curr` is a non-null node so it is valid by the type invariants. + Ordering::Greater => child_field_of_parent = unsafe { &mut (*curr).rb_right }, Ordering::Equal => { - // There is an existing node in the tree with this key, and that node is - // parent. Thus, we are replacing parent with a new node. - // - // INVARIANT: We are replacing an existing node with a new one, which is valid. - // It remains valid because we "forgot" it with `Box::into_raw`. - // SAFETY: All pointers are non-null and valid. - unsafe { bindings::rb_replace_node(parent, node_links, &mut self.root) }; - - // INVARIANT: The node is being returned and the caller may free it, however, - // it was removed from the tree. So the invariants still hold. - return Some(RBTreeNode { - // SAFETY: `this` was a node in the tree, so it is valid. - node: unsafe { Box::from_raw(this.cast_mut()) }, - }); + return RawEntry::Occupied(OccupiedEntry { + rbtree: self, + node_links: curr, + }) } } + parent = curr; } - // INVARIANT: We are linking in a new node, which is valid. It remains valid because we - // "forgot" it with `Box::into_raw`. - // SAFETY: All pointers are non-null and valid (`*child_field_of_parent` is null, but `child_field_of_parent` is a - // mutable reference). - unsafe { bindings::rb_link_node(node_links, parent, child_field_of_parent) }; + RawEntry::Vacant(RawVacantEntry { + parent, + child_field_of_parent, + rbtree: self, + }) + } - // SAFETY: All pointers are valid. `node` has just been inserted into the tree. - unsafe { bindings::rb_insert_color(node_links, &mut self.root) }; - None + /// Gets the given key's corresponding entry in the map for in-place manipulation. + pub fn entry(&mut self, key: K) -> Entry<'_, K, V> { + match self.raw_entry(&key) { + RawEntry::Occupied(entry) => Entry::Occupied(entry), + RawEntry::Vacant(entry) => Entry::Vacant(VacantEntry { raw: entry, key }), + } + } + + /// Used for accessing the given node, if it exists. + pub fn find_mut(&mut self, key: &K) -> Option> { + match self.raw_entry(key) { + RawEntry::Occupied(entry) => Some(entry), + RawEntry::Vacant(_entry) => None, + } } - /// Returns a node with the given key, if one exists. - fn find(&self, key: &K) -> Option>> { + /// Returns a reference to the value corresponding to the key. + pub fn get(&self, key: &K) -> Option<&V> { let mut node = self.root.rb_node; while !node.is_null() { // SAFETY: By the type invariant of `Self`, all non-null `rb_node` pointers stored in `self` @@ -388,47 +385,30 @@ fn find(&self, key: &K) -> Option>> { Ordering::Less => unsafe { (*node).rb_left }, // SAFETY: `node` is a non-null node so it is valid by the type invariants. Ordering::Greater => unsafe { (*node).rb_right }, - Ordering::Equal => return NonNull::new(this.cast_mut()), + // SAFETY: `node` is a non-null node so it is valid by the type invariants. + Ordering::Equal => return Some(unsafe { &(*this).value }), } } None } - /// Returns a reference to the value corresponding to the key. - pub fn get(&self, key: &K) -> Option<&V> { - // SAFETY: The `find` return value is a node in the tree, so it is valid. - self.find(key).map(|node| unsafe { &node.as_ref().value }) - } - /// Returns a mutable reference to the value corresponding to the key. pub fn get_mut(&mut self, key: &K) -> Option<&mut V> { - // SAFETY: The `find` return value is a node in the tree, so it is valid. - self.find(key) - .map(|mut node| unsafe { &mut node.as_mut().value }) + self.find_mut(key).map(|node| node.into_mut()) } /// Removes the node with the given key from the tree. /// /// It returns the node that was removed if one exists, or [`None`] otherwise. - fn remove_node(&mut self, key: &K) -> Option> { - let mut node = self.find(key)?; - - // SAFETY: The `find` return value is a node in the tree, so it is valid. - unsafe { bindings::rb_erase(&mut node.as_mut().links, &mut self.root) }; - - // INVARIANT: The node is being returned and the caller may free it, however, it was - // removed from the tree. So the invariants still hold. - Some(RBTreeNode { - // SAFETY: The `find` return value was a node in the tree, so it is valid. - node: unsafe { Box::from_raw(node.as_ptr()) }, - }) + pub fn remove_node(&mut self, key: &K) -> Option> { + self.find_mut(key).map(OccupiedEntry::remove_node) } /// Removes the node with the given key from the tree. /// /// It returns the value that was removed if one exists, or [`None`] otherwise. pub fn remove(&mut self, key: &K) -> Option { - self.remove_node(key).map(|node| node.node.value) + self.find_mut(key).map(OccupiedEntry::remove) } /// Returns a cursor over the tree nodes based on the given key. @@ -1125,6 +1105,173 @@ unsafe impl Send for RBTreeNode {} // [`RBTreeNode`] without synchronization. unsafe impl Sync for RBTreeNode {} +impl RBTreeNode { + /// Drop the key and value, but keep the allocation. + /// + /// It then becomes a reservation that can be re-initialised into a different node (i.e., with + /// a different key and/or value). + /// + /// The existing key and value are dropped in-place as part of this operation, that is, memory + /// may be freed (but only for the key/value; memory for the node itself is kept for reuse). + pub fn into_reservation(self) -> RBTreeNodeReservation { + RBTreeNodeReservation { + node: Box::drop_contents(self.node), + } + } +} + +/// A view into a single entry in a map, which may either be vacant or occupied. +/// +/// This enum is constructed from the [`RBTree::entry`]. +/// +/// [`entry`]: fn@RBTree::entry +pub enum Entry<'a, K, V> { + /// This [`RBTree`] does not have a node with this key. + Vacant(VacantEntry<'a, K, V>), + /// This [`RBTree`] already has a node with this key. + Occupied(OccupiedEntry<'a, K, V>), +} + +/// Like [`Entry`], except that it doesn't have ownership of the key. +enum RawEntry<'a, K, V> { + Vacant(RawVacantEntry<'a, K, V>), + Occupied(OccupiedEntry<'a, K, V>), +} + +/// A view into a vacant entry in a [`RBTree`]. It is part of the [`Entry`] enum. +pub struct VacantEntry<'a, K, V> { + key: K, + raw: RawVacantEntry<'a, K, V>, +} + +/// Like [`VacantEntry`], but doesn't hold on to the key.a +/// +/// # Invariants +/// - `parent` may be null if the new node becomes the root. +/// - `child_field_of_parent` is a valid pointer to the left-child or right-child of `parent`. If `parent` is +/// null, it is a pointer to the root of the [`RBTree`]. +struct RawVacantEntry<'a, K, V> { + rbtree: &'a mut RBTree, + /// The node that will become the parent of the new node if we insert one. + parent: *mut bindings::rb_node, + /// This points to the left-child or right-child field of `parent`, or `root` if `parent` is + /// null. + child_field_of_parent: *mut *mut bindings::rb_node, +} + +impl<'a, K, V> RawVacantEntry<'a, K, V> { + /// Inserts the given node into the [`RBTree`] at this entry. + /// + /// The `node` must have a key such that inserting it here does not break the ordering of this + /// [`RBTree`]. + fn insert(self, node: RBTreeNode) -> &'a mut V { + let node = Box::into_raw(node.node); + + // SAFETY: `node` is valid at least until we call `Box::from_raw`, which only happens when + // the node is removed or replaced. + let node_links = unsafe { addr_of_mut!((*node).links) }; + + // INVARIANT: We are linking in a new node, which is valid. It remains valid because we + // "forgot" it with `Box::into_raw`. + // SAFETY: The type invariants of `RawVacantEntry` are exactly the safety requirements of `rb_link_node`. + unsafe { bindings::rb_link_node(node_links, self.parent, self.child_field_of_parent) }; + + // SAFETY: All pointers are valid. `node` has just been inserted into the tree. + unsafe { bindings::rb_insert_color(node_links, &mut self.rbtree.root) }; + + // SAFETY: The node is valid until we remove it from the tree. + unsafe { &mut (*node).value } + } +} + +impl<'a, K, V> VacantEntry<'a, K, V> { + /// Inserts the given node into the [`RBTree`] at this entry. + pub fn insert(self, value: V, reservation: RBTreeNodeReservation) -> &'a mut V { + self.raw.insert(reservation.into_node(self.key, value)) + } +} + +/// A view into an occupied entry in a [`RBTree`]. It is part of the [`Entry`] enum. +/// +/// # Invariants +/// - `node_links` is a valid, non-null pointer to a tree node in `self.rbtree` +pub struct OccupiedEntry<'a, K, V> { + rbtree: &'a mut RBTree, + /// The node that this entry corresponds to. + node_links: *mut bindings::rb_node, +} + +impl<'a, K, V> OccupiedEntry<'a, K, V> { + fn node_ptr(&self) -> *mut Node { + // SAFETY: By the type invariant of `Self`, all `node_links` pointers stored in `self` + // point to the links field of `Node` objects. + unsafe { container_of!(self.node_links, Node, links) }.cast_mut() + } + + /// Gets a reference to the value in the entry. + pub fn get(&self) -> &V { + // SAFETY: `self.node_ptr` produces a valid pointer to a node in the tree. + unsafe { &(*self.node_ptr()).value } + } + + /// Gets a mutable reference to the value in the entry. + pub fn get_mut(&mut self) -> &mut V { + // SAFETY: `self.node_ptr` produces a valid pointer to a node in the tree. + unsafe { &mut (*self.node_ptr()).value } + } + + /// Converts the entry into a mutable reference to its value. + /// + /// If you need multiple references to the `OccupiedEntry`, see [`self#get_mut`]. + pub fn into_mut(self) -> &'a mut V { + // SAFETY: `self.node_ptr` produces a valid pointer to a node in the tree. + unsafe { &mut (*self.node_ptr()).value } + } + + /// Remove this entry from the [`RBTree`]. + pub fn remove_node(self) -> RBTreeNode { + // SAFETY: The node is a node in the tree, so it is valid. + unsafe { bindings::rb_erase(self.node_links, &mut self.rbtree.root) }; + + // INVARIANT: The node is being returned and the caller may free it, however, it was + // removed from the tree. So the invariants still hold. + RBTreeNode { + // SAFETY: The node was a node in the tree, but we removed it, so we can convert it + // back into a box. + node: unsafe { Box::from_raw(self.node_ptr()) }, + } + } + + /// Takes the value of the entry out of the map, and returns it. + pub fn remove(self) -> V { + self.remove_node().node.value + } + + /// Swap the current node for the provided node. + /// + /// The key of both nodes must be equal. + fn replace(self, node: RBTreeNode) -> RBTreeNode { + let node = Box::into_raw(node.node); + + // SAFETY: `node` is valid at least until we call `Box::from_raw`, which only happens when + // the node is removed or replaced. + let new_node_links = unsafe { addr_of_mut!((*node).links) }; + + // SAFETY: This updates the pointers so that `new_node_links` is in the tree where + // `self.node_links` used to be. + unsafe { + bindings::rb_replace_node(self.node_links, new_node_links, &mut self.rbtree.root) + }; + + // SAFETY: + // - `self.node_ptr` produces a valid pointer to a node in the tree. + // - Now that we removed this entry from the tree, we can convert the node to a box. + let old_node = unsafe { Box::from_raw(self.node_ptr()) }; + + RBTreeNode { node: old_node } + } +} + struct Node { links: bindings::rb_node, key: K, -- 2.45.1.467.gbab1589fc0-goog