use std::convert::From;
use std::io;
use std::io::{ErrorKind, Read, Write};
use std::net::{Shutdown, TcpStream};
use super::{ReadHalf, TIoChannel, WriteHalf};
use {new_transport_error, TransportErrorKind};
#[derive(Debug, Default)]
pub struct TTcpChannel {
stream: Option<TcpStream>,
}
impl TTcpChannel {
pub fn new() -> TTcpChannel {
TTcpChannel { stream: None }
}
pub fn with_stream(stream: TcpStream) -> TTcpChannel {
TTcpChannel {
stream: Some(stream),
}
}
pub fn open(&mut self, remote_address: &str) -> ::Result<()> {
if self.stream.is_some() {
Err(new_transport_error(
TransportErrorKind::AlreadyOpen,
"tcp connection previously opened",
))
} else {
match TcpStream::connect(&remote_address) {
Ok(s) => {
self.stream = Some(s);
Ok(())
}
Err(e) => Err(From::from(e)),
}
}
}
pub fn close(&mut self) -> ::Result<()> {
self.if_set(|s| s.shutdown(Shutdown::Both))
.map_err(From::from)
}
fn if_set<F, T>(&mut self, mut stream_operation: F) -> io::Result<T>
where
F: FnMut(&mut TcpStream) -> io::Result<T>,
{
if let Some(ref mut s) = self.stream {
stream_operation(s)
} else {
Err(io::Error::new(
ErrorKind::NotConnected,
"tcp endpoint not connected",
))
}
}
}
impl TIoChannel for TTcpChannel {
fn split(self) -> ::Result<(ReadHalf<Self>, WriteHalf<Self>)>
where
Self: Sized,
{
let mut s = self;
s.stream
.as_mut()
.and_then(|s| s.try_clone().ok())
.map(|cloned| {
let read_half = ReadHalf::new(TTcpChannel {
stream: s.stream.take(),
});
let write_half = WriteHalf::new(TTcpChannel {
stream: Some(cloned),
});
(read_half, write_half)
})
.ok_or_else(|| {
new_transport_error(
TransportErrorKind::Unknown,
"cannot clone underlying tcp stream",
)
})
}
}
impl Read for TTcpChannel {
fn read(&mut self, b: &mut [u8]) -> io::Result<usize> {
self.if_set(|s| s.read(b))
}
}
impl Write for TTcpChannel {
fn write(&mut self, b: &[u8]) -> io::Result<usize> {
self.if_set(|s| s.write(b))
}
fn flush(&mut self) -> io::Result<()> {
self.if_set(|s| s.flush())
}
}