1use serde_::de::DeserializeOwned;
2use serde_::Serialize;
3use std::cell::RefCell;
4use std::fs;
5use std::io;
6use std::os::unix::io::{FromRawFd, IntoRawFd};
7use std::os::unix::net::UnixListener;
8use std::path::{Path, PathBuf};
9
10use crate::typed_channel::Sender;
11
12#[derive(Debug)]
18pub struct Bootstrapper<T> {
19 listener: UnixListener,
20 sender: RefCell<Option<Sender<T>>>,
21 path: PathBuf,
22}
23
24impl<T: Serialize + DeserializeOwned> Bootstrapper<T> {
25 #[cfg(feature = "bootstrap-simple")]
27 pub fn new() -> io::Result<Bootstrapper<T>> {
28 use rand::{thread_rng, RngCore};
29 use std::time::{SystemTime, UNIX_EPOCH};
30
31 let mut dir = std::env::temp_dir();
32 let mut rng = thread_rng();
33 let now = SystemTime::now();
34 dir.push(&format!(
35 ".rust-unix-ipc.{}-{}.sock",
36 now.duration_since(UNIX_EPOCH).unwrap().as_secs(),
37 rng.next_u64(),
38 ));
39 Bootstrapper::bind(&dir)
40 }
41
42 pub fn bind<P: AsRef<Path>>(p: P) -> io::Result<Bootstrapper<T>> {
44 fs::remove_file(&p).ok();
45 let listener = UnixListener::bind(&p)?;
46 Ok(Bootstrapper {
47 listener,
48 sender: RefCell::new(None),
49 path: p.as_ref().to_path_buf(),
50 })
51 }
52
53 pub fn path(&self) -> &Path {
55 &self.path
56 }
57
58 pub fn send(&self, val: T) -> io::Result<()> {
63 if self.sender.borrow().is_none() {
64 let (sock, _) = self.listener.accept()?;
65 let sender = unsafe { Sender::from_raw_fd(sock.into_raw_fd()) };
66 *self.sender.borrow_mut() = Some(sender);
67 }
68 self.sender.borrow().as_ref().unwrap().send(val)
69 }
70}
71
72impl<T> Drop for Bootstrapper<T> {
73 fn drop(&mut self) {
74 fs::remove_file(&self.path).ok();
75 }
76}
77
78#[test]
79fn test_bootstrap() {
80 use crate::Receiver;
81
82 let bootstrapper = Bootstrapper::new().unwrap();
83 let path = bootstrapper.path().to_owned();
84
85 let handle = std::thread::spawn(move || {
86 let receiver = Receiver::<u32>::connect(path).unwrap();
87 let a = receiver.recv().unwrap();
88 let b = receiver.recv().unwrap();
89 assert_eq!(a + b, 65);
90 });
91
92 bootstrapper.send(42u32).unwrap();
93 bootstrapper.send(23u32).unwrap();
94
95 handle.join().unwrap();
96}
97
98#[test]
99fn test_bootstrap_reverse() {
100 use crate::{channel, Receiver};
101
102 let bootstrapper = Bootstrapper::new().unwrap();
103 let path = bootstrapper.path().to_owned();
104 let (tx, rx) = channel::<u32>().unwrap();
105
106 std::thread::spawn(move || {
107 let receiver = Receiver::<Sender<u32>>::connect(path).unwrap();
108 let result_sender = receiver.recv().unwrap();
109 result_sender.send(42 + 23).unwrap();
110 });
111
112 bootstrapper.send(tx).unwrap();
113 assert_eq!(rx.recv().unwrap(), 65);
114}