rust/src/libstd/io/comm_adapters.rs

195 lines
5.0 KiB
Rust
Raw Normal View History

// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use clone::Clone;
2013-12-09 11:13:54 -06:00
use cmp;
use container::Container;
use comm::{Sender, Receiver};
2013-12-09 11:13:54 -06:00
use io;
use option::{None, Option, Some};
use result::{Ok, Err};
use super::{Reader, Writer, IoResult};
use slice::{bytes, CloneableVector, MutableVector, ImmutableVector};
/// Allows reading from a rx.
2013-12-09 11:13:54 -06:00
///
/// # Example
///
/// ```
/// use std::io::ChanReader;
2014-02-15 01:44:22 -06:00
///
/// let (tx, rx) = channel();
/// # drop(tx);
/// let mut reader = ChanReader::new(rx);
2013-12-09 11:13:54 -06:00
///
/// let mut buf = ~[0u8, ..100];
/// match reader.read(buf) {
2014-02-15 01:44:22 -06:00
/// Ok(nread) => println!("Read {} bytes", nread),
/// Err(e) => println!("read error: {}", e),
2013-12-09 11:13:54 -06:00
/// }
/// ```
pub struct ChanReader {
2014-03-27 17:09:47 -05:00
buf: Option<~[u8]>, // A buffer of bytes received but not consumed.
pos: uint, // How many of the buffered bytes have already be consumed.
rx: Receiver<~[u8]>, // The rx to pull data from.
closed: bool, // Whether the pipe this rx connects to has been closed.
2013-12-09 11:13:54 -06:00
}
impl ChanReader {
/// Wraps a `Port` in a `ChanReader` structure
pub fn new(rx: Receiver<~[u8]>) -> ChanReader {
ChanReader {
2013-12-09 11:13:54 -06:00
buf: None,
pos: 0,
rx: rx,
2013-12-09 11:13:54 -06:00
closed: false,
}
}
}
impl Reader for ChanReader {
fn read(&mut self, buf: &mut [u8]) -> IoResult<uint> {
2013-12-09 11:13:54 -06:00
let mut num_read = 0;
loop {
match self.buf {
Some(ref prev) => {
let dst = buf.mut_slice_from(num_read);
let src = prev.slice_from(self.pos);
let count = cmp::min(dst.len(), src.len());
bytes::copy_memory(dst, src.slice_to(count));
2013-12-09 11:13:54 -06:00
num_read += count;
self.pos += count;
},
None => (),
};
if num_read == buf.len() || self.closed {
break;
}
self.pos = 0;
self.buf = self.rx.recv_opt();
2013-12-09 11:13:54 -06:00
self.closed = self.buf.is_none();
}
if self.closed && num_read == 0 {
Err(io::standard_error(io::EndOfFile))
2013-12-09 11:13:54 -06:00
} else {
Ok(num_read)
2013-12-09 11:13:54 -06:00
}
}
}
/// Allows writing to a tx.
2013-12-09 11:13:54 -06:00
///
/// # Example
///
/// ```
2014-02-15 01:44:22 -06:00
/// # #[allow(unused_must_use)];
/// use std::io::ChanWriter;
///
/// let (tx, rx) = channel();
/// # drop(rx);
/// let mut writer = ChanWriter::new(tx);
2013-12-09 11:13:54 -06:00
/// writer.write("hello, world".as_bytes());
/// ```
2013-12-05 20:19:06 -06:00
pub struct ChanWriter {
2014-03-27 17:09:47 -05:00
tx: Sender<~[u8]>,
2013-12-09 11:13:54 -06:00
}
2013-12-05 20:19:06 -06:00
impl ChanWriter {
/// Wraps a channel in a `ChanWriter` structure
pub fn new(tx: Sender<~[u8]>) -> ChanWriter {
ChanWriter { tx: tx }
2013-12-09 11:13:54 -06:00
}
}
impl Clone for ChanWriter {
fn clone(&self) -> ChanWriter {
ChanWriter { tx: self.tx.clone() }
}
}
2013-12-05 20:19:06 -06:00
impl Writer for ChanWriter {
fn write(&mut self, buf: &[u8]) -> IoResult<()> {
if !self.tx.try_send(buf.to_owned()) {
Err(io::IoError {
2013-12-09 11:13:54 -06:00
kind: io::BrokenPipe,
desc: "Pipe closed",
detail: None
})
} else {
Ok(())
2013-12-09 11:13:54 -06:00
}
}
}
2013-12-09 11:13:54 -06:00
#[cfg(test)]
mod test {
use prelude::*;
use super::*;
use io;
use task;
#[test]
fn test_rx_reader() {
let (tx, rx) = channel();
task::spawn(proc() {
tx.send(~[1u8, 2u8]);
tx.send(~[]);
tx.send(~[3u8, 4u8]);
tx.send(~[5u8, 6u8]);
tx.send(~[7u8, 8u8]);
});
2013-12-09 11:13:54 -06:00
let mut reader = ChanReader::new(rx);
2013-12-09 11:13:54 -06:00
let mut buf = ~[0u8, ..3];
2014-01-30 16:10:53 -06:00
assert_eq!(Ok(0), reader.read([]));
2013-12-09 11:13:54 -06:00
2014-01-30 16:10:53 -06:00
assert_eq!(Ok(3), reader.read(buf));
2013-12-09 11:13:54 -06:00
assert_eq!(~[1,2,3], buf);
2014-01-30 16:10:53 -06:00
assert_eq!(Ok(3), reader.read(buf));
2013-12-09 11:13:54 -06:00
assert_eq!(~[4,5,6], buf);
2014-01-30 16:10:53 -06:00
assert_eq!(Ok(2), reader.read(buf));
2013-12-09 11:13:54 -06:00
assert_eq!(~[7,8,6], buf);
2014-01-30 16:10:53 -06:00
match reader.read(buf) {
Ok(..) => fail!(),
Err(e) => assert_eq!(e.kind, io::EndOfFile),
}
2013-12-09 11:13:54 -06:00
assert_eq!(~[7,8,6], buf);
// Ensure it continues to fail in the same way.
2014-01-30 16:10:53 -06:00
match reader.read(buf) {
Ok(..) => fail!(),
Err(e) => assert_eq!(e.kind, io::EndOfFile),
}
2013-12-09 11:13:54 -06:00
assert_eq!(~[7,8,6], buf);
}
#[test]
fn test_chan_writer() {
let (tx, rx) = channel();
let mut writer = ChanWriter::new(tx);
2014-01-30 16:10:53 -06:00
writer.write_be_u32(42).unwrap();
2013-12-09 11:13:54 -06:00
let wanted = ~[0u8, 0u8, 0u8, 42u8];
let got = task::try(proc() { rx.recv() }).unwrap();
2013-12-09 11:13:54 -06:00
assert_eq!(wanted, got);
2014-01-30 16:10:53 -06:00
match writer.write_u8(1) {
Ok(..) => fail!(),
Err(e) => assert_eq!(e.kind, io::BrokenPipe),
}
2013-12-09 11:13:54 -06:00
}
}