<commit_before>// During tests, we disable the renderer and that causes a bunch of warnings
// See Cargo.toml for an explanation of this attribute
#![cfg_attr(any(feature = "test", test), allow(dead_code, unused_variables, unused_imports))]

use std::env;
use std::thread;
use std::process::{self, Stdio};
use std::time::Instant;
use std::cell::RefCell;
use std::sync::mpsc;

use piston_window::math;

use client;
use canvas;
use animation::{Animation, MoveAnimation, RotateAnimation, AnimationStatus};
use state::{TurtleState, DrawingState, Path};
use query::{Query, Request, StateUpdate, DrawingCommand, Response};
use radians::{self, Radians};
use {Point, Distance, Event};

use self::DrawingCommand::*;

#[cfg(any(feature = "test", test))]
fn renderer_client(_: mpsc::Sender<Response>) -> (process::Child, thread::JoinHandle<()>) {
    let command = if cfg!(windows) {
        "dir"
    } else {
        "ls"
    };
    let mut test_proc = process::Command::new(command)
        .stdin(Stdio::piped())
        .stdout(Stdio::piped())
        .stderr(Stdio::inherit())
        .spawn()
        .expect("test process failed to start");
    test_proc.kill().expect("test process could not be killed!");
    let handle = thread::spawn(move || {});
    (test_proc, handle)
}

#[cfg(not(any(feature = "test", test)))]
fn renderer_client(response_tx: mpsc::Sender<Response>) -> (process::Child, thread::JoinHandle<()>) {
    let current_exe = env::current_exe()
        .expect("Could not read path of the currently running executable")
        .into_os_string();
    let mut renderer_process = process::Command::new(current_exe)
        .env("RUN_TURTLE_CANVAS", "true")
        .stdin(Stdio::piped())
        .stdout(Stdio::piped())
        .stderr(Stdio::inherit())
        .spawn()
        .expect("renderer process failed to start");

    let renderer_stdout = renderer_process.stdout.take()
        .expect("renderer process was not opened with stdout");
    let handle = thread::spawn(move || {
        client::run(renderer_stdout, response_tx);
    });

    (renderer_process, handle)
}

pub struct TurtleWindow {
    renderer: RefCell<process::Child>,
    thread_handle: RefCell<Option<thread::JoinHandle<()>>>,
    /// Channel for receiving responses from the rendering process
    response_channel: mpsc::Receiver<Response>,
}

impl TurtleWindow {
    pub fn new() -> TurtleWindow {
        // This needs to be called as close to the start of the program as possible
        // Since Turtle::new() is called at the beginning of many turtle programs, we do so here
        // to make sure this call occurs when it should.
        canvas::start();

        let (response_tx, response_rx) = mpsc::channel();
        let (renderer_process, handle) = renderer_client(response_tx);

        Self {
            renderer: RefCell::new(renderer_process),
            thread_handle: RefCell::new(Some(handle)),
            response_channel: response_rx,
        }
    }

    pub fn fetch_turtle(&self) -> TurtleState {
        self.send_query(Query::Request(Request::TurtleState));
        match self.wait_for_response() {
            Response::TurtleState(state) => state,
            _ => panic!("bug: the renderer process did not sent back TurtleState"),
        }
    }

    pub fn update_turtle(&mut self, turtle: TurtleState) {
        self.send_query(Query::Update(StateUpdate::TurtleState(turtle)));
    }

    pub fn fetch_drawing(&self) -> DrawingState {
        self.send_query(Query::Request(Request::DrawingState));
        match self.wait_for_response() {
            Response::DrawingState(state) => state,
            _ => panic!("bug: the renderer process did not sent back DrawingState"),
        }
    }

    pub fn update_drawing(&mut self, drawing: DrawingState) {
        self.send_query(Query::Update(StateUpdate::DrawingState(drawing)));
    }

    fn set_temporary_path(&mut self, path: Option<Path>) {
        self.send_query(Query::Update(StateUpdate::TemporaryPath(path)));
    }

    /// See [`Turtle::poll_event()`](struct.Turtle.html#method.poll_event).
    pub fn poll_event(&mut self) -> Option<Event> {
        self.send_query(Query::Request(Request::Event));
        match self.wait_for_response() {
            Response::Event(event) => event,
            _ => panic!("bug: the renderer process did not sent back an Event"),
        }
    }

    /// Begin filling the shape drawn by the turtle's movements.
    pub fn begin_fill(&mut self) {
        let fill_color = self.fetch_turtle().fill_color;
        self.send_drawing_command(BeginFill(fill_color));
    }

    /// Stop filling the current shape
    pub fn end_fill(&mut self) {
        self.send_drawing_command(EndFill);
    }

    /// Clear the turtle's drawings
    pub fn clear(&mut self) {
        self.send_drawing_command(Clear);
    }

    /// Move the turtle to the given position without changing its heading.
    pub fn go_to(&mut self, end: Point) {
        let (start, speed, pen) = {
            let turtle = self.fetch_turtle();
            (turtle.position, turtle.speed, turtle.pen.clone())
        };

        let distance = math::square_len(math::sub(start, end)).sqrt();
        let speed = speed.to_absolute(); // px per second
        // We take the absolute value because the time is always positive, even if distance is negative
        let total_millis = (distance / speed * 1000.).abs();

        let animation = MoveAnimation {
            path: Path {start, end, pen},
            timer: Instant::now(),
            total_millis,
        };

        self.play_animation(animation);
    }

    /// Move the turtle forward by the given distance. To move backwards, use a negative distance.
    ///
    /// The turtle's motion will be animated based on the speed
    pub fn forward(&mut self, distance: Distance) {
        if distance == 0. {
            return;
        }

        let (start, speed, heading, pen) = {
            let turtle = self.fetch_turtle();
            (turtle.position, turtle.speed, turtle.heading, turtle.pen.clone())
        };
        let x = distance * heading.cos();
        let y = distance * heading.sin();
        let end = math::add(start, [x, y]);

        let speed = speed.to_absolute(); // px per second
        // We take the absolute value because the time is always positive, even if distance is negative
        let total_millis = (distance / speed * 1000.).abs();

        let animation = MoveAnimation {
            path: Path {start, end, pen},
            timer: Instant::now(),
            total_millis,
        };

        self.play_animation(animation);
    }

    /// Rotate the turtle in place by the given angle in the given direction of rotation
    pub fn rotate(&mut self, angle: Radians, clockwise: bool) {
        if angle == radians::ZERO {
            return;
        }

        let TurtleState {heading, speed, ..} = self.fetch_turtle();
        let speed = speed.to_rotation(); // radians per second
        let total_millis = angle / speed * 1000.;
        // We take the absolute value because the time is always positive, even if angle is negative
        let total_millis = total_millis.to_radians().abs();

        let animation = RotateAnimation {
            start: heading,
            delta_angle: angle,
            clockwise,
            timer: Instant::now(),
            total_millis,
        };

        self.play_animation(animation);
    }

    fn play_animation<A: Animation>(&mut self, animation: A) {
        loop {
            // We want to keep the lock for as little time as possible
            let status = {
                let mut turtle = self.fetch_turtle();
                let status = animation.advance(&mut turtle);
                self.update_turtle(turtle);
                status
            };
            match status {
                AnimationStatus::Running(path) => self.set_temporary_path(path),
                AnimationStatus::Complete(path) => {
                    if let Some(path) = path {
                        self.set_temporary_path(None);
                        self.send_drawing_command(StorePath(path));
                    }

                    break;
                },
            }
        }
    }

    fn send_drawing_command(&self, command: DrawingCommand) {
        self.send_query(Query::Drawing(command));
    }

    // During tests, we disable the renderer. That means that if we let this code run, it will
    // quit the application during the tests and make it look like everything passes.
    // We disable this code so that none of that happens.
    #[cfg(any(feature = "test", test))]
    fn send_query(&self, _: Query) {}

    #[inline]
    #[cfg(not(any(feature = "test", test)))]
    fn send_query(&self, query: Query) {
        let result = if let Some(ref mut stdin) = self.renderer.borrow_mut().stdin {
            client::send_query(stdin, &query)
        }
        else {
            unreachable!("bug: renderer process was not opened with stdin");
        };

        result.unwrap_or_else(|_| {
            // Something went wrong while sending the query, check if the renderer process
            // panicked (exited with an error)
            match self.renderer.borrow_mut().try_wait() {
                Ok(Some(status)) => {
                    if status.success() {
                        // The window/renderer process was closed normally
                        process::exit(0);
                    }
                    else {
                        // Something went wrong, likely the other thread panicked
                        process::exit(1);
                    }
                },
                Ok(None) => panic!("bug: failed to send query even though renderer process was still running"),
                Err(_) => panic!("bug: unable to check the exit status of the renderer process"),
            }
        });
    }

    fn wait_for_response(&self) -> Response {
        match self.response_channel.recv() {
            Ok(response) => response,
            // The client thread has exited, that means that the renderer process has exited
            // and the window has closed
            Err(_) => self.exit_process(), // Quit
        }
    }

    /// Exits the current process with the correct error code
    ///
    /// Panics if the thread handle has already been consumed
    #[inline]
    fn exit_process(&self) -> ! {
        if let Some(handle) = self.thread_handle.borrow_mut().take() {
            // First check if the other thread panicked before it quit
            match handle.join() {
                Ok(_) => match self.renderer.borrow_mut().try_wait() {
                    Ok(Some(status)) => {
                        if status.success() {
                            // The window/renderer process was closed normally
                            process::exit(0);
                        }
                        else {
                            // Something went wrong, likely the other thread panicked
                            process::exit(1);
                        }
                    },
                    Ok(None) => match self.renderer.borrow_mut().wait() {
                        Ok(status) => {
                            if status.success() {
                                process::exit(0);
                            }
                            else {
                                process::exit(1);
                            }
                        },
                        Err(_) => unreachable!("bug: renderer process never ran even though we exited"),
                    },
                    Err(_) => panic!("bug: unable to check the exit status of the renderer process after client thread quit"),
                },
                // If this returns an error, the other thread panicked
                Err(_) => process::exit(1),
            }
        }
        else {
            unreachable!("bug: the thread handle was used but the process did not end");
        }
    }
}

#[cfg(not(any(feature = "test", test)))]
impl Drop for TurtleWindow {
    fn drop(&mut self) {
        // If the current thread is panicking, we want to abort right away
        // because otherwise there is code in the rendering thread that will call
        // process::exit(0) and then the exit code will be 0 instead of 1
        if thread::panicking() {
            process::exit(1);
        }

        // If this is just a normal ending of the main thread, we want to leave the renderer
        // running so that the user can see their drawing as long as they keep the window open
        //TODO: Maybe we should wait on the renderer_process instead of (or in addition to?) this thread
        if let Some(handle) = self.thread_handle.borrow_mut().take() {
            handle.join().unwrap_or_else(|_| {
                // If this returns an error, the other thread panicked
                process::exit(1);
            });
        }
    }
}
<commit_msg>Fancier methods using closures to remove a lot of the boilerplate of fetching and updating<commit_after>// During tests, we disable the renderer and that causes a bunch of warnings
// See Cargo.toml for an explanation of this attribute
#![cfg_attr(any(feature = "test", test), allow(dead_code, unused_variables, unused_imports))]

