summaryrefslogtreecommitdiffstats
path: root/library/std/src/sys/windows/stdio_uwp.rs
blob: 32550f796ec64d8ba818caf51d00c18100e3041a (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
#![unstable(issue = "none", feature = "windows_stdio")]

use crate::io;
use crate::mem::ManuallyDrop;
use crate::os::windows::io::FromRawHandle;
use crate::sys::c;
use crate::sys::handle::Handle;

pub struct Stdin {}
pub struct Stdout;
pub struct Stderr;

const MAX_BUFFER_SIZE: usize = 8192;
pub const STDIN_BUF_SIZE: usize = MAX_BUFFER_SIZE / 2 * 3;

pub fn get_handle(handle_id: c::DWORD) -> io::Result<c::HANDLE> {
    let handle = unsafe { c::GetStdHandle(handle_id) };
    if handle == c::INVALID_HANDLE_VALUE {
        Err(io::Error::last_os_error())
    } else if handle.is_null() {
        Err(io::Error::from_raw_os_error(c::ERROR_INVALID_HANDLE as i32))
    } else {
        Ok(handle)
    }
}

fn write(handle_id: c::DWORD, data: &[u8]) -> io::Result<usize> {
    let handle = get_handle(handle_id)?;
    // SAFETY: The handle returned from `get_handle` must be valid and non-null.
    let handle = unsafe { Handle::from_raw_handle(handle) };
    ManuallyDrop::new(handle).write(data)
}

impl Stdin {
    pub const fn new() -> Stdin {
        Stdin {}
    }
}

impl io::Read for Stdin {
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        let handle = get_handle(c::STD_INPUT_HANDLE)?;
        // SAFETY: The handle returned from `get_handle` must be valid and non-null.
        let handle = unsafe { Handle::from_raw_handle(handle) };
        ManuallyDrop::new(handle).read(buf)
    }
}

impl Stdout {
    pub const fn new() -> Stdout {
        Stdout
    }
}

impl io::Write for Stdout {
    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
        write(c::STD_OUTPUT_HANDLE, buf)
    }

    fn flush(&mut self) -> io::Result<()> {
        Ok(())
    }
}

impl Stderr {
    pub const fn new() -> Stderr {
        Stderr
    }
}

impl io::Write for Stderr {
    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
        write(c::STD_ERROR_HANDLE, buf)
    }

    fn flush(&mut self) -> io::Result<()> {
        Ok(())
    }
}

pub fn is_ebadf(err: &io::Error) -> bool {
    err.raw_os_error() == Some(c::ERROR_INVALID_HANDLE as i32)
}

pub fn panic_output() -> Option<impl io::Write> {
    Some(Stderr::new())
}