Skip to content

Commit 719df35

Browse files
committed
Upgraded to tokio. Fixed several issues
1 parent 301f598 commit 719df35

File tree

6 files changed

+109
-138
lines changed

6 files changed

+109
-138
lines changed

.gitignore

Lines changed: 1 addition & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,10 @@
11
# Generated by Cargo
22
# will have compiled files and executables
3-
/target/
3+
/target
44

55
# Remove Cargo.lock from gitignore if creating an executable, leave it for libraries
66
# More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html
77
Cargo.lock
88

99
# These are backup files generated by rustfmt
1010
**/*.rs.bk
11-
12-
13-
#Added by cargo
14-
#
15-
#already existing elements were commented out
16-
17-
/target
18-
#Cargo.lock

Cargo.toml

Lines changed: 8 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,17 @@
11
[package]
2-
name = "slock"
3-
version = "0.1.2"
42
authors = ["Brandon Dyer <[email protected]>"]
5-
edition = "2018"
3+
categories = ["asynchronous", "concurrency", "memory-management", "rust-patterns"]
64
description = "An async mutex that never deadlocks."
5+
edition = "2021"
6+
keywords = ["mutex", "smart", "lock", "async"]
7+
license = "MIT"
8+
name = "slock"
79
readme = "README.md"
810
repository = "https://github.com/BrokenLamp/slock-rs"
9-
license = "MIT"
10-
keywords = ["mutex", "smart", "lock", "async"]
11-
categories = ["asynchronous", "concurrency", "memory-management", "rust-patterns"]
12-
13-
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
14-
15-
[features]
16-
default = ["futures", "blocking"]
17-
blocking = ["futures"]
18-
19-
[dependencies.futures]
20-
version = "0.3"
21-
optional = true
11+
version = "0.2.0"
2212

23-
[dependencies.async-std]
24-
version = "1.6"
13+
[dependencies]
14+
tokio = {version = "1.22", features = ["sync", "time", "rt", "macros"]}
2515

2616
[dev-dependencies]
2717
lazy_static = "1.4"
28-
futures = "0.3"

README.md

Lines changed: 8 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,9 @@ let lock = Slock::new(5i32);
1414
// Change the lock's value
1515
lock.set(|v| v + 1).await;
1616

17-
// Get the lock's value
17+
// Get the lock's value if Copy
1818
let value = lock.get().await;
19-
// Or if the value doesn't implement copy
19+
// Get the lock's value if Clone
2020
let value = lock.get_clone().await;
2121

2222
assert_eq!(value, 6);
@@ -25,24 +25,22 @@ assert_eq!(value, 6);
2525
It's also possible to extract only the data you need from larger structures without the need to clone the entire thing.
2626

2727
```rust
28-
// A user struct that doesn't implement copy
2928
struct User {
3029
name: String,
3130
age: i32,
32-
// ... lots of other things
3331
}
3432

3533
let user = Slock::new(User {
3634
name: "Bob",
3735
age: 32,
38-
// ... lots of other things
3936
});
4037

41-
// Get just the name
42-
// This performs a clone on only the name
38+
// Extract something that is Copy
39+
let age = user.map(|v| v.age).await;
40+
41+
// Extract something that is Clone
4342
let name = user.map(|v| v.name.clone()).await;
4443

45-
// Get just the age
46-
// Extracts only the age, leaving everything else untouched
47-
let age = user.map(|v| v.age).await;
44+
// Increment `age` by 1
45+
user.set(|v| v.age += 1).await;
4846
```

src/lib.rs

Lines changed: 51 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020
//! println!("{}", value); // 6
2121
//!
2222
//! // Use in multiple threads
23-
//! futures::join!(
23+
//! tokio::join!(
2424
//! do_something_in_a_thread(lock.split()),
2525
//! do_something_else_in_a_thread(lock.split()),
2626
//! do_another_thing_in_a_thread(lock.split()),
@@ -33,7 +33,7 @@
3333
//! ### Don't access a Slock from within another
3434
//!
3535
//! Bad:
36-
//! ```rust
36+
//! ```rust,ignore
3737
//! # use slock::*;
3838
//! # use futures::executor::block_on;
3939
//! # async {
@@ -58,12 +58,11 @@
5858
//! # };
5959
//! ```
6060
61-
pub use async_std::future::{timeout, TimeoutError};
62-
use std::{
63-
cmp::Eq,
64-
collections::HashMap,
65-
hash::Hash,
66-
sync::{Arc, RwLock},
61+
use std::{cmp::Eq, collections::HashMap, hash::Hash, sync::Arc};
62+
63+
use tokio::{
64+
sync::RwLock,
65+
time::{error::Elapsed, timeout},
6766
};
6867

6968
pub struct SlockData<T> {
@@ -98,25 +97,22 @@ impl<T> Slock<T> {
9897
/// let name = lock.map(|v| v.name).await;
9998
/// # };
10099
/// ```
101-
pub async fn map<F, U>(&self, mapper: F) -> Result<U, TimeoutError>
100+
pub async fn map<F, U>(&self, mapper: F) -> Result<U, Elapsed>
102101
where
103102
F: FnOnce(&T) -> U,
104103
{
105-
match self.lock.read() {
106-
Ok(v) => {
107-
timeout(std::time::Duration::from_secs(1), async {
108-
mapper(&v.value)
109-
})
110-
.await
111-
}
112-
Err(_) => panic!("Slock could not read for map!"),
113-
}
104+
let v = self.lock.read().await;
105+
timeout(std::time::Duration::from_secs(1), async {
106+
mapper(&v.value)
107+
})
108+
.await
114109
}
115110

116111
/// A setter for changing the internal data of the lock.
117112
/// ```rust
118113
/// # use slock::*;
119-
/// # let lock = Slock::new(1i32);
114+
/// let lock = Slock::new(1i32);
115+
///
120116
/// # async {
121117
/// lock.set(|v| v + 1).await;
122118
/// lock.set(|_| 6).await;
@@ -126,27 +122,22 @@ impl<T> Slock<T> {
126122
where
127123
F: FnOnce(T) -> T,
128124
{
129-
match self.lock.write() {
130-
Ok(mut data) => {
131-
let ptr = &mut data.value as *mut T;
132-
unsafe {
133-
let new = timeout(std::time::Duration::from_secs(1), async {
134-
setter(ptr.read())
135-
})
136-
.await;
137-
if let Ok(new) = new {
138-
timeout(std::time::Duration::from_secs(1), async {
139-
data.hook.as_mut().map(|hook| hook(&new));
140-
})
141-
.await
142-
.ok();
143-
ptr.write(new);
144-
}
145-
}
146-
data.version += 1;
147-
}
148-
Err(_) => panic!("Slock could not write!"),
125+
let mut data = self.lock.write().await;
126+
let ptr = &mut data.value as *mut T;
127+
let new = timeout(std::time::Duration::from_secs(1), async {
128+
setter(unsafe { ptr.read() })
129+
})
130+
.await;
131+
if let Ok(new) = new {
132+
timeout(std::time::Duration::from_secs(1), async {
133+
data.hook.as_mut().map(|hook| hook(&new));
134+
})
135+
.await
136+
.ok();
137+
unsafe { ptr.write(new) };
149138
}
139+
140+
data.version += 1;
150141
}
151142

152143
/// Create's a new lock pointing to the same data.
@@ -157,6 +148,7 @@ impl<T> Slock<T> {
157148
/// let lock = Slock::new(0i32);
158149
/// let the_same_lock = lock.split();
159150
/// ```
151+
#[deprecated = "Use `clone()` instead"]
160152
pub fn split(&self) -> Self {
161153
Self {
162154
lock: self.lock.clone(),
@@ -170,30 +162,32 @@ impl<T> Slock<T> {
170162
self.lock.clone()
171163
}
172164

173-
pub fn hook<F: 'static>(&self, hook: F)
165+
pub async fn hook<F: 'static>(&self, hook: F)
174166
where
175167
F: FnMut(&T),
176168
{
177-
match self.lock.write() {
178-
Ok(mut data) => {
179-
data.hook = Some(Box::new(hook));
180-
}
181-
Err(_) => panic!("Slock could not write!"),
169+
let mut data = self.lock.write().await;
170+
data.hook = Some(Box::new(hook));
171+
}
172+
}
173+
174+
impl<T> Clone for Slock<T> {
175+
fn clone(&self) -> Self {
176+
Self {
177+
lock: self.lock.clone(),
182178
}
183179
}
184180
}
185181

186182
impl<T: Clone> Slock<T> {
187183
/// Returns a clone of the lock's data.
188184
pub async fn get_clone(&self) -> T {
189-
match self.lock.read() {
190-
Ok(v) => v.value.clone(),
191-
Err(_) => panic!("Slock could not read for clone!"),
192-
}
185+
let data = self.lock.read().await;
186+
data.value.clone()
193187
}
194188

195-
/// Creates a clone of the lock and its data.
196-
pub async fn clone_async(&self) -> Self {
189+
/// Create a new lock with data clone from this one.
190+
pub async fn clone_deep(&self) -> Self {
197191
return Slock::new(self.get_clone().await);
198192
}
199193
}
@@ -213,7 +207,7 @@ impl<T> Slock<Vec<T>> {
213207
impl<T> Slock<Slock<T>> {
214208
/// Converts from `Slock<Slock<T>>` to `Slock<T>`
215209
pub async fn flatten(&self) -> Slock<T> {
216-
self.map(|inner| inner.split()).await.unwrap()
210+
self.map(|inner| inner.clone()).await.unwrap()
217211
}
218212
}
219213

@@ -246,7 +240,7 @@ impl<K: Eq + Hash + Copy, V> SlockMap<K, V> {
246240
pub async fn from_key(&self, key: K) -> Option<Slock<V>> {
247241
self.map(|hash_map| {
248242
let key = key;
249-
hash_map.get(&key).map(|inner| inner.split())
243+
hash_map.get(&key).map(|inner| inner.clone())
250244
})
251245
.await
252246
.unwrap()
@@ -256,14 +250,12 @@ impl<K: Eq + Hash + Copy, V> SlockMap<K, V> {
256250
impl<T: Copy> Slock<T> {
257251
/// If a lock's data implements copy, this will return an owned copy of it.
258252
pub async fn get(&self) -> T {
259-
match self.lock.read() {
260-
Ok(v) => v.value,
261-
Err(_) => panic!("Slock could not read for clone!"),
262-
}
253+
let data = self.lock.read().await;
254+
data.value
263255
}
264256
}
265257

266258
pub mod blocking;
267259

268-
unsafe impl<T> Send for Slock<T> {}
269-
unsafe impl<T> Sync for Slock<T> {}
260+
unsafe impl<T: Send> Send for Slock<T> {}
261+
unsafe impl<T: Send> Sync for Slock<T> {}

tests/hooks.rs

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,15 @@
1-
use futures::executor::block_on;
21
use slock::*;
32

4-
#[test]
5-
fn basic_hooks() {
3+
#[tokio::test]
4+
async fn basic_hooks() {
5+
// SAFETY: Required to increment the static counter
66
unsafe {
77
let lock = Slock::new(());
88
static mut COUNT: i32 = 0;
9-
lock.hook(|_| COUNT += 1);
10-
block_on(lock.set(|_| ()));
11-
block_on(lock.set(|_| ()));
12-
block_on(lock.set(|_| ()));
9+
lock.hook(|_| COUNT += 1).await;
10+
lock.set(|_| ()).await;
11+
lock.set(|_| ()).await;
12+
lock.set(|_| ()).await;
1313
assert_eq!(COUNT, 3);
1414
}
1515
}

0 commit comments

Comments
 (0)