use std::env;
use std::thread;
use std::process::{self, Stdio};
use std::time::Instant;
use std::cell::RefCell;
use std::sync::mpsc;

use piston_window::math;

use client;
use canvas;
use animation::{Animation, MoveAnimation, RotateAnimation, AnimationStatus};
use state::{TurtleState, DrawingState, Path};
use query::{Query, Request, StateUpdate, DrawingCommand, Response};
use radians::{self, Radians};
use {Point, Distance, Event};

use self::DrawingCommand::*;

#[cfg(any(feature = "test", test))]
fn renderer_client(_: mpsc::Sender<Response>) -> (process::Child, thread::JoinHandle<()>) {
    let command = if cfg!(windows) {
        "dir"
    } else {
        "ls"
    };
    let mut test_proc = process::Command::new(command)
        .stdin(Stdio::piped())
        .stdout(Stdio::piped())
        .stderr(Stdio::inherit())
        .spawn()
        .expect("test process failed to start");
    test_proc.kill().expect("test process could not be killed!");
    let handle = thread::spawn(move || {});
    (test_proc, handle)
}

#[cfg(not(any(feature = "test", test)))]
fn renderer_client(response_tx: mpsc::Sender<Response>) -> (process::Child, thread::JoinHandle<()>) {
    let current_exe = env::current_exe()
        .expect("Could not read path of the currently running executable")
        .into_os_string();
    let mut renderer_process = process::Command::new(current_exe)
        .env("RUN_TURTLE_CANVAS", "true")
        .stdin(Stdio::piped())
        .stdout(Stdio::piped())
        .stderr(Stdio::inherit())
        .spawn()
        .expect("renderer process failed to start");

    let renderer_stdout = renderer_process.stdout.take()
        .expect("renderer process was not opened with stdout");
    let handle = thread::spawn(move || {
        client::run(renderer_stdout, response_tx);
    });

    (renderer_process, handle)
}

pub struct TurtleWindow {
    renderer: RefCell<process::Child>,
    thread_handle: RefCell<Option<thread::JoinHandle<()>>>,
    /// Channel for receiving responses from the rendering process
    response_channel: mpsc::Receiver<Response>,
}

impl TurtleWindow {
    pub fn new() -> TurtleWindow {
        // This needs to be called as close to the start of the program as possible
        // Since Turtle::new() is called at the beginning of many turtle programs, we do so here
        // to make sure this call occurs when it should.
        canvas::start();

        let (response_tx, response_rx) = mpsc::channel();
        let (renderer_process, handle) = renderer_client(response_tx);

        Self {
            renderer: RefCell::new(renderer_process),
            thread_handle: RefCell::new(Some(handle)),
            response_channel: response_rx,
        }
    }

    pub fn fetch_turtle(&self) -> TurtleState {
        self.send_query(Query::Request(Request::TurtleState));
        match self.wait_for_response() {
            Response::TurtleState(state) => state,
            _ => panic!("bug: the renderer process did not sent back TurtleState"),
        }
    }

    /// Fetch and update the turtle with no way of holding on to the reference or forgetting to
    /// update it after
    pub fn with_turtle_mut<F, T>(&mut self, update: F) -> T
        where F: FnOnce(&mut TurtleState) -> T {
        let mut turtle = self.fetch_turtle();
        let result = update(&mut turtle);
        self.send_query(Query::Update(StateUpdate::TurtleState(turtle)));
        result
    }

    pub fn fetch_drawing(&self) -> DrawingState {
        self.send_query(Query::Request(Request::DrawingState));
        match self.wait_for_response() {
            Response::DrawingState(state) => state,
            _ => panic!("bug: the renderer process did not sent back DrawingState"),
        }
    }

    /// Fetch and update the drawing with no way of holding on to the reference or forgetting to
    /// update it after
    pub fn with_drawing_mut<F, T>(&mut self, update: F) -> T
        where F: FnOnce(&mut DrawingState) -> T {
        let mut drawing = self.fetch_drawing();
        let result = update(&mut drawing);
        self.send_query(Query::Update(StateUpdate::DrawingState(drawing)));
        result
    }

    fn set_temporary_path(&mut self, path: Option<Path>) {
        self.send_query(Query::Update(StateUpdate::TemporaryPath(path)));
    }

    /// See [`Turtle::poll_event()`](struct.Turtle.html#method.poll_event).
    pub fn poll_event(&mut self) -> Option<Event> {
        self.send_query(Query::Request(Request::Event));
        match self.wait_for_response() {
            Response::Event(event) => event,
            _ => panic!("bug: the renderer process did not sent back an Event"),
        }
    }

    /// Begin filling the shape drawn by the turtle's movements.
    pub fn begin_fill(&mut self) {
        let fill_color = self.fetch_turtle().fill_color;
        self.send_drawing_command(BeginFill(fill_color));
    }

    /// Stop filling the current shape
    pub fn end_fill(&mut self) {
        self.send_drawing_command(EndFill);
    }

    /// Clear the turtle's drawings
    pub fn clear(&mut self) {
        self.send_drawing_command(Clear);
    }

    /// Move the turtle to the given position without changing its heading.
    pub fn go_to(&mut self, end: Point) {
        let (start, speed, pen) = {
            let turtle = self.fetch_turtle();
            (turtle.position, turtle.speed, turtle.pen.clone())
        };

        let distance = math::square_len(math::sub(start, end)).sqrt();
        let speed = speed.to_absolute(); // px per second
        // We take the absolute value because the time is always positive, even if distance is negative
        let total_millis = (distance / speed * 1000.).abs();

        let animation = MoveAnimation {
            path: Path {start, end, pen},
            timer: Instant::now(),
            total_millis,
        };

        self.play_animation(animation);
    }

    /// Move the turtle forward by the given distance. To move backwards, use a negative distance.
    ///
    /// The turtle's motion will be animated based on the speed
    pub fn forward(&mut self, distance: Distance) {
        if distance == 0. {
            return;
        }

        let (start, speed, heading, pen) = {
            let turtle = self.fetch_turtle();
            (turtle.position, turtle.speed, turtle.heading, turtle.pen.clone())
        };
        let x = distance * heading.cos();
        let y = distance * heading.sin();
        let end = math::add(start, [x, y]);

        let speed = speed.to_absolute(); // px per second
        // We take the absolute value because the time is always positive, even if distance is negative
        let total_millis = (distance / speed * 1000.).abs();

        let animation = MoveAnimation {
            path: Path {start, end, pen},
            timer: Instant::now(),
            total_millis,
        };

        self.play_animation(animation);
    }

    /// Rotate the turtle in place by the given angle in the given direction of rotation
    pub fn rotate(&mut self, angle: Radians, clockwise: bool) {
        if angle == radians::ZERO {
            return;
        }

        let TurtleState {heading, speed, ..} = self.fetch_turtle();
        let speed = speed.to_rotation(); // radians per second
        let total_millis = angle / speed * 1000.;
        // We take the absolute value because the time is always positive, even if angle is negative
        let total_millis = total_millis.to_radians().abs();

        let animation = RotateAnimation {
            start: heading,
            delta_angle: angle,
            clockwise,
            timer: Instant::now(),
            total_millis,
        };

        self.play_animation(animation);
    }

    fn play_animation<A: Animation>(&mut self, animation: A) {
        loop {
            // We want to keep the lock for as little time as possible
            let status = self.with_turtle_mut(|turtle| animation.advance(turtle));
            match status {
                AnimationStatus::Running(path) => self.set_temporary_path(path),
                AnimationStatus::Complete(path) => {
                    if let Some(path) = path {
                        self.set_temporary_path(None);
                        self.send_drawing_command(StorePath(path));
                    }

                    break;
                },
            }
        }
    }

    fn send_drawing_command(&self, command: DrawingCommand) {
        self.send_query(Query::Drawing(command));
    }

    // During tests, we disable the renderer. That means that if we let this code run, it will
    // quit the application during the tests and make it look like everything passes.
    // We disable this code so that none of that happens.
    #[cfg(any(feature = "test", test))]
    fn send_query(&self, _: Query) {}

    #[inline]
    #[cfg(not(any(feature = "test", test)))]
    fn send_query(&self, query: Query) {
        let result = if let Some(ref mut stdin) = self.renderer.borrow_mut().stdin {
            client::send_query(stdin, &query)
        }
        else {
            unreachable!("bug: renderer process was not opened with stdin");
        };

        result.unwrap_or_else(|_| {
            // Something went wrong while sending the query, check if the renderer process
            // panicked (exited with an error)
            match self.renderer.borrow_mut().try_wait() {
                Ok(Some(status)) => {
                    if status.success() {
                        // The window/renderer process was closed normally
                        process::exit(0);
                    }
                    else {
                        // Something went wrong, likely the other thread panicked
                        process::exit(1);
                    }
                },
                Ok(None) => panic!("bug: failed to send query even though renderer process was still running"),
                Err(_) => panic!("bug: unable to check the exit status of the renderer process"),
            }
        });
    }

    fn wait_for_response(&self) -> Response {
        match self.response_channel.recv() {
            Ok(response) => response,
            // The client thread has exited, that means that the renderer process has exited
            // and the window has closed
            Err(_) => self.exit_process(), // Quit
        }
    }

    /// Exits the current process with the correct error code
    ///
    /// Panics if the thread handle has already been consumed
    #[inline]
    fn exit_process(&self) -> ! {
        if let Some(handle) = self.thread_handle.borrow_mut().take() {
            // First check if the other thread panicked before it quit
            match handle.join() {
                Ok(_) => match self.renderer.borrow_mut().try_wait() {
                    Ok(Some(status)) => {
                        if status.success() {
                            // The window/renderer process was closed normally
                            process::exit(0);
                        }
                        else {
                            // Something went wrong, likely the other thread panicked
                            process::exit(1);
                        }
                    },
                    Ok(None) => match self.renderer.borrow_mut().wait() {
                        Ok(status) => {
                            if status.success() {
                                process::exit(0);
                            }
                            else {
                                process::exit(1);
                            }
                        },
                        Err(_) => unreachable!("bug: renderer process never ran even though we exited"),
                    },
                    Err(_) => panic!("bug: unable to check the exit status of the renderer process after client thread quit"),
                },
                // If this returns an error, the other thread panicked
                Err(_) => process::exit(1),
            }
        }
        else {
            unreachable!("bug: the thread handle was used but the process did not end");
        }
    }
}

