generated from Tamschi/rust-template
-
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathlib.rs
125 lines (111 loc) · 3.35 KB
/
lib.rs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
//! An example crate for a blog post.
//!
//! [](https://iteration-square.schichler.dev/#narrow/stream/project.2FTODO_CRATE_NAME)
#![doc(html_root_url = "https://docs.rs/ances-tree/0.0.1")]
#![warn(clippy::pedantic)]
#![allow(clippy::semicolon_if_nothing_returned)]
use std::{borrow::Borrow, sync::Arc};
use tap::Pipe;
#[cfg(doctest)]
pub mod readme {
doc_comment::doctest!("../README.md");
}
/// A reference-counting inverse tree node.
#[derive(Debug, Clone)]
pub struct Node<T> {
pub parent: Option<Arc<Self>>,
pub value: T,
}
impl<T> Node<T> {
/// Creates a new [`Node`] instance with the given `parent` and `value`.
pub fn new(parent: Option<Arc<Self>>, value: T) -> Self {
Self { parent, value }
}
/// Retrieves a reference to a [`Node`] with a value matching `key` iff available.
///
/// See also: <https://doc.rust-lang.org/stable/std/collections/hash_set/struct.HashSet.html#method.get>
#[must_use]
pub fn get<Q: ?Sized>(&self, key: &Q) -> Option<&Self>
where
T: Borrow<Q>,
Q: Eq,
{
let mut this = self;
while this.value.borrow() != key {
this = this.parent.as_ref()?
}
Some(this)
}
/// Retrieves a mutable reference to a [`Node`] with a value matching `key` iff available.
///
/// # Errors
///
/// Iff an ancestor is shared so that it can't be borrowed mutably.
pub fn get_mut<Q: ?Sized>(&mut self, key: &Q) -> Result<Option<&mut Self>, &mut Arc<Self>>
where
T: Borrow<Q>,
Q: Eq,
{
let mut this = self;
while this.value.borrow() != key {
match this.parent.as_mut() {
None => return Ok(None),
Some(parent) => {
if let Some(parent) = Arc::get_mut(parent) {
// The lifetime must be detached here…:
this = unsafe { &mut *(parent as *mut _) }
} else {
// … so that this compiles. Please correct me if there's a better way.
return Err(parent);
}
}
}
}
Ok(Some(this))
}
/// Retrieves a mutable reference to a [`Node`] with a value matching `key` iff available, by cloning ancestors as necessary.
///
/// No [`Node`]s are cloned if no matching value is found.
///
/// # Errors
///
/// Iff an ancestor is shared so that it can't be borrowed mutably.
#[allow(clippy::result_unit_err)] // In a real crate, I'd return a `Result<Option<&mut T>, &mut Arc<Self>>` instead.
#[allow(clippy::shadow_unrelated)]
pub fn make_mut<Q: ?Sized>(&mut self, key: &Q) -> Option<&mut Self>
where
T: Borrow<Q> + Clone,
Q: Eq,
{
let mut this = self;
let mut shared = false;
while this.value.borrow() != key {
if let Some(parent) = this.parent.as_mut()?.pipe(Arc::get_mut) {
// The lifetime must be detached here…:
this = unsafe { &mut *(parent as *mut _) }
} else {
shared = true;
break;
}
}
if shared {
// Don't run (potentially expensive) comparisons twice.
let mut generations = 0;
// … so that this compiles. Please correct me if there's a better way.
let mut shared = &*this;
while {
shared = shared.parent.as_ref()?;
generations += 1;
shared.value.borrow() != key
} {}
for _ in 0..generations {
this = this
.parent
.as_mut()
.expect("unreachable")
.pipe(Arc::make_mut)
}
}
Some(this)
}
}