Skip to content

Commit e778041

Browse files
committed
Fix Rc
1 parent 6118e7f commit e778041

File tree

6 files changed

+147
-8
lines changed

6 files changed

+147
-8
lines changed

README.md

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -375,3 +375,24 @@ impl Iterator for MockIterator {
375375
}
376376
}
377377
```
378+
379+
### Mocking non-Send types
380+
381+
Mry supports types that don't implement `Send` for both in arguments and return type by wrapping them in [`SendWrapper`](https://docs.rs/send_wrapper/latest/send_wrapper/index.html) in the background. If you need working with non-Send types, you have to specify `#[mry::mry(not_send(Your::Type::Path, Another::Type::Path))]` for non-`Send` types other than raw pointers. Raw pointers are wrapped always with no configuration.
382+
383+
```rust
384+
#[mry::mry(not_send(Rc, NotSendValue))] // You cannot write generics fields here like `Rc<String>`
385+
impl DataHandler {
386+
fn process_raw_ptr(&self, ptr: *mut String) -> bool {
387+
// implementation...
388+
}
389+
390+
fn returns_non_send_type(&self) -> Rc<String> {
391+
// implementation...
392+
}
393+
394+
fn your_non_send_type(&self, value: NotSendValue) {
395+
// implementation...
396+
}
397+
}
398+
```

mry/src/mockable.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
#[diagnostic::on_unimplemented(
22
message = "`{Self}` is not mockable argument because it is not `Send + 'static`",
3-
// note = "If you don't need to mock this argument, you can add it to the skip list: `#[mry::mry(skip({Self}))]`"
3+
note = "Consider `#[mry::mry(not_send(Rc, YourNotSendType))]`"
44
)]
55
pub trait MockableArg: Send + 'static {}
66

77
#[diagnostic::on_unimplemented(
88
message = "`{Self}` is not mockable output because it is not `Send + 'static`",
9-
// note = "If you don't need to mock this argument, you can add it to the skip list: `#[mry::mry(skip({Self}))]`"
9+
note = "Consider `#[mry::mry(not_send(Rc, YourNotSendType))]`"
1010
)]
1111
pub trait MockableRet: Send + 'static {}
1212

mry/tests/integration/main.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,5 +19,7 @@ mod returns_with_recursive_call;
1919
mod simple_case;
2020
mod static_function;
2121

22+
#[cfg(feature = "send_wrapper")]
23+
mod non_send;
2224
#[cfg(feature = "send_wrapper")]
2325
mod raw_pointer;

mry/tests/integration/non_send.rs

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
use std::rc::Rc;
2+
3+
#[derive(Debug, Clone, PartialEq)]
4+
struct A(*const ());
5+
#[derive(Debug, Clone, PartialEq)]
6+
struct B;
7+
8+
#[mry::mry]
9+
#[derive(Default)]
10+
struct Cat {
11+
#[expect(dead_code)]
12+
name: String,
13+
}
14+
15+
#[mry::mry(not_send(A, Rc))]
16+
impl Cat {
17+
fn meow_a(&self, a: A) -> String {
18+
"meow".to_string()
19+
}
20+
21+
fn meow_rc(&self) -> Rc<String> {
22+
Rc::new("meow".to_string())
23+
}
24+
25+
fn meow_b(&self, b: B) -> B {
26+
b
27+
}
28+
}
29+
30+
#[cfg(test)]
31+
mod tests {
32+
use std::ptr::null;
33+
34+
use mry::send_wrapper::SendWrapper;
35+
36+
use super::*;
37+
38+
#[test]
39+
fn test_meow_a() {
40+
let mut cat = Cat {
41+
name: "meow".to_string(),
42+
..Default::default()
43+
};
44+
cat.mock_meow_a(A(null()))
45+
.returns_with(|_: SendWrapper<A>| "mocked".to_string());
46+
assert_eq!(cat.meow_a(A(null())), "mocked");
47+
}
48+
49+
#[test]
50+
fn test_meow_rc() {
51+
let mut cat = Cat {
52+
name: "meow".to_string(),
53+
..Default::default()
54+
};
55+
cat.mock_meow_rc()
56+
.returns_with(|| Rc::new("mocked".to_string()));
57+
assert_eq!(cat.meow_rc(), Rc::new("mocked".to_string()));
58+
}
59+
60+
#[test]
61+
fn test_meow_b() {
62+
let mut cat = Cat {
63+
name: "meow".to_string(),
64+
..Default::default()
65+
};
66+
cat.mock_meow_b(B).returns_with(|_: B| B);
67+
assert_eq!(cat.meow_b(B), B);
68+
}
69+
}