#[cfg(not(any(feature = "test", test)))]
impl Drop for TurtleWindow {
    fn drop(&mut self) {
        // If the current thread is panicking, we want to abort right away
        // because otherwise there is code in the rendering thread that will call
        // process::exit(0) and then the exit code will be 0 instead of 1
        if thread::panicking() {
            process::exit(1);
        }

        // If this is just a normal ending of the main thread, we want to leave the renderer
        // running so that the user can see their drawing as long as they keep the window open
        //TODO: Maybe we should wait on the renderer_process instead of (or in addition to?) this thread
        if let Some(handle) = self.thread_handle.borrow_mut().take() {
            handle.join().unwrap_or_else(|_| {
                // If this returns an error, the other thread panicked
                process::exit(1);
            });
        }
    }
}
<|endoftext|>


<commit_before>//! TODO Documentation

use std::{panic, ptr};
use std::marker::PhantomData;
use std::rc::{Rc, Weak};
use std::sync::atomic::{AtomicBool, Ordering};
use std::time::Duration;

use libc;
use wlroots_sys::{timespec, wlr_surface, wlr_surface_get_main_surface, wlr_surface_get_matrix,
                  wlr_surface_has_buffer, wlr_surface_make_subsurface, wlr_surface_send_enter,
                  wlr_surface_send_frame_done, wlr_surface_send_leave, wlr_surface_state};

use Output;
use errors::{UpgradeHandleErr, UpgradeHandleResult};
use render::Texture;
use utils::c_to_rust_string;

/// The state stored in the wlr_surface user data.
struct InternalSurfaceState {
    /// Used to reconstruct a SurfaceHandle from just an *mut wlr_surface.
    handle: Weak<AtomicBool>
}

// TODO Move
pub struct Subsurface;
pub struct SubsurfaceHandle;

/// Surface state as reported by wlroots.
pub struct SurfaceState<'surface> {
    state: *mut wlr_surface_state,
    phantom: PhantomData<&'surface Surface>
}

/// A Wayland object that represents the data that we display on the screen.
///
/// Most surfaces come from Wayland clients, though they can also be created
/// by the compositor directly.
#[derive(Debug)]
pub struct Surface {
    /// The structe that ensures weak handles to this structure are still alive.
    ///
    /// They contain weak handles, and will safely not use dead memory when this
    /// is freed by wlroots.
    ///
    /// If this is `None`, then this is from an upgraded `SurfaceHandle`, and
    /// the operations are **unchecked**.
    /// This is means safe operations might fail, but only if you use the unsafe
    /// marked function `upgrade` on a `SurfaceHandle`.
    liveliness: Option<Rc<AtomicBool>>,
    /// The pointer to the wlroots object that wraps a wl_surface.
    surface: *mut wlr_surface
}

/// See `Surface` for more information on how to use this structure.
#[derive(Clone, Debug)]
pub struct SurfaceHandle {
    /// The Rc that ensures that this handle is still alive.
    ///
    /// When wlroots deallocates the pointer associated with this handle,
    /// this can no longer be used.
    handle: Weak<AtomicBool>,
    /// The pointer to the wlroots object that wraps a wl_surface.
    surface: *mut wlr_surface
}

impl Surface {
    pub(crate) unsafe fn as_ptr(&self) -> *mut wlr_surface {
        self.surface
    }

    pub(crate) unsafe fn from_ptr(surface: *mut wlr_surface) -> Self {
        if !(*surface).data.is_null() {
            panic!("Tried to construct a Surface from an already initialized wlr_surface");
        }
        let liveliness = Rc::new(AtomicBool::new(false));
        let handle = Rc::downgrade(&liveliness);
        (*surface).data = Box::into_raw(Box::new(InternalSurfaceState { handle })) as _;
        let liveliness = Some(liveliness);
        Surface { liveliness,
                  surface }
    }

    /// Get the surface state.
    pub fn current_state<'surface>(&'surface mut self) -> SurfaceState<'surface> {
        unsafe {
            SurfaceState { state: (*self.surface).current,
                           phantom: PhantomData }
        }
    }

    /// Get the pending surface state.
    pub fn pending_state<'surface>(&'surface mut self) -> SurfaceState<'surface> {
        unsafe {
            SurfaceState { state: (*self.surface).pending,
                           phantom: PhantomData }
        }
    }

    /// Get the subsurface.
    pub fn subsurface(&self) -> Subsurface {
        Subsurface
    }

    /// Get the texture of this surface.
    pub fn texture(&self) -> Texture {
        unsafe { Texture::from_ptr((*self.surface).texture) }
    }

    /// Get the lifetime bound role (if one exists) for this surface.
    pub fn role(&self) -> Option<String> {
        unsafe { c_to_rust_string((*self.surface).role) }
    }

    /// Gets a matrix you can pass into wlr_render_with_matrix to display this
    /// surface.
    ///
    /// `matrix` is the output matrix, `projection` is the wlr_output
    /// projection matrix, and `transform` is any additional transformations you want
    /// to perform on the surface (or None/the identity matrix if you don't).
    ///
    /// `transform` is used before the surface is scaled, so its geometry extends
    /// from 0 to 1 in both dimensions.
    pub fn get_matrix<'a, T>(&mut self,
                             matrix: &mut [f32; 16],
                             projection: &[f32; 16],
                             transform: T)
        where T: Into<Option<&'a [f32; 16]>>
    {
        let transform = transform.into()
                                 .map(|transform| transform as *const _)
                                 .unwrap_or_else(|| ptr::null());
        unsafe { wlr_surface_get_matrix(self.surface, matrix, projection, transform) }
    }

    /// Whether or not this surface currently has an attached buffer.
    ///
    /// A surface has an attached buffer when it commits with a non-null buffer in its pending
    /// state.
    ///
    /// A surface will not have a buffer if it has never committed one, has
    /// committed a null buffer, or something went wrong with uploading the buffer.
    pub fn has_buffer(&self) -> bool {
        unsafe { wlr_surface_has_buffer(self.surface) }
    }

    /// Find a subsurface within this surface at the surface-local coordinates.
    ///
    /// Returns the surface and coordinates in the topmost surface coordinate system
    /// or None if no subsurface is found at that location.
    pub fn subsurface_at(&mut self,
                         _sx: f32,
                         _sy: f32,
                         _sub_x: &mut f32,
                         _sub_y: &mut f32)
                         -> Option<SubsurfaceHandle> {
        unimplemented!()
    }

    /// Create the subsurface implementation for this surface.
    pub fn make_subsurface(&mut self, parent: &mut Surface, id: u32) {
        unsafe { wlr_surface_make_subsurface(self.surface, parent.as_ptr(), id) }
    }

    /// Get the top of the subsurface tree for this surface.
    pub fn get_main_surface(&self) -> Option<SurfaceHandle> {
        unsafe {
            let surface = wlr_surface_get_main_surface(self.surface);
            if surface.is_null() {
                None
            } else {
                Some(SurfaceHandle::from_ptr(surface))
            }
        }
    }

    pub fn send_enter(&mut self, output: &mut Output) {
        unsafe { wlr_surface_send_enter(self.surface, output.as_ptr()) }
    }

    pub fn send_leave(&mut self, output: &mut Output) {
        unsafe { wlr_surface_send_leave(self.surface, output.as_ptr()) }
    }

    /// Send the frame done event.
    pub fn send_frame_done(&mut self, duration: Duration) {
        unsafe {
            // FIXME
            // This is converting from a u64 -> i64
            // Something bad could happen!
            let when = timespec { tv_sec: duration.as_secs() as i64,
                                  tv_nsec: duration.subsec_nanos() as i64 };
            wlr_surface_send_frame_done(self.surface, &when);
        }
    }

    /// Get the matrix used to convert the internal byte buffer to use in the
    /// surface.
    pub fn buffer_to_surface_matrix(&self) -> [f32; 16] {
        unsafe { (*self.surface).buffer_to_surface_matrix }
    }

    /// Get the matrix used to convert the surface back to the internal byte
    /// buffer.
    pub fn surface_to_buffer_matrix(&self) -> [f32; 16] {
        unsafe { (*self.surface).surface_to_buffer_matrix }
    }

    /// Manually set the lock used to determine if a double-borrow is
    /// occuring on this structure.
    ///
    /// # Panics
    /// Panics when trying to set the lock on an upgraded handle.
    pub(crate) unsafe fn set_lock(&self, val: bool) {
        self.liveliness.as_ref()
            .expect("Tried to set lock on borrowed Surface")
            .store(val, Ordering::Release);
    }

    unsafe fn from_handle(handle: &SurfaceHandle) -> Self {
        Surface { liveliness: None,
                  surface: handle.surface }
    }
}

impl SurfaceHandle {
    /// Creates an SurfaceHandle from the raw pointer, using the saved
    /// user data to recreate the memory model.
    pub(crate) unsafe fn from_ptr(surface: *mut wlr_surface) -> Self {
        let data = (*surface).data as *mut InternalSurfaceState;
        let handle = (*data).handle.clone();
        SurfaceHandle { handle, surface }
    }

    /// Upgrades the surface handle to a reference to the backing `Surface`.
    ///
    /// # Unsafety
    /// This function is unsafe, because it creates an unbound `Surface`
    /// which may live forever..
    /// But no surface lives forever and might be disconnected at any time.
    pub(crate) unsafe fn upgrade(&self) -> UpgradeHandleResult<Surface> {
        self.handle.upgrade()
            .ok_or(UpgradeHandleErr::AlreadyDropped)
            // NOTE
            // We drop the Rc here because having two would allow a dangling
            // pointer to exist!
            .and_then(|check| {
                if check.load(Ordering::Acquire) {
                    return Err(UpgradeHandleErr::AlreadyBorrowed)
                }
                check.store(true, Ordering::Release);
                Ok(Surface::from_handle(self))
            })
    }

    /// Run a function on the referenced Surface, if it still exists
    ///
    /// Returns the result of the function, if successful
    ///
    /// # Safety
    /// By enforcing a rather harsh limit on the lifetime of the surface
    /// to a short lived scope of an anonymous function,
    /// this function ensures the Surface does not live longer
    /// than it exists.
    ///
    /// # Panics
    /// This function will panic if multiple mutable borrows are detected.
    /// This will happen if you call `upgrade` directly within this callback,
    /// or if you run this function within the another run to the same `Surface`.
    ///
    /// So don't nest `run` calls and everything will be ok :).
    pub fn run<F, R>(&mut self, runner: F) -> UpgradeHandleResult<R>
        where F: FnOnce(&mut Surface) -> R
    {
        let mut surface = unsafe { self.upgrade()? };
        let res = panic::catch_unwind(panic::AssertUnwindSafe(|| runner(&mut surface)));
        self.handle.upgrade().map(|check| {
                                      // Sanity check that it hasn't been tampered with.
                                      if !check.load(Ordering::Acquire) {
                                          wlr_log!(L_ERROR,
                                                   "After running surface callback, mutable lock \
                                                    was false for: {:?}",
                                                   surface);
                                          panic!("Lock in incorrect state!");
                                      }
                                      check.store(false, Ordering::Release);
                                  });
        match res {
            Ok(res) => Ok(res),
            Err(err) => panic::resume_unwind(err)
        }
    }
}

