rate_common/
output.rs

1//! Unified routines to print data
2//!
3//! We choose to print everything to stdout. This makes sense for a
4//! tool like a proof checker whose output consists of error messages
5//! and diagnostics, not data. It is less suited for pure data
6//! processing programs like `drat2bdrat`, however those fail only
7//! on fatal errors where we cannot guarantee that they did not
8//! print garbage (e.g., incomplete clauses), so the user needs
9//! to handle the exit code anyway.
10
11use atty::{self, Stream};
12use libc::{self, signal};
13use std::{fmt::Display, time::SystemTime};
14
15/// The basename of the current executable.
16pub fn current_executable() -> String {
17    std::env::current_exe()
18        .ok()
19        .and_then(|abspath| {
20            abspath
21                .file_name()
22                .map(|f| f.to_str().unwrap_or("").to_string())
23        })
24        .unwrap_or("".to_string())
25}
26
27/// Unwraps a result, panicking on error.
28pub fn panic_on_error<T>(result: std::io::Result<T>) -> T {
29    result.unwrap_or_else(|error| die!("{}: {}", current_executable(), error))
30}
31
32/// Write a solution line (`"s ..."`) to stdout.
33pub fn print_solution(verdict: &str) {
34    puts!("s {}\n", verdict);
35}
36
37/// Write a key-value pair to stdout.
38pub fn print_key_value(key: &str, value: impl Display) {
39    requires!(key.len() < 35);
40    comment!("{:<35} {:>15}", format!("{}:", key), value);
41}
42
43/// We handle SIGPIPE ourselves to avoid printing errors.
44pub fn install_signal_handler() {
45    // You can't disable assert! in Rust so this is fine.
46    assert!(unsafe { signal(libc::SIGPIPE, libc::SIG_DFL) } != libc::SIG_ERR);
47}
48
49/// Our version of `std::unreachable()`, unsafe if invariants are disabled.
50pub fn unreachable() -> ! {
51    invariant!(false, "unreachable");
52    unsafe { std::hint::unreachable_unchecked() }
53}
54
55/// Check whether we are writing to a terminal.
56pub fn is_a_tty() -> bool {
57    atty::is(Stream::Stdout)
58}
59
60/// A RAII object that prints a timing message when it is destroyed.
61pub struct Timer {
62    /// The name of the thing that is being timed
63    name: &'static str,
64    /// The start time, set at construction time
65    start: SystemTime,
66    /// Whether this timer should be silenced
67    pub disabled: bool,
68}
69
70impl Timer {
71    /// Create a timer with a given name.
72    pub fn name(name: &'static str) -> Timer {
73        Timer {
74            name,
75            start: SystemTime::now(),
76            disabled: false,
77        }
78    }
79}
80
81impl Drop for Timer {
82    /// Write the elapsed time as comment.
83    fn drop(&mut self) {
84        if self.disabled {
85            return;
86        }
87        let elapsed_time = self.start.elapsed().expect("failed to get time");
88        print_key_value(
89            &format!("{} (s)", self.name),
90            format!(
91                "{}.{:03}",
92                elapsed_time.as_secs(),
93                elapsed_time.subsec_millis()
94            ),
95        );
96    }
97}