Skip to content

Instantly share code, notes, and snippets.

@vi
Created October 9, 2017 19:15
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save vi/cbfa777ac201daac88d9a74f4a251bc3 to your computer and use it in GitHub Desktop.
Save vi/cbfa777ac201daac88d9a74f4a251bc3 to your computer and use it in GitHub Desktop.
Simple copy stdin to stdout example using Rust mio
extern crate mio;
use mio::unix::EventedFd;
use std::fs::File;
use mio::{Token, PollOpt, Ready, Poll, Events};
//use mio_uds::UnixStream;
use std::os::unix::io::{FromRawFd};
use std::io::{Read, Write};
use std::io::ErrorKind;
fn main() {
const IN: Token = Token(0);
const OUT: Token = Token(1);
let mut fd0 : File = unsafe{FromRawFd::from_raw_fd(0)};
let mut fd1 : File = unsafe{FromRawFd::from_raw_fd(1)};
let fd0_e = EventedFd(&0);
let fd1_e = EventedFd(&1);
let poll = Poll::new().unwrap();
poll.register(&fd0_e, IN, Ready::readable(),
PollOpt::edge()).unwrap();
poll.register(&fd1_e, OUT, Ready::writable(),
PollOpt::edge()).unwrap();
let mut events = Events::with_capacity(1024);
const BS : usize = 65536;
let mut buf = vec![0; BS];
let mut cursor : usize = 0;
let mut write_ready = false;
let mut read_ready = false;
'outer: loop {
let ret = poll.poll(&mut events, None);
if let Err(x) = ret {
eprintln!("Boo");
if x.kind() == ErrorKind::Interrupted { continue; }
break;
}
for event in events.iter() {
match event.token() {
IN => {
read_ready = true;
}
OUT => {
write_ready = true;
}
_ => unreachable!(),
}
}
loop {
if read_ready && cursor < BS {
match fd0.read(&mut buf[cursor..BS]) {
Ok(0) => {
eprintln!("EOF");
break 'outer;
}
Ok(x) => {
cursor+=x;
}
Err(ref e) if e.kind() == ErrorKind::Interrupted => {
continue;
}
Err(ref e) if e.kind() == ErrorKind::WouldBlock => {
read_ready = false;
}
Err(_) => {
eprintln!("Read fail");
break 'outer;
}
}
} else
if write_ready && cursor > 0 {
match fd1.write(&mut buf[0..cursor]) {
Ok(x) => {
unsafe { buf.set_len(cursor); }
let _ = buf.drain(0..x);
unsafe { buf.set_len(BS); }
cursor-=x;
}
Err(ref e) if e.kind() == ErrorKind::Interrupted => {
continue;
}
Err(ref e) if e.kind() == ErrorKind::WouldBlock => {
write_ready = false;
}
Err(_) => {
eprintln!("Write fail");
break 'outer;
}
}
} else {
break;
}
}
}
}
@mtn
Copy link

mtn commented Jul 19, 2018

Thanks for posting this -- I found it very helpful :-)

I had one question: why do you use fd0 and fd1. Can't we just use stdout() and stdin() to get handles? I tried this and it worked fine, so I was wondering if there are any pitfalls.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment