auto merge of #10637 : luqmana/rust/nmt, r=cmr

There's no need for it to be @mut.
This commit is contained in:
bors 2013-11-24 19:07:44 -08:00
commit 09eca11805
4 changed files with 165 additions and 129 deletions

View File

@ -13,7 +13,7 @@
#[allow(missing_doc)];
use std::io;
use std::io::{Decorator, Writer};
#[cfg(not(target_os = "win32"))] use std::os;
#[cfg(not(target_os = "win32"))] use terminfo::*;
@ -94,21 +94,21 @@ fn cap_for_attr(attr: attr::Attr) -> &'static str {
}
#[cfg(not(target_os = "win32"))]
pub struct Terminal {
pub struct Terminal<T> {
priv num_colors: u16,
priv out: @mut io::Writer,
priv out: T,
priv ti: ~TermInfo
}
#[cfg(target_os = "win32")]
pub struct Terminal {
pub struct Terminal<T> {
priv num_colors: u16,
priv out: @mut io::Writer,
priv out: T,
}
#[cfg(not(target_os = "win32"))]
impl Terminal {
pub fn new(out: @mut io::Writer) -> Result<Terminal, ~str> {
impl<T: Writer> Terminal<T> {
pub fn new(out: T) -> Result<Terminal<T>, ~str> {
let term = os::getenv("TERM");
if term.is_none() {
return Err(~"TERM environment variable undefined");
@ -138,7 +138,7 @@ impl Terminal {
/// the corresponding normal color will be used instead.
///
/// Returns true if the color was set, false otherwise.
pub fn fg(&self, color: color::Color) -> bool {
pub fn fg(&mut self, color: color::Color) -> bool {
let color = self.dim_if_necessary(color);
if self.num_colors > color {
let s = expand(*self.ti.strings.find_equiv(&("setaf")).unwrap(),
@ -158,7 +158,7 @@ impl Terminal {
/// the corresponding normal color will be used instead.
///
/// Returns true if the color was set, false otherwise.
pub fn bg(&self, color: color::Color) -> bool {
pub fn bg(&mut self, color: color::Color) -> bool {
let color = self.dim_if_necessary(color);
if self.num_colors > color {
let s = expand(*self.ti.strings.find_equiv(&("setab")).unwrap(),
@ -175,7 +175,7 @@ impl Terminal {
/// Sets the given terminal attribute, if supported.
/// Returns true if the attribute was supported, false otherwise.
pub fn attr(&self, attr: attr::Attr) -> bool {
pub fn attr(&mut self, attr: attr::Attr) -> bool {
match attr {
attr::ForegroundColor(c) => self.fg(c),
attr::BackgroundColor(c) => self.bg(c),
@ -210,7 +210,7 @@ impl Terminal {
}
/// Resets all terminal attributes and color to the default.
pub fn reset(&self) {
pub fn reset(&mut self) {
let mut cap = self.ti.strings.find_equiv(&("sgr0"));
if cap.is_none() {
// are there any terminals that have color/attrs and not sgr0?
@ -242,20 +242,20 @@ impl Terminal {
}
#[cfg(target_os = "win32")]
impl Terminal {
pub fn new(out: @mut io::Writer) -> Result<Terminal, ~str> {
impl<T: Writer> Terminal<T> {
pub fn new(out: T) -> Result<Terminal<T>, ~str> {
return Ok(Terminal {out: out, num_colors: 0});
}
pub fn fg(&self, _color: color::Color) -> bool {
pub fn fg(&mut self, _color: color::Color) -> bool {
false
}
pub fn bg(&self, _color: color::Color) -> bool {
pub fn bg(&mut self, _color: color::Color) -> bool {
false
}
pub fn attr(&self, _attr: attr::Attr) -> bool {
pub fn attr(&mut self, _attr: attr::Attr) -> bool {
false
}
@ -266,3 +266,27 @@ impl Terminal {
pub fn reset(&self) {
}
}
impl<T: Writer> Decorator<T> for Terminal<T> {
fn inner(self) -> T {
self.out
}
fn inner_ref<'a>(&'a self) -> &'a T {
&self.out
}
fn inner_mut_ref<'a>(&'a mut self) -> &'a mut T {
&mut self.out
}
}
impl<T: Writer> Writer for Terminal<T> {
fn write(&mut self, buf: &[u8]) {
self.out.write(buf);
}
fn flush(&mut self) {
self.out.flush();
}
}

View File

@ -32,6 +32,8 @@ use std::clone::Clone;
use std::comm::{stream, SharedChan, GenericPort, GenericChan};
use std::io;
use std::io::File;
use std::io::Writer;
use std::io::stdio::StdWriter;
use std::task;
use std::to_str::ToStr;
use std::f64;
@ -338,10 +340,9 @@ pub enum TestResult {
TrBench(BenchSamples),
}
struct ConsoleTestState {
out: @mut io::Writer,
log_out: Option<@mut io::Writer>,
term: Option<term::Terminal>,
struct ConsoleTestState<T> {
log_out: Option<File>,
out: Either<term::Terminal<T>, T>,
use_color: bool,
total: uint,
passed: uint,
@ -353,22 +354,20 @@ struct ConsoleTestState {
max_name_len: uint, // number of columns to fill when aligning names
}
impl ConsoleTestState {
pub fn new(opts: &TestOpts) -> ConsoleTestState {
impl<T: Writer> ConsoleTestState<T> {
pub fn new(opts: &TestOpts, _: Option<T>) -> ConsoleTestState<StdWriter> {
let log_out = match opts.logfile {
Some(ref path) => Some(@mut File::create(path) as @mut io::Writer),
Some(ref path) => File::create(path),
None => None
};
let out = @mut io::stdio::stdout() as @mut io::Writer;
let term = match term::Terminal::new(out) {
Err(_) => None,
Ok(t) => Some(t)
let out = match term::Terminal::new(io::stdout()) {
Err(_) => Right(io::stdout()),
Ok(t) => Left(t)
};
ConsoleTestState {
out: out,
log_out: log_out,
use_color: use_color(),
term: term,
total: 0u,
passed: 0u,
failed: 0u,
@ -380,115 +379,123 @@ impl ConsoleTestState {
}
}
pub fn write_ok(&self) {
pub fn write_ok(&mut self) {
self.write_pretty("ok", term::color::GREEN);
}
pub fn write_failed(&self) {
pub fn write_failed(&mut self) {
self.write_pretty("FAILED", term::color::RED);
}
pub fn write_ignored(&self) {
pub fn write_ignored(&mut self) {
self.write_pretty("ignored", term::color::YELLOW);
}
pub fn write_metric(&self) {
pub fn write_metric(&mut self) {
self.write_pretty("metric", term::color::CYAN);
}
pub fn write_bench(&self) {
pub fn write_bench(&mut self) {
self.write_pretty("bench", term::color::CYAN);
}
pub fn write_added(&self) {
pub fn write_added(&mut self) {
self.write_pretty("added", term::color::GREEN);
}
pub fn write_improved(&self) {
pub fn write_improved(&mut self) {
self.write_pretty("improved", term::color::GREEN);
}
pub fn write_removed(&self) {
pub fn write_removed(&mut self) {
self.write_pretty("removed", term::color::YELLOW);
}
pub fn write_regressed(&self) {
pub fn write_regressed(&mut self) {
self.write_pretty("regressed", term::color::RED);
}
pub fn write_pretty(&self,
pub fn write_pretty(&mut self,
word: &str,
color: term::color::Color) {
match self.term {
None => self.out.write(word.as_bytes()),
Some(ref t) => {
match self.out {
Left(ref mut term) => {
if self.use_color {
t.fg(color);
term.fg(color);
}
self.out.write(word.as_bytes());
term.write(word.as_bytes());
if self.use_color {
t.reset();
term.reset();
}
}
Right(ref mut stdout) => stdout.write(word.as_bytes())
}
}
pub fn write_plain(&mut self, s: &str) {
match self.out {
Left(ref mut term) => term.write(s.as_bytes()),
Right(ref mut stdout) => stdout.write(s.as_bytes())
}
}
pub fn write_run_start(&mut self, len: uint) {
self.total = len;
let noun = if len != 1 { &"tests" } else { &"test" };
write!(self.out, "\nrunning {} {}\n", len, noun);
self.write_plain(format!("\nrunning {} {}\n", len, noun));
}
pub fn write_test_start(&self, test: &TestDesc, align: NamePadding) {
pub fn write_test_start(&mut self, test: &TestDesc, align: NamePadding) {
let name = test.padded_name(self.max_name_len, align);
write!(self.out, "test {} ... ", name);
self.write_plain(format!("test {} ... ", name));
}
pub fn write_result(&self, result: &TestResult) {
pub fn write_result(&mut self, result: &TestResult) {
match *result {
TrOk => self.write_ok(),
TrFailed => self.write_failed(),
TrIgnored => self.write_ignored(),
TrMetrics(ref mm) => {
self.write_metric();
write!(self.out, ": {}", fmt_metrics(mm));
self.write_plain(format!(": {}", fmt_metrics(mm)));
}
TrBench(ref bs) => {
self.write_bench();
write!(self.out, ": {}", fmt_bench_samples(bs));
self.write_plain(format!(": {}", fmt_bench_samples(bs)));
}
}
write!(self.out, "\n");
self.write_plain("\n");
}
pub fn write_log(&self, test: &TestDesc, result: &TestResult) {
pub fn write_log(&mut self, test: &TestDesc, result: &TestResult) {
match self.log_out {
None => (),
Some(out) => {
write!(out, "{} {}",match *result {
TrOk => ~"ok",
TrFailed => ~"failed",
TrIgnored => ~"ignored",
TrMetrics(ref mm) => fmt_metrics(mm),
TrBench(ref bs) => fmt_bench_samples(bs)
}, test.name.to_str());
Some(ref mut o) => {
let s = format!("{} {}", match *result {
TrOk => ~"ok",
TrFailed => ~"failed",
TrIgnored => ~"ignored",
TrMetrics(ref mm) => fmt_metrics(mm),
TrBench(ref bs) => fmt_bench_samples(bs)
}, test.name.to_str());
o.write(s.as_bytes());
}
}
}
pub fn write_failures(&self) {
write!(self.out, "\nfailures:\n");
pub fn write_failures(&mut self) {
self.write_plain("\nfailures:\n");
let mut failures = ~[];
for f in self.failures.iter() {
failures.push(f.name.to_str());
}
sort::tim_sort(failures);
for name in failures.iter() {
writeln!(self.out, " {}", name.to_str());
self.write_plain(format!(" {}\n", name.to_str()));
}
}
pub fn write_metric_diff(&self, diff: &MetricDiff) {
pub fn write_metric_diff(&mut self, diff: &MetricDiff) {
let mut noise = 0;
let mut improved = 0;
let mut regressed = 0;
@ -501,38 +508,38 @@ impl ConsoleTestState {
MetricAdded => {
added += 1;
self.write_added();
writeln!(self.out, ": {}", *k);
self.write_plain(format!(": {}\n", *k));
}
MetricRemoved => {
removed += 1;
self.write_removed();
writeln!(self.out, ": {}", *k);
self.write_plain(format!(": {}\n", *k));
}
Improvement(pct) => {
improved += 1;
write!(self.out, "{}: ", *k);
self.write_plain(format!(": {}", *k));
self.write_improved();
writeln!(self.out, " by {:.2f}%", pct as f64);
self.write_plain(format!(" by {:.2f}%\n", pct as f64));
}
Regression(pct) => {
regressed += 1;
write!(self.out, "{}: ", *k);
self.write_plain(format!(": {}", *k));
self.write_regressed();
writeln!(self.out, " by {:.2f}%", pct as f64);
self.write_plain(format!(" by {:.2f}%\n", pct as f64));
}
}
}
writeln!(self.out, "result of ratchet: {} matrics added, {} removed, \
{} improved, {} regressed, {} noise",
added, removed, improved, regressed, noise);
self.write_plain(format!("result of ratchet: {} matrics added, {} removed, \
{} improved, {} regressed, {} noise\n",
added, removed, improved, regressed, noise));
if regressed == 0 {
writeln!(self.out, "updated ratchet file");
self.write_plain("updated ratchet file\n");
} else {
writeln!(self.out, "left ratchet file untouched");
self.write_plain("left ratchet file untouched\n");
}
}
pub fn write_run_finish(&self,
pub fn write_run_finish(&mut self,
ratchet_metrics: &Option<Path>,
ratchet_pct: Option<f64>) -> bool {
assert!(self.passed + self.failed + self.ignored + self.measured == self.total);
@ -540,12 +547,12 @@ impl ConsoleTestState {
let ratchet_success = match *ratchet_metrics {
None => true,
Some(ref pth) => {
write!(self.out, "\nusing metrics ratcher: {}\n", pth.display());
self.write_plain(format!("\nusing metrics ratcher: {}\n", pth.display()));
match ratchet_pct {
None => (),
Some(pct) =>
writeln!(self.out, "with noise-tolerance forced to: {}%",
pct)
self.write_plain(format!("with noise-tolerance forced to: {}%\n",
pct))
}
let (diff, ok) = self.metrics.ratchet(pth, ratchet_pct);
self.write_metric_diff(&diff);
@ -560,15 +567,16 @@ impl ConsoleTestState {
let success = ratchet_success && test_success;
write!(self.out, "\ntest result: ");
self.write_plain("\ntest result: ");
if success {
// There's no parallelism at this point so it's safe to use color
self.write_ok();
} else {
self.write_failed();
}
write!(self.out, ". {} passed; {} failed; {} ignored; {} measured\n\n",
self.passed, self.failed, self.ignored, self.measured);
let s = format!(". {} passed; {} failed; {} ignored; {} measured\n\n",
self.passed, self.failed, self.ignored, self.measured);
self.write_plain(s);
return success;
}
}
@ -599,7 +607,7 @@ pub fn fmt_bench_samples(bs: &BenchSamples) -> ~str {
// A simple console test runner
pub fn run_tests_console(opts: &TestOpts,
tests: ~[TestDescAndFn]) -> bool {
fn callback(event: &TestEvent, st: &mut ConsoleTestState) {
fn callback<T: Writer>(event: &TestEvent, st: &mut ConsoleTestState<T>) {
debug!("callback(event={:?})", event);
match (*event).clone() {
TeFiltered(ref filtered_tests) => st.write_run_start(filtered_tests.len()),
@ -632,7 +640,7 @@ pub fn run_tests_console(opts: &TestOpts,
}
}
}
let st = @mut ConsoleTestState::new(opts);
let mut st = ConsoleTestState::new(opts, None::<StdWriter>);
fn len_if_padded(t: &TestDescAndFn) -> uint {
match t.testfn.padding() {
PadNone => 0u,
@ -647,12 +655,12 @@ pub fn run_tests_console(opts: &TestOpts,
},
None => {}
}
run_tests(opts, tests, |x| callback(&x, st));
run_tests(opts, tests, |x| callback(&x, &mut st));
match opts.save_metrics {
None => (),
Some(ref pth) => {
st.metrics.save(pth);
write!(st.out, "\nmetrics saved to: {}", pth.display());
st.write_plain(format!("\nmetrics saved to: {}", pth.display()));
}
}
return st.write_run_finish(&opts.ratchet_metrics, opts.ratchet_noise_percent);
@ -660,13 +668,11 @@ pub fn run_tests_console(opts: &TestOpts,
#[test]
fn should_sort_failures_before_printing_them() {
use std::io;
use std::io::Decorator;
use std::io::mem::MemWriter;
use std::str;
fn dummy() {}
let m = @mut MemWriter::new();
let test_a = TestDesc {
name: StaticTestName("a"),
ignore: false,
@ -679,10 +685,9 @@ fn should_sort_failures_before_printing_them() {
should_fail: false
};
let st = @ConsoleTestState {
out: m as @mut io::Writer,
let mut st = ConsoleTestState {
log_out: None,
term: None,
out: Right(MemWriter::new()),
use_color: false,
total: 0u,
passed: 0u,
@ -695,7 +700,10 @@ fn should_sort_failures_before_printing_them() {
};
st.write_failures();
let s = str::from_utf8(*m.inner_ref());
let s = match st.out {
Right(ref m) => str::from_utf8(*m.inner_ref()),
Left(_) => unreachable!()
};
let apos = s.find_str("a").unwrap();
let bpos = s.find_str("b").unwrap();

View File

@ -12,35 +12,32 @@ use extra::term;
use std::io;
pub fn note(msg: &str) {
pretty_message(msg, "note: ", term::color::GREEN,
@mut io::stdout() as @mut io::Writer)
pretty_message(msg, "note: ", term::color::GREEN);
}
pub fn warn(msg: &str) {
pretty_message(msg, "warning: ", term::color::YELLOW,
@mut io::stdout() as @mut io::Writer)
pretty_message(msg, "warning: ", term::color::YELLOW);
}
pub fn error(msg: &str) {
pretty_message(msg, "error: ", term::color::RED,
@mut io::stdout() as @mut io::Writer)
pretty_message(msg, "error: ", term::color::RED);
}
fn pretty_message<'a>(msg: &'a str,
prefix: &'a str,
color: term::color::Color,
out: @mut io::Writer) {
let term = term::Terminal::new(out);
color: term::color::Color) {
let mut term = term::Terminal::new(io::stdout());
let mut stdout = io::stdout();
match term {
Ok(ref t) => {
Ok(ref mut t) => {
t.fg(color);
out.write(prefix.as_bytes());
t.write(prefix.as_bytes());
t.reset();
},
_ => {
out.write(prefix.as_bytes());
stdout.write(prefix.as_bytes());
}
}
out.write(msg.as_bytes());
out.write(['\n' as u8]);
stdout.write(msg.as_bytes());
stdout.write(['\n' as u8]);
}

View File

@ -12,6 +12,7 @@ use codemap::{Pos, Span};
use codemap;
use std::io;
use std::io::stdio::StdWriter;
use std::local_data;
use extra::term;
@ -197,38 +198,44 @@ fn diagnosticcolor(lvl: level) -> term::color::Color {
}
fn print_maybe_styled(msg: &str, color: term::attr::Attr) {
local_data_key!(tls_terminal: @Option<term::Terminal>)
local_data_key!(tls_terminal: ~Option<term::Terminal<StdWriter>>)
let stderr = @mut io::stderr() as @mut io::Writer;
fn is_stderr_screen() -> bool {
use std::libc;
unsafe { libc::isatty(libc::STDERR_FILENO) != 0 }
}
fn write_pretty<T: Writer>(term: &mut term::Terminal<T>, s: &str, c: term::attr::Attr) {
term.attr(c);
term.write(s.as_bytes());
term.reset();
}
if is_stderr_screen() {
let t = match local_data::get(tls_terminal, |v| v.map(|k| *k)) {
None => {
let t = term::Terminal::new(stderr);
let tls = @match t {
Ok(t) => Some(t),
Err(_) => None
};
local_data::set(tls_terminal, tls);
&*tls
local_data::get_mut(tls_terminal, |term| {
match term {
Some(term) => {
match **term {
Some(ref mut term) => write_pretty(term, msg, color),
None => io::stderr().write(msg.as_bytes())
}
}
None => {
let t = ~match term::Terminal::new(io::stderr()) {
Ok(mut term) => {
write_pretty(&mut term, msg, color);
Some(term)
}
Err(_) => {
io::stderr().write(msg.as_bytes());
None
}
};
local_data::set(tls_terminal, t);
}
}
Some(tls) => &*tls
};
match t {
&Some(ref term) => {
term.attr(color);
write!(stderr, "{}", msg);
term.reset();
},
_ => write!(stderr, "{}", msg)
}
});
} else {
write!(stderr, "{}", msg);
io::stderr().write(msg.as_bytes());
}
}