mod send_safe {
pub struct SendSafe<T>(T);
pub trait ISendSafe {
fn check(&self) -> Option<String>;
fn into_safe(self) -> SendSafe<Self>
where
Self: Sized,
{
SendSafe::from(self)
}
}
impl<T: ISendSafe> SendSafe<T> {
pub fn from(t: T) -> SendSafe<T> {
if let Some(msg) = t.check() {
panic!("{}", msg);
}
Self(t)
}
pub fn into_raw(self) -> T {
self.0
}
}
unsafe impl<T> Send for SendSafe<T> {}
}
type NotSend = Rc<i32>;
struct A {
map: HashMap<NotSend, NotSend>,
rc: Rc<NotSend>,
option: Option<NotSend>,
}
impl ISendSafe for A {
fn check(&self) -> Option<String> {
if !self.map.is_empty() || Rc::strong_count(&self.rc) > 1 || self.option.is_some() {
Some("not safe".to_string())
} else {
None
}
}
}
#[test]
fn test_unsafe_send() {
let a = A { map: Default::default(), rc: Rc::new(Rc::new(1)), option: None };
let send_a = a.into_safe();
std::thread::spawn(move || {
drop(send_a);
}).join().unwrap();
}
I"m implementing a safety wrapper to allow sending structs containing non-Send types when specific conditions are met. The requirements are that all non-Send fields must be either:
- Empty containers (like HashMap)
- None values in Options
- Owning exclusive ownership (reference count = 1)
The implementation checks these conditions in the check()
method before constructing the SendSafe wrapper. Could this approach have hidden safety issues? Specifically:
- Are there any edge cases I might be missing with container types?
- Does the current reference count check properly ensure exclusive ownership?
- Are there any potential race conditions despite these checks?
- Does the unsafe Send implementation follow Rust"s safety requirements?