1
Fork 0

Runtime removal: refactor tty

This patch continues runtime removal by moving the tty implementations
into `sys`.

Because this eliminates APIs in `libnative` and `librustrt`, it is a:

[breaking-change]

This functionality is likely to be available publicly, in some form,
from `std` in the future.
This commit is contained in:
Aaron Turon 2014-10-17 13:33:08 -07:00
parent b8f1193bb1
commit 431dcdc840
8 changed files with 112 additions and 96 deletions

View file

@ -99,30 +99,4 @@ impl IoFactory {
}
impl rtio::IoFactory for IoFactory {
#[cfg(unix)]
fn tty_open(&mut self, fd: c_int, _readable: bool)
-> IoResult<Box<rtio::RtioTTY + Send>> {
if unsafe { libc::isatty(fd) } != 0 {
Ok(box file::FileDesc::new(fd, true) as Box<rtio::RtioTTY + Send>)
} else {
Err(IoError {
code: libc::ENOTTY as uint,
extra: 0,
detail: None,
})
}
}
#[cfg(windows)]
fn tty_open(&mut self, fd: c_int, _readable: bool)
-> IoResult<Box<rtio::RtioTTY + Send>> {
if tty::is_tty(fd) {
Ok(box tty::WindowsTTY::new(fd) as Box<rtio::RtioTTY + Send>)
} else {
Err(IoError {
code: libc::ERROR_INVALID_HANDLE as uint,
extra: 0,
detail: None,
})
}
}
}

View file

@ -36,7 +36,7 @@ use kinds::Send;
use libc;
use option::{Option, Some, None};
use boxed::Box;
use sys::fs::FileDesc;
use sys::{fs, tty};
use result::{Ok, Err};
use rt;
use rt::local::Local;
@ -74,17 +74,15 @@ use uint;
// tl;dr; TTY works on everything but when windows stdout is redirected, in that
// case pipe also doesn't work, but magically file does!
enum StdSource {
TTY(Box<RtioTTY + Send>),
File(FileDesc),
TTY(tty::TTY),
File(fs::FileDesc),
}
fn src<T>(fd: libc::c_int, readable: bool, f: |StdSource| -> T) -> T {
LocalIo::maybe_raise(|io| {
Ok(match io.tty_open(fd, readable) {
Ok(tty) => f(TTY(tty)),
Err(_) => f(File(FileDesc::new(fd, false))),
})
}).map_err(IoError::from_rtio_error).unwrap()
fn src<T>(fd: libc::c_int, _readable: bool, f: |StdSource| -> T) -> T {
match tty::TTY::new(fd) {
Ok(tty) => f(TTY(tty)),
Err(_) => f(File(fs::FileDesc::new(fd, false))),
}
}
local_data_key!(local_stdout: Box<Writer + Send>)
@ -278,7 +276,7 @@ impl Reader for StdReader {
// print!'d prompt not being shown until after the user hits
// enter.
flush();
tty.read(buf).map_err(IoError::from_rtio_error)
tty.read(buf).map(|i| i as uint)
},
File(ref mut file) => file.read(buf).map(|i| i as uint),
};
@ -313,7 +311,7 @@ impl StdWriter {
pub fn winsize(&mut self) -> IoResult<(int, int)> {
match self.inner {
TTY(ref mut tty) => {
tty.get_winsize().map_err(IoError::from_rtio_error)
tty.get_winsize()
}
File(..) => {
Err(IoError {
@ -335,7 +333,7 @@ impl StdWriter {
pub fn set_raw(&mut self, raw: bool) -> IoResult<()> {
match self.inner {
TTY(ref mut tty) => {
tty.set_raw(raw).map_err(IoError::from_rtio_error)
tty.set_raw(raw)
}
File(..) => {
Err(IoError {
@ -372,7 +370,7 @@ impl Writer for StdWriter {
let max_size = if cfg!(windows) {8192} else {uint::MAX};
for chunk in buf.chunks(max_size) {
try!(match self.inner {
TTY(ref mut tty) => tty.write(chunk).map_err(IoError::from_rtio_error),
TTY(ref mut tty) => tty.write(chunk),
File(ref mut file) => file.write(chunk),
})
}

View file

@ -48,6 +48,14 @@ pub fn short_write(n: uint, desc: &'static str) -> IoError {
}
}
pub fn unimpl() -> IoError {
IoError {
kind: io::IoUnavailable,
desc: "operations not yet supported",
detail: None,
}
}
// unix has nonzero values as errors
pub fn mkerr_libc<Int: num::Zero>(ret: Int) -> IoResult<()> {
if !ret.is_zero() {

View file

@ -137,25 +137,6 @@ impl FileDesc {
}
}
/*
impl RtioTTY for FileDesc {
fn read(&mut self, buf: &mut [u8]) -> IoResult<uint> {
self.inner_read(buf)
}
fn write(&mut self, buf: &[u8]) -> IoResult<()> {
self.inner_write(buf)
}
fn set_raw(&mut self, _raw: bool) -> IoResult<()> {
Err(super::unimpl())
}
fn get_winsize(&mut self) -> IoResult<(int, int)> {
Err(super::unimpl())
}
fn isatty(&self) -> bool { false }
}
*/
impl Drop for FileDesc {
fn drop(&mut self) {
// closing stdio file handles makes no sense, so never do it. Also, note

View file

@ -35,6 +35,7 @@ pub mod pipe;
pub mod helper_signal;
pub mod process;
pub mod timer;
pub mod tty;
pub mod addrinfo {
pub use sys_common::net::get_host_addresses;

View file

@ -0,0 +1,47 @@
// Copyright 2014 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 sys::fs::FileDesc;
use prelude::*;
use libc::{mod, c_int};
use io::{mod, IoResult, IoError};
use sys_common;
pub struct TTY {
pub fd: FileDesc,
}
impl TTY {
pub fn new(fd: c_int) -> IoResult<TTY> {
if unsafe { libc::isatty(fd) } != 0 {
Ok(TTY { fd: FileDesc::new(fd, true) })
} else {
Err(IoError {
kind: io::MismatchedFileTypeForOperation,
desc: "file descriptor is not a TTY",
detail: None,
})
}
}
pub fn read(&mut self, buf: &mut [u8]) -> IoResult<uint> {
self.fd.read(buf)
}
pub fn write(&mut self, buf: &[u8]) -> IoResult<()> {
self.fd.write(buf)
}
pub fn set_raw(&mut self, _raw: bool) -> IoResult<()> {
Err(sys_common::unimpl())
}
pub fn get_winsize(&mut self) -> IoResult<(int, int)> {
Err(sys_common::unimpl())
}
pub fn isatty(&self) -> bool { false }
}

View file

@ -42,6 +42,7 @@ pub mod pipe;
pub mod helper_signal;
pub mod process;
pub mod timer;
pub mod tty;
pub mod addrinfo {
pub use sys_common::net::get_host_addresses;

View file

@ -33,16 +33,16 @@ use super::c::{ENABLE_PROCESSED_INPUT, ENABLE_QUICK_EDIT_MODE};
use libc::{c_int, HANDLE, LPDWORD, DWORD, LPVOID};
use libc::{get_osfhandle, CloseHandle};
use libc::types::os::arch::extra::LPCVOID;
use std::io::MemReader;
use std::ptr;
use std::rt::rtio::{IoResult, IoError, RtioTTY};
use std::str::from_utf8;
use io::{mod, IoError, IoResult, MemReader};
use prelude::*;
use ptr;
use str::from_utf8;
fn invalid_encoding() -> IoError {
IoError {
code: ERROR_ILLEGAL_CHARACTER as uint,
extra: 0,
detail: Some("text was not valid unicode".to_string()),
kind: io::InvalidInput,
desc: "text was not valid unicode",
detail: None,
}
}
@ -56,40 +56,37 @@ pub fn is_tty(fd: c_int) -> bool {
}
}
pub struct WindowsTTY {
pub struct TTY {
closeme: bool,
handle: HANDLE,
utf8: MemReader,
}
impl WindowsTTY {
pub fn new(fd: c_int) -> WindowsTTY {
// If the file descriptor is one of stdin, stderr, or stdout
// then it should not be closed by us
let closeme = match fd {
0...2 => false,
_ => true,
};
let handle = unsafe { get_osfhandle(fd) as HANDLE };
WindowsTTY {
handle: handle,
utf8: MemReader::new(Vec::new()),
closeme: closeme,
impl TTY {
pub fn new(fd: c_int) -> IoResult<TTY> {
if is_tty(fd) {
// If the file descriptor is one of stdin, stderr, or stdout
// then it should not be closed by us
let closeme = match fd {
0...2 => false,
_ => true,
};
let handle = unsafe { get_osfhandle(fd) as HANDLE };
Ok(TTY {
handle: handle,
utf8: MemReader::new(Vec::new()),
closeme: closeme,
})
} else {
Err(IoError {
kind: io::MismatchedFileTypeForOperation,
desc: "invalid handle provided to function",
detail: None,
})
}
}
}
impl Drop for WindowsTTY {
fn drop(&mut self) {
if self.closeme {
// Nobody cares about the return value
let _ = unsafe { CloseHandle(self.handle) };
}
}
}
impl RtioTTY for WindowsTTY {
fn read(&mut self, buf: &mut [u8]) -> IoResult<uint> {
pub fn read(&mut self, buf: &mut [u8]) -> IoResult<uint> {
// Read more if the buffer is empty
if self.utf8.eof() {
let mut utf16 = Vec::from_elem(0x1000, 0u16);
@ -113,7 +110,7 @@ impl RtioTTY for WindowsTTY {
Ok(self.utf8.read(buf).unwrap())
}
fn write(&mut self, buf: &[u8]) -> IoResult<()> {
pub fn write(&mut self, buf: &[u8]) -> IoResult<()> {
let utf16 = match from_utf8(buf) {
Some(utf8) => {
utf8.as_slice().utf16_units().collect::<Vec<u16>>()
@ -131,7 +128,7 @@ impl RtioTTY for WindowsTTY {
}
}
fn set_raw(&mut self, raw: bool) -> IoResult<()> {
pub fn set_raw(&mut self, raw: bool) -> IoResult<()> {
// FIXME
// Somebody needs to decide on which of these flags we want
match unsafe { SetConsoleMode(self.handle,
@ -146,7 +143,7 @@ impl RtioTTY for WindowsTTY {
}
}
fn get_winsize(&mut self) -> IoResult<(int, int)> {
pub fn get_winsize(&mut self) -> IoResult<(int, int)> {
// FIXME
// Get console buffer via CreateFile with CONOUT$
// Make a CONSOLE_SCREEN_BUFFER_INFO
@ -156,5 +153,14 @@ impl RtioTTY for WindowsTTY {
}
// Let us magically declare this as a TTY
fn isatty(&self) -> bool { true }
pub fn isatty(&self) -> bool { true }
}
impl Drop for TTY {
fn drop(&mut self) {
if self.closeme {
// Nobody cares about the return value
let _ = unsafe { CloseHandle(self.handle) };
}
}
}