diff --git a/examples/examples.rs b/examples/examples.rs index 95840fc..4369c27 100644 --- a/examples/examples.rs +++ b/examples/examples.rs @@ -28,6 +28,8 @@ use crossterm::cursor::cursor; use std::io::Read; fn main() { + use crossterm::color; + let input = CROSSTERM.input(); let mut stdin = input.read_async().bytes(); CROSSTERM.cursor().hide(); diff --git a/examples/program_examples/snake/Cargo.toml b/examples/program_examples/snake/Cargo.toml new file mode 100644 index 0000000..b03910c --- /dev/null +++ b/examples/program_examples/snake/Cargo.toml @@ -0,0 +1,11 @@ +[package] +name = "first_depth_search" +version = "0.1.0" +authors = ["TimonPost "] + +[dependencies] +rand = "0.4.2" + +[dependencies.crossterm] +path = "../../../" +branch = "development" \ No newline at end of file diff --git a/examples/program_examples/snake/src/main.rs b/examples/program_examples/snake/src/main.rs new file mode 100644 index 0000000..726c2e9 --- /dev/null +++ b/examples/program_examples/snake/src/main.rs @@ -0,0 +1,141 @@ +extern crate crossterm; +extern crate rand; + +mod map; +mod snake; +mod variables; +mod messages; + +use self::crossterm::input::input; +use self::crossterm::terminal::{terminal, ClearType}; +use self::crossterm::style::Color; + +use self::crossterm::{Screen, Crossterm}; + +use map::Map; +use variables::{Size, Direction, Position}; +use snake::Snake; + +use std::collections::HashMap; +use std::{thread, time}; +use std::iter::Iterator; +use std::io::Read; +use std::io::Write; + +fn main() { + let map_size = title_screen(); + + { + let mut screen = Screen::new(true); + let crossterm = Crossterm::new(&screen); + + let cursor = crossterm.cursor(); + let mut input = crossterm.input(); + + cursor.hide(); + let mut stdin = input.read_async().bytes(); + + let mut free_positions: HashMap = HashMap::with_capacity((map_size.width * map_size.height) as usize); + + let mut map = Map::new(map_size.clone()); + map.render_map(&screen, &mut free_positions); + + let mut direction = Direction::Right; + + let mut snake = Snake::new(map_size.clone()); + + for part in snake.get_parts().iter() { + free_positions.remove_entry(format!("{},{}", part.position.x, part.position.y).as_str()); + } + + map.spawn_food(&free_positions, &screen); + + loop { + thread::sleep(time::Duration::from_millis(500)); + let pressed_key = stdin.next(); + + if let Some(Ok(key)) = pressed_key { + match key as char { + 'w' => direction = Direction::Up, + 'a' => direction = Direction::Left, + 's' => direction = Direction::Down, + 'd' => direction = Direction::Right, + _ => {} + } + } + + snake.move_snake(&direction, &screen, &mut free_positions); + + if map.is_out_of_bounds(snake.snake_parts[0].position) + { + break; + } + + snake.draw_snake(&screen); + + + + if snake.has_eaten_food(map.foot_pos) + { + map.spawn_food(&free_positions, &screen); + } + + + } + } + game_over_screen(); +} + +fn title_screen() -> Size +{ + let crossterm = Crossterm::new(&Screen::default()); + + let cursor = crossterm.cursor(); + let terminal = crossterm.terminal().clear(ClearType::All); + + println!("{}",messages::SNAKERS.join("\n\r")); + cursor.goto(0, 15); + println!("Enter map width:"); + cursor.goto(17, 15); + let width = crossterm.input().read_line().unwrap(); + println!("\n\rEnter map height:"); + cursor.goto(17, 16); + let height = crossterm.input().read_line().unwrap(); + + let parsed_width = width.parse::().unwrap(); + let parsed_height = height.parse::().unwrap(); + + let terminal = crossterm.terminal().clear(ClearType::All); + + return Size::new(parsed_width, parsed_height); +} + +fn print_game_stats(map_size: Size, snake_lenght: usize, food_aten: usize, screen: &mut Screen) +{ + let crossterm = Crossterm::new(&Screen::default()); + + let cursor = crossterm.cursor(); + let terminal = crossterm.terminal().clear(ClearType::All); + + screen.write(format!("Snake Lenght: {}\n\r", snake_lenght).as_ref()); + screen.write(format!("Food aten: {}\n\r", snake_lenght).as_ref()); + + cursor.goto(0,map_size.height as u16); + cursor.goto(0,map_size.height as u16); +} + +fn game_over_screen() +{ + let crossterm = Crossterm::new(&Screen::default()); + + let cursor = crossterm.cursor(); + let terminal = crossterm.terminal(); + + terminal.clear(ClearType::All); + + println!("{}",messages::END_MESSAGE.join("\n\r")); +// cursor.goto() + cursor.show(); +} + + diff --git a/examples/program_examples/snake/src/map.rs b/examples/program_examples/snake/src/map.rs index e69de29..5b5e10b 100644 --- a/examples/program_examples/snake/src/map.rs +++ b/examples/program_examples/snake/src/map.rs @@ -0,0 +1,80 @@ +use super::variables::{Position, Size, Direction }; +use super::snake::Snake; + +use crossterm::{Crossterm, Screen}; +use crossterm::cursor::cursor; +use crossterm::style::{ObjectStyle, StyledObject, Color, style}; + +use rand::distributions::{IndependentSample, Range}; + +use std::hash::Hash; +use std::collections::HashMap; +use std::fmt::Display; +use std::ops::Index; + +use rand; + +pub struct Map +{ + pub size: Size, + pub foot_pos: Position, +} + +impl Map +{ + pub fn new(size: Size) -> Self + { + Map { size: size, foot_pos: Position::new(0,0) } + } + + // render the map on the screen. + pub fn render_map(&mut self, screen: &Screen, free_positions: &mut HashMap) + { + let crossterm = Crossterm::new(screen); + let mut cursor = crossterm.cursor(); + let mut terminal = crossterm.terminal(); + + for y in 0..self.size.height + { + for x in 0..self.size.height + { + if (y == 0 || y == self.size.height - 1) || (x == 0 || x == self.size.width - 1) + { + cursor.goto(x as u16, y as u16); + terminal.write("█") + }else { + free_positions.insert(format!("{},{}",x,y), Position::new(x,y)); + } + } + } + } + + pub fn is_out_of_bounds(&self, new_pos: Position) -> bool + { + if (new_pos.x == 0 || new_pos.x == self.size.width) || (new_pos.y == 0 || new_pos.y == self.size.height) + { + return true; + } + + return false; + } + + pub fn is_food_eaten(&self, snake_head: Position) -> bool + { + snake_head.x == self.foot_pos.x && snake_head.y == self.foot_pos.y + } + + pub fn spawn_food(&mut self, free_positions: &HashMap, screen: &Screen) + { + let index = Range::new(0, free_positions.len()).ind_sample(&mut rand::thread_rng()); + self.foot_pos = free_positions.values().skip(index).next().unwrap().clone(); + self.draw_food(screen); + } + + fn draw_food(&self, screen: &Screen) + { + cursor(screen).goto(self.foot_pos.x as u16, self.foot_pos.y as u16); + style("$").with(Color::Green).paint(screen); + screen.stdout.flush(); + } +} \ No newline at end of file diff --git a/examples/program_examples/snake/src/messages.rs b/examples/program_examples/snake/src/messages.rs index e69de29..f23f366 100644 --- a/examples/program_examples/snake/src/messages.rs +++ b/examples/program_examples/snake/src/messages.rs @@ -0,0 +1,30 @@ +pub const SNAKERS: [&str; 11] = +[ + " ▄▄▄▄▄▄▄▄▄▄▄ ▄▄ ▄ ▄▄▄▄▄▄▄▄▄▄▄ ▄ ▄ ▄▄▄▄▄▄▄▄▄▄▄ ▄▄▄▄▄▄▄▄▄▄▄ ▄▄▄▄▄▄▄▄▄▄▄ ", + "▐░░░░░░░░░░░▌▐░░▌ ▐░▌▐░░░░░░░░░░░▌▐░▌ ▐░▌▐░░░░░░░░░░░▌▐░░░░░░░░░░░▌▐░░░░░░░░░░░▌", + "▐░█▀▀▀▀▀▀▀▀▀ ▐░▌░▌ ▐░▌▐░█▀▀▀▀▀▀▀█░▌▐░▌ ▐░▌ ▐░█▀▀▀▀▀▀▀▀▀ ▐░█▀▀▀▀▀▀▀█░▌▐░█▀▀▀▀▀▀▀▀▀", + "▐░▌ ▐░▌▐░▌ ▐░▌▐░▌ ▐░▌▐░▌▐░▌ ▐░▌ ▐░▌ ▐░▌▐░▌", + "▐░█▄▄▄▄▄▄▄▄▄ ▐░▌ ▐░▌ ▐░▌▐░█▄▄▄▄▄▄▄█░▌▐░▌░▌ ▐░█▄▄▄▄▄▄▄▄▄ ▐░█▄▄▄▄▄▄▄█░▌▐░█▄▄▄▄▄▄▄▄▄", + "▐░░░░░░░░░░░▌▐░▌ ▐░▌ ▐░▌▐░░░░░░░░░░░▌▐░░▌ ▐░░░░░░░░░░░▌▐░░░░░░░░░░░▌▐░░░░░░░░░░░▌", + " ▀▀▀▀▀▀▀▀▀█░▌▐░▌ ▐░▌ ▐░▌▐░█▀▀▀▀▀▀▀█░▌▐░▌░▌ ▐░█▀▀▀▀▀▀▀▀▀ ▐░█▀▀▀▀█░█▀▀ ▀▀▀▀▀▀▀▀▀█░▌", + " ▐░▌▐░▌ ▐░▌▐░▌▐░▌ ▐░▌▐░▌▐░▌ ▐░▌ ▐░▌ ▐░▌ ▐░▌", + " ▄▄▄▄▄▄▄▄▄█░▌▐░▌ ▐░▐░▌▐░▌ ▐░▌▐░▌ ▐░▌ ▐░█▄▄▄▄▄▄▄▄▄ ▐░▌ ▐░▌ ▄▄▄▄▄▄▄▄▄█░▌", + "▐░░░░░░░░░░░▌▐░▌ ▐░░▌▐░▌ ▐░▌▐░▌ ▐░▌▐░░░░░░░░░░░▌▐░▌ ▐░▌▐░░░░░░░░░░░▌", + " ▀▀▀▀▀▀▀▀▀▀▀ ▀ ▀▀ ▀ ▀ ▀ ▀ ▀▀▀▀▀▀▀▀▀▀▀ ▀ ▀ ▀▀▀▀▀▀▀▀▀▀▀" +]; + +pub const END_MESSAGE: [&str; 11] = +[ + " ▄▄▄▄▄▄▄▄▄▄▄ ▄▄▄▄▄▄▄▄▄▄▄ ▄▄ ▄▄ ▄▄▄▄▄▄▄▄▄▄▄ ▄▄▄▄▄▄▄▄▄▄▄ ▄ ▄ ▄▄▄▄▄▄▄▄▄▄▄ ▄▄▄▄▄▄▄▄▄▄▄ ", + " ▐░░░░░░░░░░░▌▐░░░░░░░░░░░▌▐░░▌ ▐░░▌▐░░░░░░░░░░░▌ ▐░░░░░░░░░░░▌▐░▌ ▐░▌▐░░░░░░░░░░░▌▐░░░░░░░░░░░▌ ", + " ▐░█▀▀▀▀▀▀▀▀▀ ▐░█▀▀▀▀▀▀▀█░▌▐░▌░▌ ▐░▐░▌▐░█▀▀▀▀▀▀▀▀▀ ▐░█▀▀▀▀▀▀▀█░▌ ▐░▌ ▐░▌ ▐░█▀▀▀▀▀▀▀▀▀ ▐░█▀▀▀▀▀▀▀█░▌ ", + " ▐░▌ ▐░▌ ▐░▌▐░▌▐░▌ ▐░▌▐░▌▐░▌ ▐░▌ ▐░▌ ▐░▌ ▐░▌ ▐░▌ ▐░▌ ▐░▌ ", + " ▐░▌ ▄▄▄▄▄▄▄▄ ▐░█▄▄▄▄▄▄▄█░▌▐░▌ ▐░▐░▌ ▐░▌▐░█▄▄▄▄▄▄▄▄▄ ▐░▌ ▐░▌ ▐░▌ ▐░▌ ▐░█▄▄▄▄▄▄▄▄▄ ▐░█▄▄▄▄▄▄▄█░▌ ", + " ▐░▌▐░░░░░░░░▌▐░░░░░░░░░░░▌▐░▌ ▐░▌ ▐░▌▐░░░░░░░░░░░▌ ▐░▌ ▐░▌ ▐░▌ ▐░▌ ▐░░░░░░░░░░░▌▐░░░░░░░░░░░▌ ", + " ▐░▌ ▀▀▀▀▀▀█░▌▐░█▀▀▀▀▀▀▀█░▌▐░▌ ▀ ▐░▌▐░█▀▀▀▀▀▀▀▀▀ ▐░▌ ▐░▌ ▐░▌ ▐░▌ ▐░█▀▀▀▀▀▀▀▀▀ ▐░█▀▀▀▀█░█▀▀ ", + " ▐░▌ ▐░▌▐░▌ ▐░▌▐░▌ ▐░▌▐░▌ ▐░▌ ▐░▌ ▐░▌ ▐░▌ ▐░▌ ▐░▌ ▐░▌ ", + " ▐░█▄▄▄▄▄▄▄█░▌▐░▌ ▐░▌▐░▌ ▐░▌▐░█▄▄▄▄▄▄▄▄▄ ▐░█▄▄▄▄▄▄▄█░▌ ▐░▐░▌ ▐░█▄▄▄▄▄▄▄▄▄ ▐░▌ ▐░▌ ", + " ▐░░░░░░░░░░░▌▐░▌ ▐░▌▐░▌ ▐░▌▐░░░░░░░░░░░▌ ▐░░░░░░░░░░░▌ ▐░▌ ▐░░░░░░░░░░░▌▐░▌ ▐░▌ ", + " ▀▀▀▀▀▀▀▀▀▀▀ ▀ ▀ ▀ ▀ ▀▀▀▀▀▀▀▀▀▀▀ ▀▀▀▀▀▀▀▀▀▀▀ ▀ ▀▀▀▀▀▀▀▀▀▀▀ ▀ ▀ ", + +]; \ No newline at end of file diff --git a/examples/program_examples/snake/src/snake.rs b/examples/program_examples/snake/src/snake.rs index e69de29..ed89a33 100644 --- a/examples/program_examples/snake/src/snake.rs +++ b/examples/program_examples/snake/src/snake.rs @@ -0,0 +1,100 @@ +use crossterm::{Screen, Crossterm}; +use crossterm::style::Color; +use super::variables::{Position, Direction, Size}; + +use std::collections::HashMap; + +pub struct Part +{ + pub position: Position, +} + +impl Part +{ + pub fn new(x: usize, y: usize) -> Part + { + Part { position: Position::new(x,y) } + } +} + +pub struct Snake +{ + pub snake_parts: Vec, + pub parent_pos: Position, + map_size: Size +} + +impl Snake +{ + pub fn new(map_size: Size) -> Snake + { + return Snake { map_size, snake_parts: vec![Part::new(9, 10), Part::new(8, 10)], parent_pos: Position::new(0,0) } + } + + pub fn move_snake(&mut self, direction: &Direction, screen: &Screen, free_positions: &mut HashMap ) + { + let crossterm = Crossterm::new(screen); + let cursor = crossterm.cursor(); + let terminal = crossterm.terminal(); + + let count = self.snake_parts.len(); + let is_food_eaten = false; + + for (index, ref mut snake_part) in self.snake_parts.iter_mut().enumerate() { + if index == count - 1 + { + snake_part.position.remove(screen); + free_positions.insert(format!("{},{}",snake_part.position.x,snake_part.position.y), snake_part.position); + } + + if index == 0 + { + self.parent_pos = snake_part.position.clone(); + + match direction { + &Direction::Up => { snake_part.position.y -= 1 }, + &Direction::Down => { snake_part.position.y += 1 }, + &Direction::Left => { snake_part.position.x -= 1 }, + &Direction::Right => { snake_part.position.x += 1 }, + } + + free_positions.remove_entry(format!("{},{}",snake_part.position.x,snake_part.position.y).as_str()); + + } else { + let new_pos = self.parent_pos.clone(); + self.parent_pos = snake_part.position.clone(); + snake_part.position = new_pos; + } + } + } + + pub fn draw_snake(&mut self, screen: &Screen) + { + for (index, ref mut snake_part) in self.snake_parts.iter_mut().enumerate() { + snake_part.position.draw("■", screen); + } + } + + pub fn has_eaten_food(&mut self, food_pos: Position) -> bool + { + if self.snake_parts[0].position.x == food_pos.x && self.snake_parts[0].position.y == food_pos.y + { + self.snake_parts.push(Part::new(1,1)); + return true; + } + + return false; + } + + pub fn get_parts(&self) -> &Vec + { + return &self.snake_parts; + } +} + +pub enum SnakeState +{ + MovedOutMap, + Moved, + AteFood +} \ No newline at end of file diff --git a/examples/program_examples/snake/src/variables.rs b/examples/program_examples/snake/src/variables.rs index e69de29..0311631 100644 --- a/examples/program_examples/snake/src/variables.rs +++ b/examples/program_examples/snake/src/variables.rs @@ -0,0 +1,61 @@ +extern crate crossterm; + +use self::crossterm::terminal::{terminal, ClearType}; +use self::crossterm::style::{Color, StyledObject, ObjectStyle, style }; +use self::crossterm::cursor::cursor; +use self::crossterm::Screen; + +use std::fmt::Debug; +use std::fmt; + +#[derive(Copy, Clone,Debug)] +pub enum Direction +{ + Up = 0, + Down = 1, + Left = 2, + Right = 3 +} + +#[derive(Copy, Clone, Debug, PartialOrd, PartialEq)] +pub struct Position +{ + pub x: usize, + pub y: usize +} + +impl Position +{ + pub fn new(x: usize, y: usize) -> Position + { + Position { x, y } + } + + pub fn draw(&self, val: &str, screen: &Screen) + { + cursor(screen).goto(self.x as u16, self.y as u16); + style(val).with(Color::Red).paint(&screen); + screen.stdout.flush(); + } + + pub fn remove(&self, screen: &Screen) + { + cursor(screen).goto(self.x as u16, self.y as u16); + terminal(&screen).write(" "); + } +} + +#[derive(Copy, Clone)] +pub struct Size +{ + pub width: usize, + pub height: usize +} + +impl Size +{ + pub fn new(width: usize, height: usize) -> Size + { + Size {width,height} + } +} \ No newline at end of file diff --git a/src/modules/write/ansi_stdout.rs b/src/modules/output/ansi_output.rs similarity index 90% rename from src/modules/write/ansi_stdout.rs rename to src/modules/output/ansi_output.rs index 2a4bb7c..26a32ba 100644 --- a/src/modules/write/ansi_stdout.rs +++ b/src/modules/output/ansi_output.rs @@ -11,11 +11,11 @@ use std::io::{self, Read, Write,Stdout, stdout}; use std::str::from_utf8; /// This struct is a wrapper for `Stdout` -pub struct AnsiStdout { +pub struct AnsiOutput { pub handle: Stdout, } -impl IStdout for AnsiStdout { +impl IStdout for AnsiOutput { fn write_str(&self, string: &str) -> io::Result { let out = &self.handle; let mut handle = out.lock(); @@ -47,8 +47,8 @@ impl IStdout for AnsiStdout { } } -impl AnsiStdout { +impl AnsiOutput { pub fn new() -> Self { - AnsiStdout { handle: stdout() } + AnsiOutput { handle: stdout() } } } diff --git a/src/modules/write/mod.rs b/src/modules/output/mod.rs similarity index 85% rename from src/modules/write/mod.rs rename to src/modules/output/mod.rs index ce9e9a6..4e01f94 100644 --- a/src/modules/write/mod.rs +++ b/src/modules/output/mod.rs @@ -1,16 +1,16 @@ //! This module provides a way to work with an handle to an screen on different platforms. -mod stdout; +mod output; -mod ansi_stdout; +mod ansi_output; #[cfg(target_os = "windows")] -mod winapi_stdout; +mod winapi_output; -pub use self::ansi_stdout::AnsiStdout; +pub use self::ansi_output::AnsiOutput; #[cfg(target_os = "windows")] -pub use self::winapi_stdout::WinApiStdout; +pub use self::winapi_output::WinApiOutput; -pub use self::stdout::Stdout; +pub use self::output::TerminalOutput; use std::any::Any; use std::io; diff --git a/src/modules/write/stdout.rs b/src/modules/output/output.rs similarity index 77% rename from src/modules/write/stdout.rs rename to src/modules/output/output.rs index 045df43..1a84932 100644 --- a/src/modules/write/stdout.rs +++ b/src/modules/output/output.rs @@ -34,67 +34,67 @@ use std::sync::Arc; /// This handle could be used to write to the current screen /// /// For unix and windows 10 `stdout()` will be used for handle when on windows systems with versions lower than 10 WinApi `HANDLE` will be used. -pub struct Stdout { - screen_manager: Box, +pub struct TerminalOutput { + stdout: Box, pub is_in_raw_mode:bool, } -impl Stdout { +impl TerminalOutput { /// Create new screen write instance whereon screen related actions can be performed. pub fn new(is_in_raw_mode: bool) -> Self { #[cfg(target_os = "windows")] - let screen_manager: Box = functions::get_module::>( + let stdout: Box = functions::get_module::>( Box::from(WinApiStdout::new()), Box::from(AnsiStdout::new()), ).unwrap(); #[cfg(not(target_os = "windows"))] - let screen_manager = Box::from(AnsiStdout::new()) as Box; + let stdout = Box::from(AnsiStdout::new()) as Box; - Stdout { screen_manager , is_in_raw_mode} + TerminalOutput { stdout , is_in_raw_mode} } /// Write String to the current screen. pub fn write_string(&self, string: String) -> io::Result { - self.screen_manager.write_str(string.as_str()) + self.stdout.write_str(string.as_str()) } /// Flush the current screen. pub fn flush(&self) -> io::Result<()> { - self.screen_manager.flush() + self.stdout.flush() } /// Write &str to the current screen. pub fn write_str(&self, string: &str) -> io::Result { - self.screen_manager.write_str(string) + self.stdout.write_str(string) } /// Write buffer to the screen pub fn write_buf(&self, buf: &[u8]) -> io::Result { - self.screen_manager.write(buf) + self.stdout.write(buf) } pub fn as_any(&self) -> &Any { - self.screen_manager.as_any() + self.stdout.as_any() } pub fn as_any_mut(&mut self) -> &mut Any { - self.screen_manager.as_any_mut() + self.stdout.as_any_mut() } } -impl Default for Stdout +impl Default for TerminalOutput { /// Get the default handle to the current screen. fn default() -> Self { #[cfg(target_os = "windows")] - let screen_manager = functions::get_module::>( + let stdout = functions::get_module::>( Box::from(WinApiStdout::new()), Box::from(AnsiStdout::new()), ).unwrap(); #[cfg(not(target_os = "windows"))] - let screen_manager = Box::from(AnsiStdout::new()) as Box; + let stdout = Box::from(AnsiStdout::new()) as Box; - Stdout { screen_manager , is_in_raw_mode: false} + TerminalOutput { stdout , is_in_raw_mode: false} } } diff --git a/src/modules/write/winapi_stdout.rs b/src/modules/output/winapi_output.rs similarity index 77% rename from src/modules/write/winapi_stdout.rs rename to src/modules/output/winapi_output.rs index b58117e..a059c1e 100644 --- a/src/modules/write/winapi_stdout.rs +++ b/src/modules/output/winapi_output.rs @@ -3,17 +3,18 @@ use kernel::windows_kernel::{handle, kernel, writing}; use winapi::um::wincon::ENABLE_PROCESSED_OUTPUT; use winapi::um::winnt::HANDLE; +use std::sync::Mutex; use std::ptr::NonNull; use std::any::Any; -use std::io::{self, Write}; -use std::sync::{Mutex,Arc, }; +use std::io; + /// This struct is a wrapper for WINAPI `HANDLE` -pub struct WinApiStdout { +pub struct WinApiOutput { pub handle: Mutex, } -impl IStdout for WinApiStdout { +impl IStdout for WinApiOutput { fn write_str(&self, string: &str) -> io::Result { self.write(string.as_bytes()) @@ -36,9 +37,9 @@ impl IStdout for WinApiStdout { } } -impl WinApiStdout { +impl WinApiOutput { pub fn new() -> Self { - WinApiStdout { handle: Mutex::new(handle::get_output_handle().unwrap()) } + WinApiOutput { handle: Mutex::new(handle::get_output_handle().unwrap()) } } pub fn set(&mut self, handle: HANDLE) @@ -53,6 +54,6 @@ impl WinApiStdout { } } -unsafe impl Send for WinApiStdout {} +unsafe impl Send for WinApiOutput {} -unsafe impl Sync for WinApiStdout {} +unsafe impl Sync for WinApiOutput {}