impl<'surface> SurfaceState<'surface> {
    pub fn width(&self) -> libc::c_int {
        unsafe { (*self.state).width }
    }

    pub fn height(&self) -> libc::c_int {
        unsafe { (*self.state).height }
    }
}
<commit_msg>Suppress warnings and panic in subsurface_at<commit_after>//! TODO Documentation

use std::{panic, ptr};
use std::marker::PhantomData;
use std::rc::{Rc, Weak};
use std::sync::atomic::{AtomicBool, Ordering};
use std::time::Duration;

use libc;
use wlroots_sys::{timespec, wlr_surface, wlr_surface_get_main_surface, wlr_surface_get_matrix,
                  wlr_surface_has_buffer, wlr_surface_make_subsurface, wlr_surface_send_enter,
                  wlr_surface_send_frame_done, wlr_surface_send_leave, wlr_surface_state};

use Output;
use errors::{UpgradeHandleErr, UpgradeHandleResult};
use render::Texture;
use utils::c_to_rust_string;

/// The state stored in the wlr_surface user data.
struct InternalSurfaceState {
    /// Used to reconstruct a SurfaceHandle from just an *mut wlr_surface.
    handle: Weak<AtomicBool>
}

// TODO Move
pub struct Subsurface;
pub struct SubsurfaceHandle;

/// Surface state as reported by wlroots.
pub struct SurfaceState<'surface> {
    state: *mut wlr_surface_state,
    phantom: PhantomData<&'surface Surface>
}

/// A Wayland object that represents the data that we display on the screen.
///
/// Most surfaces come from Wayland clients, though they can also be created
/// by the compositor directly.
#[derive(Debug)]
pub struct Surface {
    /// The structe that ensures weak handles to this structure are still alive.
    ///
    /// They contain weak handles, and will safely not use dead memory when this
    /// is freed by wlroots.
    ///
    /// If this is `None`, then this is from an upgraded `SurfaceHandle`, and
    /// the operations are **unchecked**.
    /// This is means safe operations might fail, but only if you use the unsafe
    /// marked function `upgrade` on a `SurfaceHandle`.
    liveliness: Option<Rc<AtomicBool>>,
    /// The pointer to the wlroots object that wraps a wl_surface.
    surface: *mut wlr_surface
}

/// See `Surface` for more information on how to use this structure.
#[derive(Clone, Debug)]
pub struct SurfaceHandle {
    /// The Rc that ensures that this handle is still alive.
    ///
    /// When wlroots deallocates the pointer associated with this handle,
    /// this can no longer be used.
    handle: Weak<AtomicBool>,
    /// The pointer to the wlroots object that wraps a wl_surface.
    surface: *mut wlr_surface
}

impl Surface {
    pub(crate) unsafe fn as_ptr(&self) -> *mut wlr_surface {
        self.surface
    }

    pub(crate) unsafe fn from_ptr(surface: *mut wlr_surface) -> Self {
        if !(*surface).data.is_null() {
            panic!("Tried to construct a Surface from an already initialized wlr_surface");
        }
        let liveliness = Rc::new(AtomicBool::new(false));
        let handle = Rc::downgrade(&liveliness);
        (*surface).data = Box::into_raw(Box::new(InternalSurfaceState { handle })) as _;
        let liveliness = Some(liveliness);
        Surface { liveliness,
                  surface }
    }

    /// Get the surface state.
    pub fn current_state<'surface>(&'surface mut self) -> SurfaceState<'surface> {
        unsafe {
            SurfaceState { state: (*self.surface).current,
                           phantom: PhantomData }
        }
    }

    /// Get the pending surface state.
    pub fn pending_state<'surface>(&'surface mut self) -> SurfaceState<'surface> {
        unsafe {
            SurfaceState { state: (*self.surface).pending,
                           phantom: PhantomData }
        }
    }

    /// Get the subsurface.
    pub fn subsurface(&self) -> Subsurface {
        Subsurface
    }

    /// Get the texture of this surface.
    pub fn texture(&self) -> Texture {
        unsafe { Texture::from_ptr((*self.surface).texture) }
    }

    /// Get the lifetime bound role (if one exists) for this surface.
    pub fn role(&self) -> Option<String> {
        unsafe { c_to_rust_string((*self.surface).role) }
    }

    /// Gets a matrix you can pass into wlr_render_with_matrix to display this
    /// surface.
    ///
    /// `matrix` is the output matrix, `projection` is the wlr_output
    /// projection matrix, and `transform` is any additional transformations you want
    /// to perform on the surface (or None/the identity matrix if you don't).
    ///
    /// `transform` is used before the surface is scaled, so its geometry extends
    /// from 0 to 1 in both dimensions.
    pub fn get_matrix<'a, T>(&mut self,
                             matrix: &mut [f32; 16],
                             projection: &[f32; 16],
                             transform: T)
        where T: Into<Option<&'a [f32; 16]>>
    {
        let transform = transform.into()
                                 .map(|transform| transform as *const _)
                                 .unwrap_or_else(|| ptr::null());
        unsafe { wlr_surface_get_matrix(self.surface, matrix, projection, transform) }
    }

    /// Whether or not this surface currently has an attached buffer.
    ///
    /// A surface has an attached buffer when it commits with a non-null buffer in its pending
    /// state.
    ///
    /// A surface will not have a buffer if it has never committed one, has
    /// committed a null buffer, or something went wrong with uploading the buffer.
    pub fn has_buffer(&self) -> bool {
        unsafe { wlr_surface_has_buffer(self.surface) }
    }

    /// Find a subsurface within this surface at the surface-local coordinates.
    ///
    /// Returns the surface and coordinates in the topmost surface coordinate system
    /// or None if no subsurface is found at that location.
    #[allow(unused_variables)]
    pub fn subsurface_at(&mut self,
                         _sx: f32,
                         _sy: f32,
                         _sub_x: &mut f32,
                         _sub_y: &mut f32)
                         -> Option<SubsurfaceHandle> {
        unimplemented!()
    }

    /// Create the subsurface implementation for this surface.
    pub fn make_subsurface(&mut self, parent: &mut Surface, id: u32) {
        unsafe { wlr_surface_make_subsurface(self.surface, parent.as_ptr(), id) }
    }

    /// Get the top of the subsurface tree for this surface.
    pub fn get_main_surface(&self) -> Option<SurfaceHandle> {
        unsafe {
            let surface = wlr_surface_get_main_surface(self.surface);
            if surface.is_null() {
                None
            } else {
                Some(SurfaceHandle::from_ptr(surface))
            }
        }
    }

    pub fn send_enter(&mut self, output: &mut Output) {
        unsafe { wlr_surface_send_enter(self.surface, output.as_ptr()) }
    }

    pub fn send_leave(&mut self, output: &mut Output) {
        unsafe { wlr_surface_send_leave(self.surface, output.as_ptr()) }
    }

    /// Send the frame done event.
    pub fn send_frame_done(&mut self, duration: Duration) {
        unsafe {
            // FIXME
            // This is converting from a u64 -> i64
            // Something bad could happen!
            let when = timespec { tv_sec: duration.as_secs() as i64,
                                  tv_nsec: duration.subsec_nanos() as i64 };
            wlr_surface_send_frame_done(self.surface, &when);
        }
    }

    /// Get the matrix used to convert the internal byte buffer to use in the
    /// surface.
    pub fn buffer_to_surface_matrix(&self) -> [f32; 16] {
        unsafe { (*self.surface).buffer_to_surface_matrix }
    }

    /// Get the matrix used to convert the surface back to the internal byte
    /// buffer.
    pub fn surface_to_buffer_matrix(&self) -> [f32; 16] {
        unsafe { (*self.surface).surface_to_buffer_matrix }
    }

    /// Manually set the lock used to determine if a double-borrow is
    /// occuring on this structure.
    ///
    /// # Panics
    /// Panics when trying to set the lock on an upgraded handle.
    pub(crate) unsafe fn set_lock(&self, val: bool) {
        self.liveliness.as_ref()
            .expect("Tried to set lock on borrowed Surface")
            .store(val, Ordering::Release);
    }

    unsafe fn from_handle(handle: &SurfaceHandle) -> Self {
        Surface { liveliness: None,
                  surface: handle.surface }
    }
}

impl SurfaceHandle {
    /// Creates an SurfaceHandle from the raw pointer, using the saved
    /// user data to recreate the memory model.
    pub(crate) unsafe fn from_ptr(surface: *mut wlr_surface) -> Self {
        let data = (*surface).data as *mut InternalSurfaceState;
        let handle = (*data).handle.clone();
        SurfaceHandle { handle, surface }
    }

    /// Upgrades the surface handle to a reference to the backing `Surface`.
    ///
    /// # Unsafety
    /// This function is unsafe, because it creates an unbound `Surface`
    /// which may live forever..
    /// But no surface lives forever and might be disconnected at any time.
    pub(crate) unsafe fn upgrade(&self) -> UpgradeHandleResult<Surface> {
        self.handle.upgrade()
            .ok_or(UpgradeHandleErr::AlreadyDropped)
            // NOTE
            // We drop the Rc here because having two would allow a dangling
            // pointer to exist!
            .and_then(|check| {
                if check.load(Ordering::Acquire) {
                    return Err(UpgradeHandleErr::AlreadyBorrowed)
                }
                check.store(true, Ordering::Release);
                Ok(Surface::from_handle(self))
            })
    }

    /// Run a function on the referenced Surface, if it still exists
    ///
    /// Returns the result of the function, if successful
    ///
    /// # Safety
    /// By enforcing a rather harsh limit on the lifetime of the surface
    /// to a short lived scope of an anonymous function,
    /// this function ensures the Surface does not live longer
    /// than it exists.
    ///
    /// # Panics
    /// This function will panic if multiple mutable borrows are detected.
    /// This will happen if you call `upgrade` directly within this callback,
    /// or if you run this function within the another run to the same `Surface`.
    ///
    /// So don't nest `run` calls and everything will be ok :).
    pub fn run<F, R>(&mut self, runner: F) -> UpgradeHandleResult<R>
        where F: FnOnce(&mut Surface) -> R
    {
        let mut surface = unsafe { self.upgrade()? };
        let res = panic::catch_unwind(panic::AssertUnwindSafe(|| runner(&mut surface)));
        self.handle.upgrade().map(|check| {
                                      // Sanity check that it hasn't been tampered with.
                                      if !check.load(Ordering::Acquire) {
                                          wlr_log!(L_ERROR,
                                                   "After running surface callback, mutable lock \
                                                    was false for: {:?}",
                                                   surface);
                                          panic!("Lock in incorrect state!");
                                      }
                                      check.store(false, Ordering::Release);
                                  });
        match res {
            Ok(res) => Ok(res),
            Err(err) => panic::resume_unwind(err)
        }
    }
}