mry_macros/src/attrs.rs

Lines changed: 41 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,18 @@ impl MryAttr {
3939
}
4040
if self.not_send.0.iter().any(|p| p == path) {
4141
self.found = true;
42+
return;
43+
}
44+
for segment in path.segments.iter() {
45+
self.visit_path_segment(segment);
46+
}
47+
}
48+
fn visit_ident(&mut self, ident: &syn::Ident) {
49+
if self.found {
50+
return;
51+
}
52+
if self.not_send.0.iter().any(|p| p.is_ident(ident)) {
53+
self.found = true;
4254
}
4355
}
4456
}
@@ -78,11 +90,37 @@ mod tests {
7890
.unwrap(),
7991
)
8092
.unwrap();
81-
assert!(attr.debug.is_present());
82-
assert!(matches!(attr.not_send, Some(NotSend(_))));
83-
let lists = attr.not_send.as_ref().unwrap().0.clone();
93+
let lists = attr.not_send.unwrap().0;
8494
assert_eq!(lists.len(), 2);
8595
assert_eq!(lists[0], parse_quote!(T));
8696
assert_eq!(lists[1], parse_quote!(U));
8797
}
98+
99+
#[test]
100+
fn test_not_send_path() {
101+
let attr = MryAttr::from_list(
102+
&NestedMeta::parse_meta_list(parse_quote! {
103+
debug,not_send(A::B)
104+
})
105+
.unwrap(),
106+
)
107+
.unwrap();
108+
109+
assert!(attr.test_non_send(&parse_quote!(A::B)));
110+
assert!(!attr.test_non_send(&parse_quote!(A::C)));
111+
}
112+
113+
#[test]
114+
fn test_not_send_rc() {
115+
let attr = MryAttr::from_list(
116+
&NestedMeta::parse_meta_list(parse_quote! {
117+
debug,not_send(Rc)
118+
})
119+
.unwrap(),
120+
)
121+
.unwrap();
122+
123+
assert!(attr.test_non_send(&parse_quote!(Rc<String>)));
124+
assert!(!attr.test_non_send(&parse_quote!(String)));
125+
}
88126
}

mry_macros/src/method.rs

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -446,8 +446,14 @@ mod test {
446446
"mry::send_wrapper::SendWrapper::new(<A::B>::clone(&var))"
447447
);
448448
let (owned_type, converter) = make_owned_type(&attr, &ident, &c_d);
449-
assert_eq!(owned_type, parse_quote!(C::D));
450-
assert_eq!(remove_spaces(&converter.to_string()), "<C::D>::clone(&var)");
449+
assert_eq!(
450+
owned_type,
451+
parse_quote!(mry::send_wrapper::SendWrapper<C::D>)
452+
);
453+
assert_eq!(
454+
remove_spaces(&converter.to_string()),
455+
"mry::send_wrapper::SendWrapper::new(<C::D>::clone(&var))"
456+
);
451457
}
452458

453459
#[test]
@@ -538,7 +544,10 @@ mod test {
538544
remove_spaces(&a_b_type.static_type.to_string()),
539545
"mry::send_wrapper::SendWrapper<A::B>"
540546
);
541-
assert_eq!(remove_spaces(&c_d_type.static_type.to_string()), "C::D");
547+
assert_eq!(
548+
remove_spaces(&c_d_type.static_type.to_string()),
549+
"mry::send_wrapper::SendWrapper<C::D>"
550+
);
542551
assert_eq!(a_type.behavior_type.to_string(), "A");
543552
assert_eq!(remove_spaces(&a_b_type.behavior_type.to_string()), "A::B");
544553
assert_eq!(remove_spaces(&c_d_type.behavior_type.to_string()), "C::D");

0 commit comments

Comments
 (0)