Skip to content

Commit 459ed5c

Browse files
Monnorochasomers
authored andcommitted
Implement with_st to match non-Send arguments. (#93)
Implement `with_st` to match non-`Send` arguments.
1 parent d14cd7d commit 459ed5c

File tree

4 files changed

+94
-3
lines changed

4 files changed

+94
-3
lines changed

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,10 @@ This project adheres to [Semantic Versioning](http://semver.org/).
55

66
## [Unreleased] - ReleaseDate
77
### Added
8+
9+
- Added the ability to match non-`Send` arguments with `withf_st`
10+
([#93](https://github.com/asomers/mockall/pull/93))
11+
812
### Changed
913
### Fixed
1014
### Removed

mockall/src/lib.rs

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -150,7 +150,8 @@
150150
//! [`returning_st`](https://docs.rs/mockall_examples/latest/mockall_examples/__mock_Foo_Foo/foo/struct.Expectation.html#method.returning_st)
151151
//! or
152152
//! [`return_once_st`](https://docs.rs/mockall_examples/latest/mockall_examples/__mock_Foo_Foo/foo/struct.Expectation.html#method.return_once_st)
153-
//! methods.
153+
//! methods. If you need to match arguments that are not `Send`, you can use the
154+
//! [`withf_st`](https://docs.rs/mockall_examples/latest/mockall_examples/__mock_Foo_Foo/foo/struct.Expectation.html#method.withf_st)
154155
//! These take a non-`Send` object and add runtime access checks. The wrapped
155156
//! object will be `Send`, but accessing it from multiple threads will cause a
156157
//! runtime panic.
@@ -165,10 +166,12 @@
165166
//!
166167
//! # fn main() {
167168
//! let mut mock = MockFoo::new();
169+
//! let x = Rc::new(5);
170+
//! let argument = x.clone();
168171
//! mock.expect_foo()
169-
//! .withf(|x| **x == 5)
172+
//! .withf_st(move |x| *x == argument)
170173
//! .returning_st(move |_| Rc::new(42u32));
171-
//! assert_eq!(42, *mock.foo(Rc::new(5)));
174+
//! assert_eq!(42, *mock.foo(x));
172175
//! # }
173176
//! ```
174177
//!

mockall/tests/automock_nonsend.rs

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,9 @@ use std::rc::Rc;
88
trait Foo {
99
// Rc is not Send
1010
fn foo(&self, x: Rc<u32>) -> Rc<u32>;
11+
12+
// Rc is not Send
13+
fn bar(x: Rc<u32>) -> Rc<u32>;
1114
}
1215

1316
#[test]
@@ -19,3 +22,35 @@ fn returning_st() {
1922
let x = Rc::new(42u32);
2023
assert_eq!(43, *mock.foo(x).as_ref());
2124
}
25+
26+
#[test]
27+
fn returning_st_static() {
28+
let mock = MockFoo::bar_context();
29+
let y = Rc::new(43u32);
30+
mock.expect()
31+
.returning_st(move |_| y.clone());
32+
let x = Rc::new(42u32);
33+
assert_eq!(43, *MockFoo::bar(x).as_ref());
34+
}
35+
36+
#[test]
37+
fn withf_st() {
38+
let mut mock = MockFoo::new();
39+
let x = Rc::new(42u32);
40+
let argument = x.clone();
41+
mock.expect_foo()
42+
.withf_st(move |x| *x == argument)
43+
.returning_st(|_| Rc::new(43u32));
44+
assert_eq!(43, *mock.foo(x).as_ref());
45+
}
46+
47+
#[test]
48+
fn withf_st_static() {
49+
let mock = MockFoo::bar_context();
50+
let x = Rc::new(42u32);
51+
let argument = x.clone();
52+
mock.expect()
53+
.withf_st(move |x| *x == argument)
54+
.returning_st(|_| Rc::new(43u32));
55+
assert_eq!(43, *MockFoo::bar(x).as_ref());
56+
}

mockall_derive/src/expectation.rs

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -192,6 +192,16 @@ impl<'a> Common<'a> {
192192
self.common.withf(__mockall_f);
193193
self
194194
}
195+
196+
/// Single-threaded version of [`withf`](#method.withf).
197+
/// Can be used when the argument type isn't `Send`.
198+
#v fn withf_st<MockallF>(&mut self, __mockall_f: MockallF) -> &mut Self
199+
where MockallF: #hrtb Fn(#(&#predty, )*)
200+
-> bool + 'static
201+
{
202+
self.common.withf_st(__mockall_f);
203+
self
204+
}
195205
)
196206
}
197207

@@ -391,6 +401,8 @@ impl<'a> Expectation<'a> {
391401
enum Matcher #ig #wc {
392402
Always,
393403
Func(Box<dyn #hrtb Fn(#refpredty) -> bool + Send>),
404+
// Version of Matcher::Func for closures that aren't Send
405+
FuncST(::mockall::Fragile<Box<dyn #hrtb Fn(#refpredty) -> bool>>),
394406
Pred(Box<(#preds)>),
395407
// Prevent "unused type parameter" errors
396408
// Surprisingly, PhantomData<Fn(generics)> is Send even if
@@ -404,6 +416,8 @@ impl<'a> Expectation<'a> {
404416
Matcher::Always => true,
405417
Matcher::Func(__mockall_f) =>
406418
__mockall_f(#(#argnames, )*),
419+
Matcher::FuncST(__mockall_f) =>
420+
(__mockall_f.get())(#(#argnames, )*),
407421
Matcher::Pred(__mockall_pred) =>
408422
[#pred_matches]
409423
.iter()
@@ -427,6 +441,7 @@ impl<'a> Expectation<'a> {
427441
match self {
428442
Matcher::Always => write!(__mockall_fmt, "<anything>"),
429443
Matcher::Func(_) => write!(__mockall_fmt, "<function>"),
444+
Matcher::FuncST(_) => write!(__mockall_fmt, "<single threaded function>"),
430445
Matcher::Pred(__mockall_p) => {
431446
write!(__mockall_fmt, #braces,
432447
#(__mockall_p.#indices,)*)
@@ -521,6 +536,15 @@ impl<'a> Expectation<'a> {
521536
Matcher::Func(Box::new(__mockall_f)));
522537
}
523538

539+
fn withf_st<MockallF>(&mut self, __mockall_f: MockallF)
540+
where MockallF: #hrtb Fn(#refpredty)
541+
-> bool + 'static
542+
{
543+
let mut __mockall_guard = self.matcher.lock().unwrap();
544+
mem::replace(__mockall_guard.deref_mut(),
545+
Matcher::FuncST(::mockall::Fragile::new(Box::new(__mockall_f))));
546+
}
547+
524548
fn verify_sequence(&self) {
525549
if let Some(__mockall_handle) = &self.seq_handle {
526550
__mockall_handle.verify()
@@ -1267,6 +1291,16 @@ impl<'a> StaticExpectation<'a> {
12671291
{
12681292
self.guard.0[self.i].withf(__mockall_f)
12691293
}
1294+
1295+
/// Just like
1296+
/// [`Expectation::withf_st`](struct.Expectation.html#method.withf_st)
1297+
#v fn withf_st<MockallF>(&mut self, __mockall_f: MockallF)
1298+
-> &mut Expectation #tg
1299+
where MockallF: #hrtb Fn(#(&#predty, )*)
1300+
-> bool + 'static
1301+
{
1302+
self.guard.0[self.i].withf_st(__mockall_f)
1303+
}
12701304
}
12711305
#context_ts
12721306
)
@@ -1463,6 +1497,21 @@ impl<'a> StaticExpectation<'a> {
14631497
.0[self.i]
14641498
.withf(__mockall_f)
14651499
}
1500+
1501+
/// Just like
1502+
/// [`Expectation::withf_st`](struct.Expectation.html#method.withf_st)
1503+
#v fn withf_st<MockallF>(&mut self, __mockall_f: MockallF) -> &mut Expectation #tg
1504+
where MockallF: #hrtb Fn(#(&#predty, )*)
1505+
-> bool + 'static
1506+
{
1507+
self.guard.store.get_mut(
1508+
&::mockall::Key::new::<(#(#argty, )*)>()
1509+
).unwrap()
1510+
.downcast_mut::<Expectations #tg>()
1511+
.unwrap()
1512+
.0[self.i]
1513+
.withf_st(__mockall_f)
1514+
}
14661515
}
14671516
#context_ts
14681517
)

0 commit comments

Comments
 (0)