impl<'surface> SurfaceState<'surface> {
    pub fn width(&self) -> libc::c_int {
        unsafe { (*self.state).width }
    }

    pub fn height(&self) -> libc::c_int {
        unsafe { (*self.state).height }
    }
}
<|endoftext|>


<commit_before>use crate::env::temp_dir;
use crate::fs::OpenOptions;
use crate::io;
use crate::io::Result;
use crate::io::SeekFrom;
use crate::io::{BufRead, Read, Seek, Write};
use crate::os::unix::io::AsRawFd;

#[test]
fn copy_specialization() -> Result<()> {
    use crate::io::{BufReader, BufWriter};

    let path = crate::env::temp_dir();
    let source_path = path.join("copy-spec.source");
    let sink_path = path.join("copy-spec.sink");

    let result: Result<()> = try {
        let mut source = crate::fs::OpenOptions::new()
            .read(true)
            .write(true)
            .create(true)
            .truncate(true)
            .open(&source_path)?;
        source.write_all(b"abcdefghiklmnopqr")?;
        source.seek(SeekFrom::Start(8))?;
        let mut source = BufReader::with_capacity(8, source.take(5));
        source.fill_buf()?;
        assert_eq!(source.buffer(), b"iklmn");
        source.get_mut().set_limit(6);
        source.get_mut().get_mut().seek(SeekFrom::Start(1))?; // "bcdefg"
        let mut source = source.take(10); // "iklmnbcdef"

        let mut sink = crate::fs::OpenOptions::new()
            .read(true)
            .write(true)
            .create(true)
            .truncate(true)
            .open(&sink_path)?;
        sink.write_all(b"000000")?;
        let mut sink = BufWriter::with_capacity(5, sink);
        sink.write_all(b"wxyz")?;
        assert_eq!(sink.buffer(), b"wxyz");

        let copied = crate::io::copy(&mut source, &mut sink)?;
        assert_eq!(copied, 10);
        assert_eq!(sink.buffer().len(), 0);

        let mut sink = sink.into_inner()?;
        sink.seek(SeekFrom::Start(0))?;
        let mut copied = Vec::new();
        sink.read_to_end(&mut copied)?;
        assert_eq!(&copied, b"000000wxyziklmnbcdef");
    };

    let rm1 = crate::fs::remove_file(source_path);
    let rm2 = crate::fs::remove_file(sink_path);

    result.and(rm1).and(rm2)
}

#[bench]
fn bench_file_to_file_copy(b: &mut test::Bencher) {
    const BYTES: usize = 128 * 1024;
    let src_path = temp_dir().join("file-copy-bench-src");
    let mut src = crate::fs::OpenOptions::new()
        .create(true)
        .truncate(true)
        .read(true)
        .write(true)
        .open(src_path)
        .unwrap();
    src.write(&vec![0u8; BYTES]).unwrap();

    let sink_path = temp_dir().join("file-copy-bench-sink");
    let mut sink = crate::fs::OpenOptions::new()
        .create(true)
        .truncate(true)
        .write(true)
        .open(sink_path)
        .unwrap();

    b.bytes = BYTES as u64;
    b.iter(|| {
        src.seek(SeekFrom::Start(0)).unwrap();
        sink.seek(SeekFrom::Start(0)).unwrap();
        assert_eq!(BYTES as u64, io::copy(&mut src, &mut sink).unwrap());
    });
}

#[bench]
fn bench_file_to_socket_copy(b: &mut test::Bencher) {
    const BYTES: usize = 128 * 1024;
    let src_path = temp_dir().join("pipe-copy-bench-src");
    let mut src = OpenOptions::new()
        .create(true)
        .truncate(true)
        .read(true)
        .write(true)
        .open(src_path)
        .unwrap();
    src.write(&vec![0u8; BYTES]).unwrap();

    let sink_drainer = crate::net::TcpListener::bind("localhost:0").unwrap();
    let mut sink = crate::net::TcpStream::connect(sink_drainer.local_addr().unwrap()).unwrap();
    let mut sink_drainer = sink_drainer.accept().unwrap().0;

    crate::thread::spawn(move || {
        let mut sink_buf = vec![0u8; 1024 * 1024];
        loop {
            sink_drainer.read(&mut sink_buf[..]).unwrap();
        }
    });

    b.bytes = BYTES as u64;
    b.iter(|| {
        src.seek(SeekFrom::Start(0)).unwrap();
        assert_eq!(BYTES as u64, io::copy(&mut src, &mut sink).unwrap());
    });
}

#[bench]
fn bench_file_to_uds_copy(b: &mut test::Bencher) {
    const BYTES: usize = 128 * 1024;
    let src_path = temp_dir().join("uds-copy-bench-src");
    let mut src = OpenOptions::new()
        .create(true)
        .truncate(true)
        .read(true)
        .write(true)
        .open(src_path)
        .unwrap();
    src.write(&vec![0u8; BYTES]).unwrap();

    let (mut sink, mut sink_drainer) = crate::os::unix::net::UnixStream::pair().unwrap();

    crate::thread::spawn(move || {
        let mut sink_buf = vec![0u8; 1024 * 1024];
        loop {
            sink_drainer.read(&mut sink_buf[..]).unwrap();
        }
    });

    b.bytes = BYTES as u64;
    b.iter(|| {
        src.seek(SeekFrom::Start(0)).unwrap();
        assert_eq!(BYTES as u64, io::copy(&mut src, &mut sink).unwrap());
    });
}

#[cfg(any(target_os = "linux", target_os = "android"))]
#[bench]
fn bench_socket_pipe_socket_copy(b: &mut test::Bencher) {
    use super::CopyResult;
    use crate::io::ErrorKind;
    use crate::process::{ChildStdin, ChildStdout};
    use crate::sys_common::FromInner;

    let (read_end, write_end) = crate::sys::pipe::anon_pipe().unwrap();

    let mut read_end = ChildStdout::from_inner(read_end);
    let write_end = ChildStdin::from_inner(write_end);

    let acceptor = crate::net::TcpListener::bind("localhost:0").unwrap();
    let mut remote_end = crate::net::TcpStream::connect(acceptor.local_addr().unwrap()).unwrap();

    let local_end = crate::sync::Arc::new(acceptor.accept().unwrap().0);

    // the data flow in this benchmark:
    //
    //                      socket(tx)  local_source
    // remote_end (write)  +-------->   (splice to)
    //                                  write_end
    //                                     +
    //                                     |
    //                                     | pipe
    //                                     v
    //                                  read_end
    // remote_end (read)   <---------+  (splice to) *
    //                      socket(rx)  local_end
    //
    // * benchmark loop using io::copy

    crate::thread::spawn(move || {
        let mut sink_buf = vec![0u8; 1024 * 1024];
        remote_end.set_nonblocking(true).unwrap();
        loop {
            match remote_end.write(&mut sink_buf[..]) {
                Err(err) if err.kind() == ErrorKind::WouldBlock => {}
                Ok(_) => {}
                err => {
                    err.expect("write failed");
                }
            };
            match remote_end.read(&mut sink_buf[..]) {
                Err(err) if err.kind() == ErrorKind::WouldBlock => {}
                Ok(_) => {}
                err => {
                    err.expect("read failed");
                }
            };
        }
    });

    // check that splice works, otherwise the benchmark would hang
    let probe = super::sendfile_splice(
        super::SpliceMode::Splice,
        local_end.as_raw_fd(),
        write_end.as_raw_fd(),
        1,
    );

    match probe {
        CopyResult::Ended(Ok(1)) => {
            // splice works
        }
        _ => {
            eprintln!("splice failed, skipping benchmark");
            return;
        }
    }

    let local_source = local_end.clone();
    crate::thread::spawn(move || {
        loop {
            super::sendfile_splice(
                super::SpliceMode::Splice,
                local_source.as_raw_fd(),
                write_end.as_raw_fd(),
                u64::MAX,
            );
        }
    });

    const BYTES: usize = 128 * 1024;
    b.bytes = BYTES as u64;
    b.iter(|| {
        assert_eq!(
            BYTES as u64,
            io::copy(&mut (&mut read_end).take(BYTES as u64), &mut &*local_end).unwrap()
        );
    });
}
<commit_msg>update test to check Take limits after copying<commit_after>use crate::env::temp_dir;
use crate::fs::OpenOptions;
use crate::io;
use crate::io::Result;
use crate::io::SeekFrom;
use crate::io::{BufRead, Read, Seek, Write};
use crate::os::unix::io::AsRawFd;

#[test]
fn copy_specialization() -> Result<()> {
    use crate::io::{BufReader, BufWriter};

    let path = crate::env::temp_dir();
    let source_path = path.join("copy-spec.source");
    let sink_path = path.join("copy-spec.sink");

    let result: Result<()> = try {
        let mut source = crate::fs::OpenOptions::new()
            .read(true)
            .write(true)
            .create(true)
            .truncate(true)
            .open(&source_path)?;
        source.write_all(b"abcdefghiklmnopqr")?;
        source.seek(SeekFrom::Start(8))?;
        let mut source = BufReader::with_capacity(8, source.take(5));
        source.fill_buf()?;
        assert_eq!(source.buffer(), b"iklmn");
        source.get_mut().set_limit(6);
        source.get_mut().get_mut().seek(SeekFrom::Start(1))?; // "bcdefg"
        let mut source = source.take(10); // "iklmnbcdef"

        let mut sink = crate::fs::OpenOptions::new()
            .read(true)
            .write(true)
            .create(true)
            .truncate(true)
            .open(&sink_path)?;
        sink.write_all(b"000000")?;
        let mut sink = BufWriter::with_capacity(5, sink);
        sink.write_all(b"wxyz")?;
        assert_eq!(sink.buffer(), b"wxyz");

        let copied = crate::io::copy(&mut source, &mut sink)?;
        assert_eq!(copied, 10, "copy obeyed limit imposed by Take");
        assert_eq!(sink.buffer().len(), 0, "sink buffer was flushed");
        assert_eq!(source.limit(), 0, "outer Take was exhausted");
        assert_eq!(source.get_ref().buffer().len(), 0, "source buffer should be drained");
        assert_eq!(
            source.get_ref().get_ref().limit(),
            1,
            "inner Take allowed reading beyond end of file, some bytes should be left"
        );

        let mut sink = sink.into_inner()?;
        sink.seek(SeekFrom::Start(0))?;
        let mut copied = Vec::new();
        sink.read_to_end(&mut copied)?;
        assert_eq!(&copied, b"000000wxyziklmnbcdef");
    };

    let rm1 = crate::fs::remove_file(source_path);
    let rm2 = crate::fs::remove_file(sink_path);

    result.and(rm1).and(rm2)
}

