extern crate libc;
use std::ffi::CString;
use std::io::prelude::*;
use std::path::{Path, PathBuf};
fn mkfifo(name: &str) -> PathBuf {
let prefix = Path::new("/tmp/palombe/");
let path = prefix.join(name);
std::fs::create_dir_all(prefix)
.unwrap_or_else(|_| panic!("Error: couldn't create the folder {}", prefix.display()));
let filename = CString::new(path.to_str().unwrap()).unwrap();
unsafe {
libc::mkfifo(filename.as_ptr(), 0o600);
}
path
}
pub fn send(name: &str, value: &str) {
let path = mkfifo(&name);
let mut file = std::fs::OpenOptions::new()
.write(true)
.open(path)
.expect("Error: couldn't open the named pipe");
file.write_all(value.as_bytes())
.expect("Error: couldn't write the named pipe");
}
pub fn receive(name: &str) -> String {
let path = mkfifo(&name);
let file = std::fs::File::open(path.clone())
.unwrap_or_else(|_| panic!("Error: couldn't open: {}", path.display()));
let mut reader = std::io::BufReader::new(file);
let mut buffer = String::new();
loop {
let len = reader
.read_line(&mut buffer)
.expect("Error: couldn't read the input file");
if len == 0 {
std::fs::remove_file(&path)
.unwrap_or_else(|_| panic!("Error: couldn't remove the file {}", path.display()));
return buffer;
}
}
}
#[no_mangle]
pub extern "C" fn c_send(key: &CString, value: &CString) {
let path = mkfifo(&key.to_str().unwrap());
let mut file = std::fs::OpenOptions::new()
.write(true)
.open(path)
.expect("Error: couldn't open the named pipe");
file.write_all(value.as_bytes())
.expect("Error: couldn't write the named pipe");
}
#[no_mangle]
pub extern "C" fn c_receive(key: &CString) -> CString {
let path = mkfifo(&key.to_str().unwrap());
let file = std::fs::File::open(path.clone())
.unwrap_or_else(|_| panic!("Error: couldn't open: {}", path.display()));
let mut reader = std::io::BufReader::new(file);
let mut buffer = String::new();
loop {
let len = reader
.read_line(&mut buffer)
.expect("Error: couldn't read the input file");
if len == 0 {
std::fs::remove_file(&path)
.unwrap_or_else(|_| panic!("Error: couldn't remove the file {}", path.display()));
return CString::new(buffer).unwrap();
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn string() {
std::thread::spawn(|| send("foo", "bar"));
assert_eq!(receive("foo"), "bar");
}
#[test]
fn c_string() {
let key = CString::new("bip").unwrap();
let value = CString::new("boop").unwrap();
let key_ = key.clone();
let value_ = value.clone();
std::thread::spawn(move || c_send(&key_, &value_));
assert_eq!(c_receive(&key), value);
}
}