#[bench]
fn bench_file_to_file_copy(b: &mut test::Bencher) {
    const BYTES: usize = 128 * 1024;
    let src_path = temp_dir().join("file-copy-bench-src");
    let mut src = crate::fs::OpenOptions::new()
        .create(true)
        .truncate(true)
        .read(true)
        .write(true)
        .open(src_path)
        .unwrap();
    src.write(&vec![0u8; BYTES]).unwrap();

    let sink_path = temp_dir().join("file-copy-bench-sink");
    let mut sink = crate::fs::OpenOptions::new()
        .create(true)
        .truncate(true)
        .write(true)
        .open(sink_path)
        .unwrap();

    b.bytes = BYTES as u64;
    b.iter(|| {
        src.seek(SeekFrom::Start(0)).unwrap();
        sink.seek(SeekFrom::Start(0)).unwrap();
        assert_eq!(BYTES as u64, io::copy(&mut src, &mut sink).unwrap());
    });
}

#[bench]
fn bench_file_to_socket_copy(b: &mut test::Bencher) {
    const BYTES: usize = 128 * 1024;
    let src_path = temp_dir().join("pipe-copy-bench-src");
    let mut src = OpenOptions::new()
        .create(true)
        .truncate(true)
        .read(true)
        .write(true)
        .open(src_path)
        .unwrap();
    src.write(&vec![0u8; BYTES]).unwrap();

    let sink_drainer = crate::net::TcpListener::bind("localhost:0").unwrap();
    let mut sink = crate::net::TcpStream::connect(sink_drainer.local_addr().unwrap()).unwrap();
    let mut sink_drainer = sink_drainer.accept().unwrap().0;

    crate::thread::spawn(move || {
        let mut sink_buf = vec![0u8; 1024 * 1024];
        loop {
            sink_drainer.read(&mut sink_buf[..]).unwrap();
        }
    });

    b.bytes = BYTES as u64;
    b.iter(|| {
        src.seek(SeekFrom::Start(0)).unwrap();
        assert_eq!(BYTES as u64, io::copy(&mut src, &mut sink).unwrap());
    });
}

#[bench]
fn bench_file_to_uds_copy(b: &mut test::Bencher) {
    const BYTES: usize = 128 * 1024;
    let src_path = temp_dir().join("uds-copy-bench-src");
    let mut src = OpenOptions::new()
        .create(true)
        .truncate(true)
        .read(true)
        .write(true)
        .open(src_path)
        .unwrap();
    src.write(&vec![0u8; BYTES]).unwrap();

    let (mut sink, mut sink_drainer) = crate::os::unix::net::UnixStream::pair().unwrap();

    crate::thread::spawn(move || {
        let mut sink_buf = vec![0u8; 1024 * 1024];
        loop {
            sink_drainer.read(&mut sink_buf[..]).unwrap();
        }
    });

    b.bytes = BYTES as u64;
    b.iter(|| {
        src.seek(SeekFrom::Start(0)).unwrap();
        assert_eq!(BYTES as u64, io::copy(&mut src, &mut sink).unwrap());
    });
}

#[cfg(any(target_os = "linux", target_os = "android"))]
#[bench]
fn bench_socket_pipe_socket_copy(b: &mut test::Bencher) {
    use super::CopyResult;
    use crate::io::ErrorKind;
    use crate::process::{ChildStdin, ChildStdout};
    use crate::sys_common::FromInner;

    let (read_end, write_end) = crate::sys::pipe::anon_pipe().unwrap();

    let mut read_end = ChildStdout::from_inner(read_end);
    let write_end = ChildStdin::from_inner(write_end);

    let acceptor = crate::net::TcpListener::bind("localhost:0").unwrap();
    let mut remote_end = crate::net::TcpStream::connect(acceptor.local_addr().unwrap()).unwrap();

    let local_end = crate::sync::Arc::new(acceptor.accept().unwrap().0);

    // the data flow in this benchmark:
    //
    //                      socket(tx)  local_source
    // remote_end (write)  +-------->   (splice to)
    //                                  write_end
    //                                     +
    //                                     |
    //                                     | pipe
    //                                     v
    //                                  read_end
    // remote_end (read)   <---------+  (splice to) *
    //                      socket(rx)  local_end
    //
    // * benchmark loop using io::copy

    crate::thread::spawn(move || {
        let mut sink_buf = vec![0u8; 1024 * 1024];
        remote_end.set_nonblocking(true).unwrap();
        loop {
            match remote_end.write(&mut sink_buf[..]) {
                Err(err) if err.kind() == ErrorKind::WouldBlock => {}
                Ok(_) => {}
                err => {
                    err.expect("write failed");
                }
            };
            match remote_end.read(&mut sink_buf[..]) {
                Err(err) if err.kind() == ErrorKind::WouldBlock => {}
                Ok(_) => {}
                err => {
                    err.expect("read failed");
                }
            };
        }
    });

    // check that splice works, otherwise the benchmark would hang
    let probe = super::sendfile_splice(
        super::SpliceMode::Splice,
        local_end.as_raw_fd(),
        write_end.as_raw_fd(),
        1,
    );

    match probe {
        CopyResult::Ended(Ok(1)) => {
            // splice works
        }
        _ => {
            eprintln!("splice failed, skipping benchmark");
            return;
        }
    }

    let local_source = local_end.clone();
    crate::thread::spawn(move || {
        loop {
            super::sendfile_splice(
                super::SpliceMode::Splice,
                local_source.as_raw_fd(),
                write_end.as_raw_fd(),
                u64::MAX,
            );
        }
    });

    const BYTES: usize = 128 * 1024;
    b.bytes = BYTES as u64;
    b.iter(|| {
        assert_eq!(
            BYTES as u64,
            io::copy(&mut (&mut read_end).take(BYTES as u64), &mut &*local_end).unwrap()
        );
    });
}
<|endoftext|>


<commit_before>#![crate_name = "uutils"]

/*
 * This file is part of the uutils coreutils package.
 *
 * (c) Michael Gehring <mg@ebfe.org>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

include!(concat!(env!("OUT_DIR"), "/uutils_crates.rs"));

use std::collections::hash_map::HashMap;
use std::path::Path;
use std::env;

static NAME: &'static str = "uutils";
static VERSION: &'static str = env!("CARGO_PKG_VERSION");

include!(concat!(env!("OUT_DIR"), "/uutils_map.rs"));

fn usage(cmap: &UtilityMap) {
    println!("{} {}", NAME, VERSION);
    println!("");
    println!("Usage:");
    println!("  {} [util [arguments...]]\n", NAME);
    println!("Currently defined functions:");
    let mut utils: Vec<&str> = cmap.keys().map(|&s| s).collect();
    utils.sort();
    for util in utils.iter() {
        println!("\t{}", util);
    }
}

fn main() {
    let umap = util_map();
    let mut args : Vec<String> = env::args().collect();

    // try binary name as util name.
    let args0 = args[0].clone();
    let binary = Path::new(&args0[..]);
    let binary_as_util = binary.file_name().unwrap().to_str().unwrap();

    match umap.get(binary_as_util) {
        Some(&uumain) => {
            std::process::exit(uumain(args));
        }
        None => (),
    }

    if binary_as_util.ends_with("uutils") || binary_as_util.starts_with("uutils") ||
        binary_as_util.ends_with("busybox") || binary_as_util.starts_with("busybox") {
            // uutils can be called as either "uutils", "busybox"
            // "uutils-suffix" or "busybox-suffix". Not sure
            // what busybox uses the -suffix pattern for.
    } else {
        println!("{}: applet not found", binary_as_util);
        std::process::exit(1);
    }

    // try first arg as util name.
    if args.len() >= 2 {
        args.remove(0);
        let util = &args[0][..];

        match umap.get(util) {
            Some(&uumain) => {
                std::process::exit(uumain(args.clone()));
            }
            None => {
                if &args[0][..] == "--help" {
                    // see if they want help on a specific util
                    if args.len() >= 2 {
                        let util = &args[1][..];
                        match umap.get(util) {
                            Some(&uumain) => {
                                std::process::exit(uumain(vec![util.to_string(), "--help".to_string()]));
                            }
                            None => {
                                println!("{}: applet not found", util);
                                std::process::exit(1);
                            }
                        }
                    }
                    usage(&umap);
                    std::process::exit(0);
                } else {
                    println!("{}: applet not found", util);
                    std::process::exit(1);
                }
            }
        }
    } else {
        // no arguments provided
        usage(&umap);
        std::process::exit(0);
    }
}
<commit_msg>rm recognition of "busybox" bin name in uutils.rs<commit_after>#![crate_name = "uutils"]

/*
 * This file is part of the uutils coreutils package.
 *
 * (c) Michael Gehring <mg@ebfe.org>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

include!(concat!(env!("OUT_DIR"), "/uutils_crates.rs"));

use std::collections::hash_map::HashMap;
use std::path::Path;
use std::env;

static NAME: &'static str = "uutils";
static VERSION: &'static str = env!("CARGO_PKG_VERSION");

include!(concat!(env!("OUT_DIR"), "/uutils_map.rs"));

fn usage(cmap: &UtilityMap) {
    println!("{} {}", NAME, VERSION);
    println!("");
    println!("Usage:");
    println!("  {} [util [arguments...]]\n", NAME);
    println!("Currently defined functions:");
    let mut utils: Vec<&str> = cmap.keys().map(|&s| s).collect();
    utils.sort();
    for util in utils.iter() {
        println!("\t{}", util);
    }
}

fn main() {
    let umap = util_map();
    let mut args : Vec<String> = env::args().collect();

    // try binary name as util name.
    let args0 = args[0].clone();
    let binary = Path::new(&args0[..]);
    let binary_as_util = binary.file_name().unwrap().to_str().unwrap();

    match umap.get(binary_as_util) {
        Some(&uumain) => {
            std::process::exit(uumain(args));
        }
        None => (),
    }

    if !(binary_as_util.ends_with("uutils") || binary_as_util.starts_with("uutils")) {
        println!("{}: applet not found", binary_as_util);
        std::process::exit(1);
    }

    // try first arg as util name.
    if args.len() >= 2 {
        args.remove(0);
        let util = &args[0][..];

        match umap.get(util) {
            Some(&uumain) => {
                std::process::exit(uumain(args.clone()));
            }
            None => {
                if &args[0][..] == "--help" {
                    // see if they want help on a specific util
                    if args.len() >= 2 {
                        let util = &args[1][..];
                        match umap.get(util) {
                            Some(&uumain) => {
                                std::process::exit(uumain(vec![util.to_string(), "--help".to_string()]));
                            }
                            None => {
                                println!("{}: applet not found", util);
                                std::process::exit(1);
                            }
                        }
                    }
                    usage(&umap);
                    std::process::exit(0);
                } else {
                    println!("{}: applet not found", util);
                    std::process::exit(1);
                }
            }
        }
    } else {
        // no arguments provided
        usage(&umap);
        std::process::exit(0);
    }
}
<|endoftext|>


<commit_before>use std::collections::HashSet;
use std::fs::{read_dir, remove_dir_all, read_link};
use std::io::{stdout, stderr};
use std::collections::HashSet;
use std::path::Path;
use std::str::FromStr;

use libc::pid_t;
use argparse::{ArgumentParser, PushConst, StoreTrue};

use super::setup;
use super::Wrapper;

#[derive(Copy)]
enum Action {
    Temporary,
    Old,
    Everything,
    Orphans,
    Transient,
}

pub fn clean_cmd(wrapper: &Wrapper, cmdline: Vec<String>)
    -> Result<i32, String>
{
    let mut global = false;
    let mut dry_run = false;
    let mut actions = vec!();
    {
        let mut ap = ArgumentParser::new();
        ap.set_description("
            Performs various cleanup tasks
            ");
        ap.refer(&mut actions)
          .add_option(&["--tmp", "--tmp-folders"],
                PushConst(Action::Temporary),
                "Clean temporary containers (failed builds)")
          .add_option(&["--old", "--old-containers"], PushConst(Action::Old),
                "Clean old versions of containers (configurable)")
          .add_option(&["--transient"], PushConst(Action::Transient),
                "Clean unneeded transient folders (left from containers with
                 `write-mode` set to transient-something). The pid of process
                 is checked for liveness first.")
          .add_option(&["--everything"], PushConst(Action::Everything),
                "Clean whole `.vagga` folder. Useful when deleting a project.
                 With ``--global`` cleans whole storage-dir and cache-dir")
          .add_option(&["--orphans"], PushConst(Action::Orphans),
                "Without `--global` removes containers which are not in
                 vagga.yaml any more. With `--global` removes all folders
                 which have `.lnk` pointing to nowhere (i.e. project dir
                 already deleted while vagga folder is not)")
          .required();
        ap.refer(&mut global)
          .add_option(&["--global"], StoreTrue,
                "Apply cleanup command to all containers. Works only \
                if `storage-dir` is configured in settings");
        ap.refer(&mut dry_run)
          .add_option(&["-n", "--dry-run"], StoreTrue,
                "Dry run. Don't delete everything, just print");
        match ap.parse(cmdline, &mut stdout(), &mut stderr()) {
            Ok(()) => {}
            Err(0) => return Ok(0),
            Err(_) => {
                return Ok(1);
            }
        }
    }
    if global && wrapper.ext_settings.storage_dir.is_none() {
        error!("The --global flag is only meaningful if you configure \
            storage-dir in settings");
        return Ok(2);
    }
    for action in actions.iter() {
        let res = match *action {
            Action::Temporary => clean_temporary(wrapper, global, dry_run),
            Action::Old => clean_old(wrapper, global, dry_run),
            Action::Transient => clean_transient(wrapper, global, dry_run),
            _ => unimplemented!(),
        };
        match res {
            Ok(()) => {}
            Err(err) => {
                error!("Error cleaning up: {}", err);
                return Ok(3);
            }
        }
    }
    return Ok(0);
}

fn clean_dir(path: &Path, dry_run: bool) -> Result<(), String> {
    // TODO(tailhook) chroot to dir for removing
    if dry_run {
        println!("Would remove {:?}", path);
    } else {
        debug!("Removing {:?}", path);
        try!(remove_dir_all(path)
             .map_err(|x| format!("Error removing directory: {}", x)));
    }
    Ok(())
}

fn clean_temporary(wrapper: &Wrapper, global: bool, dry_run: bool)
    -> Result<(), String>
{
    if global {
        panic!("Global cleanup is not implemented yet");
    }
    let base = match try!(setup::get_vagga_base(
        wrapper.project_root, wrapper.ext_settings))
    {
        Some(base) => base,
        None => {
            warn!("No vagga directory exists");
            return Ok(());
        }
    };
    let roots = base.join(".roots");
    for path in try!(read_dir(&roots)
            .map_err(|e| format!("Can't read dir {:?}: {}", roots, e)))
            .iter()
    {
        if path.filename_str().map(|n| n.starts_with(".tmp")).unwrap_or(false)
        {
            try!(clean_dir(path, dry_run));
        }
    }

    return Ok(());
}

fn clean_old(wrapper: &Wrapper, global: bool, dry_run: bool)
    -> Result<(), String>
{
    if global {
        panic!("Global cleanup is not implemented yet");
    }
    let base = match try!(setup::get_vagga_base(
        wrapper.project_root, wrapper.ext_settings))
    {
        Some(base) => base,
        None => {
            warn!("No vagga directory exists");
            return Ok(());
        }
    };
    let useful: HashSet<String> = try!(
        read_dir(&wrapper.project_root.join(".vagga"))
            .map_err(|e| format!("Can't read vagga directory: {}", e)))
        .into_iter()
        .filter(|path| !path.filename_str()
                           .map(|f| f.starts_with("."))
                           .unwrap_or(true))
        .map(|path| read_link(&path)
                    .map_err(|e| warn!("Can't readlink {:?}: {}", path, e))
                    .ok()
                    .and_then(|f| {
                        let mut cmp = f.str_components().rev();
                        cmp.next();
                        // The container name is next to the last component
                        cmp.next().and_then(|x| x).map(ToString::to_string)
                    }))
        .filter(|x| x.is_some()).map(|x| x.unwrap())
        .collect();
    debug!("Useful images {:?}", useful);

    let roots = base.join(".roots");
    for path in try!(read_dir(&roots)
            .map_err(|e| format!("Can't read dir {:?}: {}", roots, e)))
            .iter()
    {
        if path.filename_str()
            .map(|n| !useful.contains(&n.to_string()))
            .unwrap_or(false)
        {
            try!(clean_dir(path, dry_run));
        }
    }

    return Ok(());
}

fn clean_transient(wrapper: &Wrapper, global: bool, dry_run: bool)
    -> Result<(), String>
{
    if global {
        panic!("Global cleanup is not implemented yet");
    }
    let base = match try!(setup::get_vagga_base(
        wrapper.project_root, wrapper.ext_settings))
    {
        Some(base) => base,
        None => {
            warn!("No vagga directory exists");
            return Ok(());
        }
    };
    let procfs = Path::new("/proc");
    for dir in try!(read_dir(&base.join(".transient"))
                    .map_err(|e| format!(
                             "Can't read .vagga/.transient dir: {}", e)))
                .into_iter()
                .filter(|path| path.extension_str()
                               .and_then(|e| FromStr::from_str(e).ok())
                               .map(|p: pid_t| !procfs.join(format!("{}", p))
                                              .exists())
                               .unwrap_or(true))
    {
        try!(clean_dir(&dir, dry_run));
    }

    return Ok(());
}
<commit_msg>Quickfix of merge error<commit_after>use std::collections::HashSet;
use std::fs::{read_dir, remove_dir_all, read_link};
use std::io::{stdout, stderr};
use std::path::Path;
use std::str::FromStr;

use libc::pid_t;
use argparse::{ArgumentParser, PushConst, StoreTrue};

use super::setup;
use super::Wrapper;

#[derive(Copy)]
enum Action {
    Temporary,
    Old,
    Everything,
    Orphans,
    Transient,
}

pub fn clean_cmd(wrapper: &Wrapper, cmdline: Vec<String>)
    -> Result<i32, String>
{
    let mut global = false;
    let mut dry_run = false;
    let mut actions = vec!();
    {
        let mut ap = ArgumentParser::new();
        ap.set_description("
            Performs various cleanup tasks
            ");
        ap.refer(&mut actions)
          .add_option(&["--tmp", "--tmp-folders"],
                PushConst(Action::Temporary),
                "Clean temporary containers (failed builds)")
          .add_option(&["--old", "--old-containers"], PushConst(Action::Old),
                "Clean old versions of containers (configurable)")
          .add_option(&["--transient"], PushConst(Action::Transient),
                "Clean unneeded transient folders (left from containers with
                 `write-mode` set to transient-something). The pid of process
                 is checked for liveness first.")
          .add_option(&["--everything"], PushConst(Action::Everything),
                "Clean whole `.vagga` folder. Useful when deleting a project.
                 With ``--global`` cleans whole storage-dir and cache-dir")
          .add_option(&["--orphans"], PushConst(Action::Orphans),
                "Without `--global` removes containers which are not in
                 vagga.yaml any more. With `--global` removes all folders
                 which have `.lnk` pointing to nowhere (i.e. project dir
                 already deleted while vagga folder is not)")
          .required();
        ap.refer(&mut global)
          .add_option(&["--global"], StoreTrue,
                "Apply cleanup command to all containers. Works only \
                if `storage-dir` is configured in settings");
        ap.refer(&mut dry_run)
          .add_option(&["-n", "--dry-run"], StoreTrue,
                "Dry run. Don't delete everything, just print");
        match ap.parse(cmdline, &mut stdout(), &mut stderr()) {
            Ok(()) => {}
            Err(0) => return Ok(0),
            Err(_) => {
                return Ok(1);
            }
        }
    }
    if global && wrapper.ext_settings.storage_dir.is_none() {
        error!("The --global flag is only meaningful if you configure \
            storage-dir in settings");
        return Ok(2);
    }
    for action in actions.iter() {
        let res = match *action {
            Action::Temporary => clean_temporary(wrapper, global, dry_run),
            Action::Old => clean_old(wrapper, global, dry_run),
            Action::Transient => clean_transient(wrapper, global, dry_run),
            _ => unimplemented!(),
        };
        match res {
            Ok(()) => {}
            Err(err) => {
                error!("Error cleaning up: {}", err);
                return Ok(3);
            }
        }
    }
    return Ok(0);
}

fn clean_dir(path: &Path, dry_run: bool) -> Result<(), String> {
    // TODO(tailhook) chroot to dir for removing
    if dry_run {
        println!("Would remove {:?}", path);
    } else {
        debug!("Removing {:?}", path);
        try!(remove_dir_all(path)
             .map_err(|x| format!("Error removing directory: {}", x)));
    }
    Ok(())
}

fn clean_temporary(wrapper: &Wrapper, global: bool, dry_run: bool)
    -> Result<(), String>
{
    if global {
        panic!("Global cleanup is not implemented yet");
    }
    let base = match try!(setup::get_vagga_base(
        wrapper.project_root, wrapper.ext_settings))
    {
        Some(base) => base,
        None => {
            warn!("No vagga directory exists");
            return Ok(());
        }
    };
    let roots = base.join(".roots");
    for path in try!(read_dir(&roots)
            .map_err(|e| format!("Can't read dir {:?}: {}", roots, e)))
            .iter()
    {
        if path.filename_str().map(|n| n.starts_with(".tmp")).unwrap_or(false)
        {
            try!(clean_dir(path, dry_run));
        }
    }

    return Ok(());
}

fn clean_old(wrapper: &Wrapper, global: bool, dry_run: bool)
    -> Result<(), String>
{
    if global {
        panic!("Global cleanup is not implemented yet");
    }
    let base = match try!(setup::get_vagga_base(
        wrapper.project_root, wrapper.ext_settings))
    {
        Some(base) => base,
        None => {
            warn!("No vagga directory exists");
            return Ok(());
        }
    };
    let useful: HashSet<String> = try!(
        read_dir(&wrapper.project_root.join(".vagga"))
            .map_err(|e| format!("Can't read vagga directory: {}", e)))
        .into_iter()
        .filter(|path| !path.filename_str()
                           .map(|f| f.starts_with("."))
                           .unwrap_or(true))
        .map(|path| read_link(&path)
                    .map_err(|e| warn!("Can't readlink {:?}: {}", path, e))
                    .ok()
                    .and_then(|f| {
                        let mut cmp = f.str_components().rev();
                        cmp.next();
                        // The container name is next to the last component
                        cmp.next().and_then(|x| x).map(ToString::to_string)
                    }))
        .filter(|x| x.is_some()).map(|x| x.unwrap())
        .collect();
    debug!("Useful images {:?}", useful);

    let roots = base.join(".roots");
    for path in try!(read_dir(&roots)
            .map_err(|e| format!("Can't read dir {:?}: {}", roots, e)))
            .iter()
    {
        if path.filename_str()
            .map(|n| !useful.contains(&n.to_string()))
            .unwrap_or(false)
        {
            try!(clean_dir(path, dry_run));
        }
    }

    return Ok(());
}

fn clean_transient(wrapper: &Wrapper, global: bool, dry_run: bool)
    -> Result<(), String>
{
    if global {
        panic!("Global cleanup is not implemented yet");
    }
    let base = match try!(setup::get_vagga_base(
        wrapper.project_root, wrapper.ext_settings))
    {
        Some(base) => base,
        None => {
            warn!("No vagga directory exists");
            return Ok(());
        }
    };
    let procfs = Path::new("/proc");
    for dir in try!(read_dir(&base.join(".transient"))
                    .map_err(|e| format!(
                             "Can't read .vagga/.transient dir: {}", e)))
                .into_iter()
                .filter(|path| path.extension_str()
                               .and_then(|e| FromStr::from_str(e).ok())
                               .map(|p: pid_t| !procfs.join(format!("{}", p))
                                              .exists())
                               .unwrap_or(true))
    {
        try!(clean_dir(&dir, dry_run));
    }

    return Ok(());
}
<|endoftext|>


<commit_before>

use cargo_edit::Manifest;
use list_error::ListError;
use pad::{Alignment, PadStr};
use toml;

/// List the dependencies for manifest section
#[allow(deprecated)] // connect -> join
pub fn list_section(manifest: &Manifest, section: &str) -> Result<String, ListError> {
    let mut output = vec![];

    let list = try!(manifest.data
        .get(section)
        .and_then(|field| field.as_table())
        .ok_or_else(|| ListError::SectionMissing(String::from(section))));

    let name_max_len = list.keys().map(|k| k.len()).max().unwrap_or(0);

    for (name, val) in list {
        let version = match *val {
            toml::Value::String(ref version) => version.clone(),
            toml::Value::Table(_) => {
                try!(val.lookup("version")
                    .and_then(|field| field.as_str().map(|s| s.to_owned()))
                    .or_else(|| val.lookup("git").map(|repo| format!("git: {}", repo)))
                    .or_else(|| val.lookup("path").map(|path| format!("path: {}", path)))
                    .ok_or_else(|| ListError::VersionMissing(name.clone(), section.to_owned())))
            }
            _ => String::from(""),
        };

        let optional = if let toml::Value::Table(_) = *val {
            val.lookup("optional")
                .and_then(|field| field.as_bool())
                .unwrap_or(false)
        } else {
            false
        };

        output.push(format!("{name} {version}{optional}",
                            name =
                                name.pad_to_width_with_alignment(name_max_len, Alignment::Left),
                            version = version,
                            optional = if optional { " (optional)" } else { "" }));
    }

    Ok(output.connect("\n"))
}

#[cfg(test)]
mod test {
    use cargo_edit::Manifest;
    use super::list_section;

    static DEFAULT_CARGO_TOML: &'static str = r#"[package]
authors = ["Some Guy"]
name = "lorem-ipsum"
version = "0.1.0"

[dependencies]
foo-bar = "0.1"
lorem-ipsum = "0.4.2""#;

    #[test]
    fn basic_listing() {
        let manifile: Manifest = DEFAULT_CARGO_TOML.parse().unwrap();

        assert_eq!(list_section(&manifile, "dependencies").unwrap(),
                   "\
foo-bar     0.1
lorem-ipsum 0.4.2");
    }

    #[test]
    #[should_panic]
    fn unknown_section() {
        let manifile: Manifest = DEFAULT_CARGO_TOML.parse().unwrap();

        list_section(&manifile, "lol-dependencies").unwrap();
    }
}
<commit_msg>Remove redundant space if output does not contain a version.<commit_after>

use cargo_edit::Manifest;
use list_error::ListError;
use pad::{Alignment, PadStr};
use toml;

/// List the dependencies for manifest section
#[allow(deprecated)] // connect -> join
pub fn list_section(manifest: &Manifest, section: &str) -> Result<String, ListError> {
    let mut output = vec![];

    let list = try!(manifest.data
        .get(section)
        .and_then(|field| field.as_table())
        .ok_or_else(|| ListError::SectionMissing(String::from(section))));

    let name_max_len = list.keys().map(|k| k.len()).max().unwrap_or(0);

    for (name, val) in list {
        let version = match *val {
            toml::Value::String(ref version) => version.clone(),
            toml::Value::Table(_) => {
                try!(val.lookup("version")
                    .and_then(|field| field.as_str().map(|s| s.to_owned()))
                    .or_else(|| val.lookup("git").map(|repo| format!("git: {}", repo)))
                    .or_else(|| val.lookup("path").map(|path| format!("path: {}", path)))
                    .ok_or_else(|| ListError::VersionMissing(name.clone(), section.to_owned())))
            }
            _ => String::from(""),
        };

        let optional = if let toml::Value::Table(_) = *val {
            val.lookup("optional")
                .and_then(|field| field.as_bool())
                .unwrap_or(false)
        } else {
            false
        };

        output.push(format!("{name}{}{version}{optional}",
                            if version.is_empty() { "" } else { " " },
                            name =
                                name.pad_to_width_with_alignment(name_max_len, Alignment::Left),
                            version = version,
                            optional = if optional { " (optional)" } else { "" }));
    }

    Ok(output.connect("\n"))
}

#[cfg(test)]
mod test {
    use cargo_edit::Manifest;
    use super::list_section;

    static DEFAULT_CARGO_TOML: &'static str = r#"[package]
authors = ["Some Guy"]
name = "lorem-ipsum"
version = "0.1.0"

[dependencies]
foo-bar = "0.1"
lorem-ipsum = "0.4.2""#;

    #[test]
    fn basic_listing() {
        let manifile: Manifest = DEFAULT_CARGO_TOML.parse().unwrap();

        assert_eq!(list_section(&manifile, "dependencies").unwrap(),
                   "\
foo-bar     0.1
lorem-ipsum 0.4.2");
    }

    #[test]
    #[should_panic]
    fn unknown_section() {
        let manifile: Manifest = DEFAULT_CARGO_TOML.parse().unwrap();

        list_section(&manifile, "lol-dependencies").unwrap();
    }
}
<|endoftext|>


<commit_before>use toml:: { Parser, Decoder, Value };
use rustc_serialize:: { Decodable };
use std::default:: { Default };
use std::path:: { Path };
use std::fs::File;
use std::io:: { Read, Result };
use std::borrow:: { Borrow };

#[derive(RustcDecodable)]
pub struct Configuration {
    server: Server
}

#[derive(RustcDecodable)]
pub struct Server {
    host: String,
    port: i64
}

impl Configuration {
    pub fn fromFile(path: &Path) -> Self {
        from_toml_file(path).unwrap()
    }
}

impl Default for Configuration {
    fn default() -> Self {
        Configuration {
            server: Server {
                host: "127.0.0.1".to_string(),
                port: 6767
            }
        }
    }
}

pub fn from_toml_file(path: &Path) -> Result<Configuration> {
    let content = read_file(path).unwrap();
    let toml = &content[..];
    let value = Parser::new(toml).parse().unwrap();
    let mut decoder = Decoder::new(Value::Table(value));
    let configuration = Configuration::decode(&mut decoder).unwrap();
    Ok(configuration)
}

pub fn read_file(path: &Path) -> Result<String> {
    let mut file = try!(File::open(path));
    let mut buffer = String::new();
    let _ = try!(file.read_to_string(&mut buffer));
    Ok(buffer.clone())
}
<commit_msg>add server default<commit_after>use toml:: { Parser, Decoder, Value };
use rustc_serialize:: { Decodable };
use std::default:: { Default };
use std::path:: { Path };
use std::fs::File;
use std::io:: { Read, Result };
use std::borrow:: { Borrow };

#[derive(RustcDecodable)]
pub struct Configuration {
    server: Server
}

#[derive(RustcDecodable)]
pub struct Server {
    host: String,
    port: i64
}

impl Configuration {
    pub fn fromFile(path: &Path) -> Self {
        from_toml_file(path).unwrap()
    }
}

impl Default for Server {
    fn default() -> Self {
        Server {
            host: "127.0.0.1".to_string(),
            port: 6767
        }
    }
}

impl Default for Configuration {
    fn default() -> Self {
        Configuration {
            server: Server::default()
        }
    }
}

pub fn from_toml_file(path: &Path) -> Result<Configuration> {
    let content = read_file(path).unwrap();
    let toml = &content[..];
    let value = Parser::new(toml).parse().unwrap();
    let mut decoder = Decoder::new(Value::Table(value));
    let configuration = Configuration::decode(&mut decoder).unwrap();
    Ok(configuration)
}

pub fn read_file(path: &Path) -> Result<String> {
    let mut file = try!(File::open(path));
    let mut buffer = String::new();
    let _ = try!(file.read_to_string(&mut buffer));
    Ok(buffer.clone())
}
<|endoftext|>