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

use std::env;
use std::thread;
use std::process;
use std::sync::mpsc::{self, TryRecvError};

use piston_window::{
    PistonWindow,
    WindowSettings,
    G2d,
    context,
    clear,
    line,
    polygon,
};

use app::{TurtleApp, ReadOnly};
use extensions::ConvertScreenCoordinates;
use state::{Path, Polygon, Pen, TurtleState, DrawingState};
use query::DrawingCommand;
use event::{Event, from_piston_event};
use types::Point;
use color::{self, Color};
use server;

/// Setup the turtle window in advance
///
/// You must call this function at the beginning of `main()` if you do not create the
/// turtle immediately using [`Turtle::new()`].
///
/// It's a good idea to call this function before any other code runs in `main()`. Programs that
/// parse command line arguments or look at environment variables may **fail** to start if this
/// function is not called right at the beginning of the program. Programs that perform any
/// expensive computations may experience delayed start up problems unless they call this
/// function first.
///
/// The [`Turtle::new()`] method will call this function for you so that you don't need to worry
/// about this unless you are doing something before that.
///
/// # Example
/// ```rust,no_run
/// # #![allow(unused_variables, unused_mut)]
/// extern crate turtle;
/// use turtle::{self, Turtle};
///
/// fn main() {
///     // Initializes the turtle renderer first so that there is less delay when a Turtle
///     // is created and so that there are no conflicts with command line arguments or
///     // environment variables.
///     // Not required if Turtle::new() is already at the top of main.
///     turtle::setup();
///
///     // Do all kinds of expensive work here...
///     // Feel free to check environment variables, command line arguments, etc.
///
///     // Create the turtle when you are ready
///     // Turtle::new() will also call setup(), but calling it twice doesn't matter
///     let mut turtle = Turtle::new();
///     // Do things with the turtle...
/// }
/// ```
///
/// [`Turtle::new()`]: struct.Turtle.html#method.new
pub fn setup() {
    // If this environment variable is present, this process is taken over so that no other
    // code runs after main(). This allows us to ship one executable that appears to
    // have two separate processes.
    // We run the renderer loop and then immediately exit.
    if env::var("RUN_TURTLE_CANVAS").unwrap_or_else(|_| "".to_owned()) == "true" {
        // This code MUST be run on the main thread.

        // Run the canvas process
        main();
        unreachable!("bug: renderer loop did not exit after finishing");
    }
}

/// Run the renderer process in the current thread
///
/// This function must run in the main thread ONLY
pub fn main() {
    let app = TurtleApp::new();
    let read_only = app.read_only();
    let (drawing_tx, drawing_rx) = mpsc::channel();
    let (events_tx, events_rx) = mpsc::channel();

    // The running channel is entirely for checking if the other thread is still active.
    // We need to check because while we can exit while that thread is still running, we want
    // any errors caused in that thread to be reported.
    let (running_tx, running_rx) = mpsc::channel();
    let handle = thread::spawn(move || {
        server::run(app, drawing_tx, events_rx, running_tx);
    });

    // Renderer MUST run on the main thread or else it will panic on MacOS
    #[cfg(not(any(feature = "test", test)))]
    Renderer::new().run(drawing_rx, events_tx, read_only);

    // Quit immediately when the window is closed

    // Check if an error has occurred on the thread
    match running_rx.try_recv() {
        Ok(_) => unreachable!("bug: running channel should always be empty"),
        // The thread was still running, exit normally
        Err(mpsc::TryRecvError::Empty) => process::exit(0),
        Err(mpsc::TryRecvError::Disconnected) => match handle.join() {
            Ok(_) => process::exit(0),
            // The other thread must have panicked
            Err(_) => process::exit(1),
        },
    }
}

#[derive(Debug)]
pub enum Drawing {
    Path(Path),
    Polygon(Polygon),
}

pub struct Renderer {
    drawings: Vec<Drawing>,
    /// Polygon that is currently in the process of being filled
    /// Removed when EndFill is sent
    fill_polygon: Option<(Vec<Path>, Polygon)>,
}

impl Renderer {
    pub fn new() -> Renderer {
        Self {
            drawings: Vec::new(),
            fill_polygon: None,
        }
    }

    pub fn run(
        &mut self,
        drawing_rx: mpsc::Receiver<DrawingCommand>,
        events_tx: mpsc::Sender<Event>,
        state: ReadOnly,
    ) {
        let mut window: PistonWindow = WindowSettings::new(
            "Turtle", [800, 600]
        ).exit_on_esc(true).build().unwrap();

        let mut center = [0.0, 0.0];

        'renderloop:
        while let Some(e) = window.next() {
            if let Some(event) = from_piston_event(&e, |pt| pt.to_local_coords(center)) {
                match events_tx.send(event) {
                    Ok(_) => {},
                    // Quit - the server thread must have quit
                    Err(_) => break,
                }
            }

            // Need to handle all of the queries we receive at once so that any lag caused by
            // how long rendering takes doesn't cause any problems
            loop {
                match drawing_rx.try_recv() {
                    Ok(cmd) => self.handle_drawing_command(cmd),
                    Err(TryRecvError::Empty) => break, // Do nothing
                    Err(TryRecvError::Disconnected) => break 'renderloop, // Quit
                }
            }

            window.draw_2d(&e, |c, g| {
                let view = c.get_view_size();
                let width = view[0] as f64;
                let height = view[1] as f64;
                center = [width * 0.5, height * 0.5];

                // We clone the relevant state before rendering so that the rendering thread
                // doesn't need to keep locking, waiting or making the main thread wait
                let drawing = state.drawing().clone();
                let temporary_path = state.temporary_path().clone();
                let turtle = state.turtle().clone();

                self.render(c, g, center, &drawing, &temporary_path, &turtle);
            });
        }
    }

    /// Handles a drawing command sent from the main thread
    fn handle_drawing_command(&mut self, command: DrawingCommand) {
        //NOTE: Do not pass the ReadOnly state to this function. By the time a DrawingCommand is
        // handled, that state may be completely out of date
        use self::DrawingCommand::*;
        match command {
            StorePath(path) => {
                if self.fill_polygon.is_some() {
                    let &mut (ref mut border, ref mut poly) = self.fill_polygon.as_mut().unwrap();
                    border.push(path.clone());

                    let Path {start, end, ..} = path;
                    if poly.vertices.last().map_or(true, |&v| v != start) {
                        poly.vertices.push(start);
                    }
                    poly.vertices.push(end);
                }
                else if path.pen.enabled {
                    self.drawings.push(Drawing::Path(path));
                }
            },
            BeginFill(fill_color) => {
                // Calling begin_fill multiple times is okay, it just won't do anything until
                // end_fill is called
                self.fill_polygon = self.fill_polygon.take().or_else(|| Some((Vec::new(), Polygon {
                    vertices: Vec::new(),
                    fill_color: fill_color,
                })));
            },
            // Calling end_fill multiple times is not a problem
            EndFill => if let Some((border, poly)) = self.fill_polygon.take() {
                // Always add the border over the filled polygon so the border is drawn on top
                self.drawings.push(Drawing::Polygon(poly));
                self.drawings.extend(border.into_iter().filter_map(|p| if p.pen.enabled {
                    Some(Drawing::Path(p))
                } else { None }));
            },
            Clear => {
                self.drawings.clear();
                // Because clear doesn't actually shorten the capacity of the vector
                // We don't want to leak memory by leaving this Vec at whatever its size was before
                self.drawings.shrink_to_fit();
                self.fill_polygon.take();
            }
        }
    }

    /// The main rendering route. Dispatches to other functions as needed.
    fn render(&self, c: context::Context, g: &mut G2d, center: Point,
        drawing: &DrawingState, temporary_path: &Option<Path>, turtle: &TurtleState) {
        let background = drawing.background;
        clear(background.into(), g);

        for drawing in &self.drawings {
            match *drawing {
                Drawing::Path(ref path) => self.render_path(c, g, center, path),
                Drawing::Polygon(ref poly) => self.render_polygon(c, g, center,
                    poly.fill_color, poly.vertices.iter()),
            }
        }

        if let Some(&(ref border, ref poly)) = self.fill_polygon.as_ref() {
            // If the temporary_path is not None, we need to add it to the polygon being
            // filled or else the polygon will fall one edge behind in the animation
            let extra = temporary_path.as_ref().map_or(Vec::new(), |&Path {start, end, ..}| {
                if poly.vertices.last().map_or(true, |&v| v != start) {
                    vec![start, end]
                }
                else {
                    vec![end]
                }
            });
            self.render_polygon(c, g, center, poly.fill_color,
                poly.vertices.iter().chain(extra.iter()));

            for path in border {
                if path.pen.enabled {
                    self.render_path(c, g, center, path);
                }
            }
        }

        if let Some(ref path) = *temporary_path {
            if path.pen.enabled {
                self.render_path(c, g, center, path);
            }
        }

        self.render_shell(c, g, center, turtle);
    }

    /// Render a path assuming that its pen is enabled
    fn render_path(&self, c: context::Context, g: &mut G2d, center: Point, path: &Path) {
        let &Path {start, end, ref pen} = path;
        let &Pen {thickness, color, enabled} = pen;
        debug_assert!(enabled, "bug: attempt to render path when pen was not enabled");

        let start = start.to_screen_coords(center);
        let end = end.to_screen_coords(center);

        line(color.into(), thickness,
            [start[0], start[1], end[0], end[1]],
            c.transform, g);
    }

    /// Render a polygon given its vertices
    fn render_polygon<'a, T: Iterator<Item=&'a Point>>(
        &self,
        c: context::Context,
        g: &mut G2d,
        center: Point,
        fill_color: Color,
        verts: T,
    ) {
        // Performance note: Why make this function generic instead of just taking Polygon?
        // Answer: render_polygon is called multiple times. It's called repeatedly in a loop, and
        // it is also called when drawing the current fill_polygon. Rather than moving the
        // code to *maybe* add the temporary_path to the rendered polygon into this method, we
        // avoid branching unnecessarily by allowing the repeated caller to do what is fast, then
        // doing the slow thing (checking if the path is None) only once when it is needed.
        //
        // We pass in the points as an Iterator so that they do not need to be collected into any
        // struct. This avoids an allocation that really isn't needed since these are all temporary
        // anyway. Everything is going to get copied anyway on the next line. No need to do it
        // twice.
        //
        // See the commit before this comment was added for the approach that would have required
        // branching in every iteration of the loop where render_polygon is called over and over
        // again.
        let verts = verts.map(|p| p.to_screen_coords(center)).collect::<Vec<_>>();
        polygon(fill_color.into(), &verts, c.transform, g);
    }

    /// Draw the turtle's shell
    fn render_shell(&self, c: context::Context, g: &mut G2d, center: Point,
        &TurtleState {position, heading, visible, ..}: &TurtleState) {
        // Calculate all the points on the shell by rotating the shell shape by the turtle's
        // heading and moving it to the turtle's position
        if !visible {
            return;
        }

        let cos = heading.cos();
        let sin = heading.sin();
        let turtle_x = position[0];
        let turtle_y = position[1];
        let shell: Vec<_> = [
            [0., 15.],
            [10., 0.],
            [0., -15.],
        ].into_iter().map(|pt| {
            // Rotate each point by the heading and add the current turtle position
            let x = cos * pt[0] - sin * pt[1] + turtle_x;
            let y = sin * pt[0] + cos * pt[1] + turtle_y;
            [x, y].to_screen_coords(center)
        }).collect();

        // Draw the turtle shell with its background first, then its border
        polygon(color::WHITE.into(), &shell, c.transform, g);
        for i in 0..shell.len() {
            let start = shell[i];
            let end = shell[(i + 1) % shell.len()];

            line(color::BLACK.into(), 1.,
            [start[0], start[1], end[0], end[1]],
            c.transform, g);
        }
    }
}
<commit_msg>Removed redundant use of self in setup() example<commit_after>// During tests, we disable the renderer and that causes a bunch of warnings that we just want
// to get rid of.
// See Cargo.toml for an explanation of this attribute
#![cfg_attr(any(feature = "test", test), allow(dead_code, unused_variables))]

use std::env;
use std::thread;
use std::process;
use std::sync::mpsc::{self, TryRecvError};

use piston_window::{
    PistonWindow,
    WindowSettings,
    G2d,
    context,
    clear,
    line,
    polygon,
};

use app::{TurtleApp, ReadOnly};
use extensions::ConvertScreenCoordinates;
use state::{Path, Polygon, Pen, TurtleState, DrawingState};
use query::DrawingCommand;
use event::{Event, from_piston_event};
use types::Point;
use color::{self, Color};
use server;

/// Setup the turtle window in advance
///
/// You must call this function at the beginning of `main()` if you do not create the
/// turtle immediately using [`Turtle::new()`].
///
/// It's a good idea to call this function before any other code runs in `main()`. Programs that
/// parse command line arguments or look at environment variables may **fail** to start if this
/// function is not called right at the beginning of the program. Programs that perform any
/// expensive computations may experience delayed start up problems unless they call this
/// function first.
///
/// The [`Turtle::new()`] method will call this function for you so that you don't need to worry
/// about this unless you are doing something before that.
///
/// # Example
/// ```rust,no_run
/// # #![allow(unused_variables, unused_mut)]
/// extern crate turtle;
/// use turtle::Turtle;
///
/// fn main() {
///     // Initializes the turtle renderer first so that there is less delay when a Turtle
///     // is created and so that there are no conflicts with command line arguments or
///     // environment variables.
///     // Not required if Turtle::new() is already at the top of main.
///     turtle::setup();
///
///     // Do all kinds of expensive work here...
///     // Feel free to check environment variables, command line arguments, etc.
///
///     // Create the turtle when you are ready
///     // Turtle::new() will also call setup(), but calling it twice doesn't matter
///     let mut turtle = Turtle::new();
///     // Do things with the turtle...
/// }
/// ```
///
/// [`Turtle::new()`]: struct.Turtle.html#method.new
pub fn setup() {
    // If this environment variable is present, this process is taken over so that no other
    // code runs after main(). This allows us to ship one executable that appears to
    // have two separate processes.
    // We run the renderer loop and then immediately exit.
    if env::var("RUN_TURTLE_CANVAS").unwrap_or_else(|_| "".to_owned()) == "true" {
        // This code MUST be run on the main thread.

        // Run the canvas process
        main();
        unreachable!("bug: renderer loop did not exit after finishing");
    }
}

/// Run the renderer process in the current thread
///
/// This function must run in the main thread ONLY
pub fn main() {
    let app = TurtleApp::new();
    let read_only = app.read_only();
    let (drawing_tx, drawing_rx) = mpsc::channel();
    let (events_tx, events_rx) = mpsc::channel();

    // The running channel is entirely for checking if the other thread is still active.
    // We need to check because while we can exit while that thread is still running, we want
    // any errors caused in that thread to be reported.
    let (running_tx, running_rx) = mpsc::channel();
    let handle = thread::spawn(move || {
        server::run(app, drawing_tx, events_rx, running_tx);
    });

    // Renderer MUST run on the main thread or else it will panic on MacOS
    #[cfg(not(any(feature = "test", test)))]
    Renderer::new().run(drawing_rx, events_tx, read_only);

    // Quit immediately when the window is closed

    // Check if an error has occurred on the thread
    match running_rx.try_recv() {
        Ok(_) => unreachable!("bug: running channel should always be empty"),
        // The thread was still running, exit normally
        Err(mpsc::TryRecvError::Empty) => process::exit(0),
        Err(mpsc::TryRecvError::Disconnected) => match handle.join() {
            Ok(_) => process::exit(0),
            // The other thread must have panicked
            Err(_) => process::exit(1),
        },
    }
}

#[derive(Debug)]
pub enum Drawing {
    Path(Path),
    Polygon(Polygon),
}

pub struct Renderer {
    drawings: Vec<Drawing>,
    /// Polygon that is currently in the process of being filled
    /// Removed when EndFill is sent
    fill_polygon: Option<(Vec<Path>, Polygon)>,
}

impl Renderer {
    pub fn new() -> Renderer {
        Self {
            drawings: Vec::new(),
            fill_polygon: None,
        }
    }

    pub fn run(
        &mut self,
        drawing_rx: mpsc::Receiver<DrawingCommand>,
        events_tx: mpsc::Sender<Event>,
        state: ReadOnly,
    ) {
        let mut window: PistonWindow = WindowSettings::new(
            "Turtle", [800, 600]
        ).exit_on_esc(true).build().unwrap();

        let mut center = [0.0, 0.0];

        'renderloop:
        while let Some(e) = window.next() {
            if let Some(event) = from_piston_event(&e, |pt| pt.to_local_coords(center)) {
                match events_tx.send(event) {
                    Ok(_) => {},
                    // Quit - the server thread must have quit
                    Err(_) => break,
                }
            }

            // Need to handle all of the queries we receive at once so that any lag caused by
            // how long rendering takes doesn't cause any problems
            loop {
                match drawing_rx.try_recv() {
                    Ok(cmd) => self.handle_drawing_command(cmd),
                    Err(TryRecvError::Empty) => break, // Do nothing
                    Err(TryRecvError::Disconnected) => break 'renderloop, // Quit
                }
            }

            window.draw_2d(&e, |c, g| {
                let view = c.get_view_size();
                let width = view[0] as f64;
                let height = view[1] as f64;
                center = [width * 0.5, height * 0.5];

                // We clone the relevant state before rendering so that the rendering thread
                // doesn't need to keep locking, waiting or making the main thread wait
                let drawing = state.drawing().clone();
                let temporary_path = state.temporary_path().clone();
                let turtle = state.turtle().clone();

                self.render(c, g, center, &drawing, &temporary_path, &turtle);
            });
        }
    }

    /// Handles a drawing command sent from the main thread
    fn handle_drawing_command(&mut self, command: DrawingCommand) {
        //NOTE: Do not pass the ReadOnly state to this function. By the time a DrawingCommand is
        // handled, that state may be completely out of date
        use self::DrawingCommand::*;
        match command {
            StorePath(path) => {
                if self.fill_polygon.is_some() {
                    let &mut (ref mut border, ref mut poly) = self.fill_polygon.as_mut().unwrap();
                    border.push(path.clone());

                    let Path {start, end, ..} = path;
                    if poly.vertices.last().map_or(true, |&v| v != start) {
                        poly.vertices.push(start);
                    }
                    poly.vertices.push(end);
                }
                else if path.pen.enabled {
                    self.drawings.push(Drawing::Path(path));
                }
            },
            BeginFill(fill_color) => {
                // Calling begin_fill multiple times is okay, it just won't do anything until
                // end_fill is called
                self.fill_polygon = self.fill_polygon.take().or_else(|| Some((Vec::new(), Polygon {
                    vertices: Vec::new(),
                    fill_color: fill_color,
                })));
            },
            // Calling end_fill multiple times is not a problem
            EndFill => if let Some((border, poly)) = self.fill_polygon.take() {
                // Always add the border over the filled polygon so the border is drawn on top
                self.drawings.push(Drawing::Polygon(poly));
                self.drawings.extend(border.into_iter().filter_map(|p| if p.pen.enabled {
                    Some(Drawing::Path(p))
                } else { None }));
            },
            Clear => {
                self.drawings.clear();
                // Because clear doesn't actually shorten the capacity of the vector
                // We don't want to leak memory by leaving this Vec at whatever its size was before
                self.drawings.shrink_to_fit();
                self.fill_polygon.take();
            }
        }
    }

    /// The main rendering route. Dispatches to other functions as needed.
    fn render(&self, c: context::Context, g: &mut G2d, center: Point,
        drawing: &DrawingState, temporary_path: &Option<Path>, turtle: &TurtleState) {
        let background = drawing.background;
        clear(background.into(), g);

        for drawing in &self.drawings {
            match *drawing {
                Drawing::Path(ref path) => self.render_path(c, g, center, path),
                Drawing::Polygon(ref poly) => self.render_polygon(c, g, center,
                    poly.fill_color, poly.vertices.iter()),
            }
        }

        if let Some(&(ref border, ref poly)) = self.fill_polygon.as_ref() {
            // If the temporary_path is not None, we need to add it to the polygon being
            // filled or else the polygon will fall one edge behind in the animation
            let extra = temporary_path.as_ref().map_or(Vec::new(), |&Path {start, end, ..}| {
                if poly.vertices.last().map_or(true, |&v| v != start) {
                    vec![start, end]
                }
                else {
                    vec![end]
                }
            });
            self.render_polygon(c, g, center, poly.fill_color,
                poly.vertices.iter().chain(extra.iter()));

            for path in border {
                if path.pen.enabled {
                    self.render_path(c, g, center, path);
                }
            }
        }

        if let Some(ref path) = *temporary_path {
            if path.pen.enabled {
                self.render_path(c, g, center, path);
            }
        }

        self.render_shell(c, g, center, turtle);
    }

    /// Render a path assuming that its pen is enabled
    fn render_path(&self, c: context::Context, g: &mut G2d, center: Point, path: &Path) {
        let &Path {start, end, ref pen} = path;
        let &Pen {thickness, color, enabled} = pen;
        debug_assert!(enabled, "bug: attempt to render path when pen was not enabled");

        let start = start.to_screen_coords(center);
        let end = end.to_screen_coords(center);

        line(color.into(), thickness,
            [start[0], start[1], end[0], end[1]],
            c.transform, g);
    }

    /// Render a polygon given its vertices
    fn render_polygon<'a, T: Iterator<Item=&'a Point>>(
        &self,
        c: context::Context,
        g: &mut G2d,
        center: Point,
        fill_color: Color,
        verts: T,
    ) {
        // Performance note: Why make this function generic instead of just taking Polygon?
        // Answer: render_polygon is called multiple times. It's called repeatedly in a loop, and
        // it is also called when drawing the current fill_polygon. Rather than moving the
        // code to *maybe* add the temporary_path to the rendered polygon into this method, we
        // avoid branching unnecessarily by allowing the repeated caller to do what is fast, then
        // doing the slow thing (checking if the path is None) only once when it is needed.
        //
        // We pass in the points as an Iterator so that they do not need to be collected into any
        // struct. This avoids an allocation that really isn't needed since these are all temporary
        // anyway. Everything is going to get copied anyway on the next line. No need to do it
        // twice.
        //
        // See the commit before this comment was added for the approach that would have required
        // branching in every iteration of the loop where render_polygon is called over and over
        // again.
        let verts = verts.map(|p| p.to_screen_coords(center)).collect::<Vec<_>>();
        polygon(fill_color.into(), &verts, c.transform, g);
    }

    /// Draw the turtle's shell
    fn render_shell(&self, c: context::Context, g: &mut G2d, center: Point,
        &TurtleState {position, heading, visible, ..}: &TurtleState) {
        // Calculate all the points on the shell by rotating the shell shape by the turtle's
        // heading and moving it to the turtle's position
        if !visible {
            return;
        }

        let cos = heading.cos();
        let sin = heading.sin();
        let turtle_x = position[0];
        let turtle_y = position[1];
        let shell: Vec<_> = [
            [0., 15.],
            [10., 0.],
            [0., -15.],
        ].into_iter().map(|pt| {
            // Rotate each point by the heading and add the current turtle position
            let x = cos * pt[0] - sin * pt[1] + turtle_x;
            let y = sin * pt[0] + cos * pt[1] + turtle_y;
            [x, y].to_screen_coords(center)
        }).collect();

        // Draw the turtle shell with its background first, then its border
        polygon(color::WHITE.into(), &shell, c.transform, g);
        for i in 0..shell.len() {
            let start = shell[i];
            let end = shell[(i + 1) % shell.len()];

            line(color::BLACK.into(), 1.,
            [start[0], start[1], end[0], end[1]],
            c.transform, g);
        }
    }
}
<|endoftext|>


<commit_before>use ruru::{RString, Object, Class, AnyObject};
extern crate ruby_sys;
use debug::RubyDebugInfo;
use pathname::Pathname;

pub trait TryFrom<T>: Sized {
  type Error;

  fn try_from(value: T) -> Result<Self, Self::Error>;
}

#[inline]
pub fn is_same_path(a: &str, b: &str) -> bool {
  if cfg!(windows) {
    a.to_uppercase() == b.to_uppercase()
  } else {
    a == b
  }
}

pub fn anyobject_to_string(item: AnyObject) -> Result<String, RubyDebugInfo> {
  let result = &item;
  if Class::from_existing("String").case_equals(result) {
    return Ok(RString::from(result.value()).to_string())
  }

  if Class::from_existing("Pathname").case_equals(result) {
    return Ok(result.instance_variable_get("@path").
      try_convert_to::<RString>().
      unwrap_or(RString::new("")).
      to_string())
  }

  if result.respond_to("to_path") {
    return Ok(RString::from(result.send("to_path", None).value()).to_string())
  }

  Ok(RString::from(result.send("to_s", None).value()).to_string())
}
<commit_msg>cleanup unused use<commit_after>use ruru::{RString, Object, Class, AnyObject};
extern crate ruby_sys;
use debug::RubyDebugInfo;

pub trait TryFrom<T>: Sized {
  type Error;

  fn try_from(value: T) -> Result<Self, Self::Error>;
}

#[inline]
pub fn is_same_path(a: &str, b: &str) -> bool {
  if cfg!(windows) {
    a.to_uppercase() == b.to_uppercase()
  } else {
    a == b
  }
}

pub fn anyobject_to_string(item: AnyObject) -> Result<String, RubyDebugInfo> {
  let result = &item;
  if Class::from_existing("String").case_equals(result) {
    return Ok(RString::from(result.value()).to_string())
  }

  if Class::from_existing("Pathname").case_equals(result) {
    return Ok(result.instance_variable_get("@path").
      try_convert_to::<RString>().
      unwrap_or(RString::new("")).
      to_string())
  }

  if result.respond_to("to_path") {
    return Ok(RString::from(result.send("to_path", None).value()).to_string())
  }

  Ok(RString::from(result.send("to_s", None).value()).to_string())
}
<|endoftext|>


<commit_before>//! Functionality for sending requests to Slack.
use async_trait::async_trait;

use std::{borrow::Borrow, error};

/// Functionality for sending authenticated and unauthenticated requests to Slack via HTTP.
///
/// If you do not have a custom client to integrate with and just want to send requests, use
/// the [`default_client()`] function to get a simple request sender.
#[async_trait]
pub trait SlackWebRequestSender {
    type Error: error::Error;

    /// Make an API call to Slack. Takes a map of parameters that get appended to the request as query
    /// params.
    async fn send<I, K, V, S>(&self, method: S, params: I) -> Result<String, Self::Error>
    where
        I: IntoIterator + Send,
        K: AsRef<str> + Send,
        V: AsRef<str> + Send,
        I::Item: Borrow<(K, V)>,
        S: AsRef<str> + Send;
}

#[cfg(feature = "reqwest")]
mod reqwest_support {
    pub use self::reqwest::Error;
    use async_trait::async_trait;
    use reqwest_ as reqwest;
    use std::borrow::Borrow;

    use super::SlackWebRequestSender;

    #[async_trait]
    impl SlackWebRequestSender for reqwest::Client {
        type Error = reqwest::Error;

        async fn send<I, K, V, S>(&self, method_url: S, params: I) -> Result<String, Self::Error>
        where
            I: IntoIterator + Send,
            K: AsRef<str> + Send,
            V: AsRef<str> + Send,
            I::Item: Borrow<(K, V)>,
            S: AsRef<str> + Send,
        {
            let mut url = reqwest::Url::parse(method_url.as_ref()).expect("Unable to parse url");

            url.query_pairs_mut().extend_pairs(params);

            Ok(self.get(url).send().await?.text().await?)
        }
    }

    /// Provides a default `reqwest` client to give to the API functions to send requests.
    ///
    /// # Examples
    ///
    /// ```
    /// # let token = "some_token";
    /// let client = slack_api::requests::default_client().unwrap();
    /// let response = slack_api::channels::list(&client, &token, &Default::default());
    /// ```
    pub fn default_client() -> Result<reqwest::Client, reqwest::Error> {
        Ok(reqwest::Client::new())
    }
}

#[cfg(feature = "reqwest")]
pub use self::reqwest_support::*;
<commit_msg>Remove Send bound where possible<commit_after>//! Functionality for sending requests to Slack.
use async_trait::async_trait;

use std::{borrow::Borrow, error};

/// Functionality for sending authenticated and unauthenticated requests to Slack via HTTP.
///
/// If you do not have a custom client to integrate with and just want to send requests, use
/// the [`default_client()`] function to get a simple request sender.
#[async_trait]
pub trait SlackWebRequestSender {
    type Error: error::Error;

    /// Make an API call to Slack. Takes a map of parameters that get appended to the request as query
    /// params.
    async fn send<I, K, V, S>(&self, method: S, params: I) -> Result<String, Self::Error>
    where
        I: IntoIterator + Send,
        K: AsRef<str>,
        V: AsRef<str>,
        I::Item: Borrow<(K, V)>,
        S: AsRef<str> + Send;
}

#[cfg(feature = "reqwest")]
mod reqwest_support {
    pub use self::reqwest::Error;
    use async_trait::async_trait;
    use reqwest_ as reqwest;
    use std::borrow::Borrow;

    use super::SlackWebRequestSender;

    #[async_trait]
    impl SlackWebRequestSender for reqwest::Client {
        type Error = reqwest::Error;

        async fn send<I, K, V, S>(&self, method_url: S, params: I) -> Result<String, Self::Error>
        where
            I: IntoIterator + Send,
            K: AsRef<str>,
            V: AsRef<str>,
            I::Item: Borrow<(K, V)>,
            S: AsRef<str> + Send,
        {
            let mut url = reqwest::Url::parse(method_url.as_ref()).expect("Unable to parse url");

            url.query_pairs_mut().extend_pairs(params);

            Ok(self.get(url).send().await?.text().await?)
        }
    }

    /// Provides a default `reqwest` client to give to the API functions to send requests.
    ///
    /// # Examples
    ///
    /// ```
    /// # let token = "some_token";
    /// let client = slack_api::requests::default_client().unwrap();
    /// let response = slack_api::channels::list(&client, &token, &Default::default());
    /// ```
    pub fn default_client() -> Result<reqwest::Client, reqwest::Error> {
        Ok(reqwest::Client::new())
    }
}

#[cfg(feature = "reqwest")]
pub use self::reqwest_support::*;
<|endoftext|>


<commit_before>use lib::*;

/// A point in time that is used as a reference for measuring a rate
/// limit. On the clock, it has meaning only relative to some other point in time.
///
/// When using `no_std`, users of this crate are expected to provide
/// an impl of `RelativeInstant` that corresponds to their system's time source.
pub trait RelativeInstant:
    Sized
    + Sub<Duration, Output = Self>
    + Add<Duration, Output = Self>
    + PartialEq
    + Eq
    + Ord
    + Copy
    + Clone
    + Send
    + Sync
    + Debug
{
    /// Returns the amount of time elapsed from an earlier point in time.
    fn duration_since(&self, earlier: Self) -> Duration;
}

/// A point in time as given by a source of time. It is assumed to be
/// monotonically moving forward.
pub trait AbsoluteInstant: RelativeInstant {
    /// Returns the current moment in time, as given by the time
    /// source.
    fn now() -> Self;
}

#[cfg(feature = "std")]
mod std {
    use std::time::{Duration, Instant};

    impl super::RelativeInstant for Instant {
        fn duration_since(&self, earlier: Self) -> Duration {
            self.duration_since(earlier)
        }
    }

    impl super::AbsoluteInstant for Instant {
        #[inline]
        fn now() -> Self {
            Instant::now()
        }
    }

    use std::time::SystemTime;

    impl super::RelativeInstant for SystemTime {
        /// Returns the difference in times between the two
        /// SystemTimes. Due to the fallible nature of SystemTimes,
        /// returns the zero duration if a negative duration would
        /// result (e.g. due to system clock adjustments).
        fn duration_since(&self, earlier: Self) -> Duration {
            self.duration_since(earlier).unwrap_or(Duration::new(0, 0))
        }
    }

    impl super::AbsoluteInstant for SystemTime {
        #[inline]
        fn now() -> Self {
            SystemTime::now()
        }
    }
}

impl RelativeInstant for Duration {
    fn duration_since(&self, earlier: Self) -> Duration {
        *self - earlier
    }
}
<commit_msg>Fix clippy<commit_after>use lib::*;

/// A point in time that is used as a reference for measuring a rate
/// limit. On the clock, it has meaning only relative to some other point in time.
///
/// When using `no_std`, users of this crate are expected to provide
/// an impl of `RelativeInstant` that corresponds to their system's time source.
pub trait RelativeInstant:
    Sized
    + Sub<Duration, Output = Self>
    + Add<Duration, Output = Self>
    + PartialEq
    + Eq
    + Ord
    + Copy
    + Clone
    + Send
    + Sync
    + Debug
{
    /// Returns the amount of time elapsed from an earlier point in time.
    fn duration_since(&self, earlier: Self) -> Duration;
}

/// A point in time as given by a source of time. It is assumed to be
/// monotonically moving forward.
pub trait AbsoluteInstant: RelativeInstant {
    /// Returns the current moment in time, as given by the time
    /// source.
    fn now() -> Self;
}

#[cfg(feature = "std")]
mod std {
    use std::time::{Duration, Instant};

    impl super::RelativeInstant for Instant {
        fn duration_since(&self, earlier: Self) -> Duration {
            self.duration_since(earlier)
        }
    }

    impl super::AbsoluteInstant for Instant {
        #[inline]
        fn now() -> Self {
            Instant::now()
        }
    }

    use std::time::SystemTime;

    impl super::RelativeInstant for SystemTime {
        /// Returns the difference in times between the two
        /// SystemTimes. Due to the fallible nature of SystemTimes,
        /// returns the zero duration if a negative duration would
        /// result (e.g. due to system clock adjustments).
        fn duration_since(&self, earlier: Self) -> Duration {
            self.duration_since(earlier)
                .unwrap_or_else(|_| Duration::new(0, 0))
        }
    }

    impl super::AbsoluteInstant for SystemTime {
        #[inline]
        fn now() -> Self {
            SystemTime::now()
        }
    }
}

impl RelativeInstant for Duration {
    fn duration_since(&self, earlier: Self) -> Duration {
        *self - earlier
    }
}
<|endoftext|>


<commit_before>use serialize::json::{self, Json, DecodeResult};
use serialize::{Decodable, Decoder};

pub struct Message {
    pub event_type: Option<String>,// TODO Enum
    pub user: Option<String>,
    pub text: Option<String>,
    pub ts: Option<String>,
    pub channel: Option<String>
}

pub fn new_message_from_str(payload: &str) -> DecodeResult<Message> {
    json::decode::<Message>(payload)
}

impl Decodable for Message {
    fn decode<D: Decoder>(decoder: &mut D) -> Result<Message, D::Error> {
        decoder.read_struct("root", 0, |decoder| {
            Ok(Message {
                event_type: try!(decoder.read_struct_field("type", 0, |decoder| Decodable::decode(decoder))),
                user: try!(decoder.read_struct_field("user", 0, |decoder| Decodable::decode(decoder))),
                text: try!(decoder.read_struct_field("text", 0, |decoder| Decodable::decode(decoder))),
                ts: try!(decoder.read_struct_field("ts", 0, |decoder| Decodable::decode(decoder))),
                channel: try!(decoder.read_struct_field("channel", 0, |decoder| Decodable::decode(decoder))),
            })
        })
    }
}

#[cfg(test)]
mod test {
    use super::new_message_from_str;

    #[test]
    fn test_decode_from_json() {
        let json = "{
            \"type\": \"message\",
            \"user\": \"Timon\",
            \"text\": \"Bananas!\",
            \"ts\": \"today\",
            \"channel\": \"banter\"
        }";
        let message = new_message_from_str(json).unwrap();
        assert_eq!(message.event_type.unwrap(), "message");
        assert_eq!(message.user.unwrap(), "Timon");
        assert_eq!(message.text.unwrap(), "Bananas!");
        assert_eq!(message.ts.unwrap(), "today");
        assert_eq!(message.channel.unwrap(), "banter");
    }
}

<commit_msg>Type out all message types into enum<commit_after>use serialize::json::{self, Json, DecodeResult};
use serialize::{Decodable, Decoder};

// All EventTypes typed out into enum
// Not used currently
enum EventType {
    Hello,
    Message,
    UserTyping,
    ChannelMarked,
    ChannelCreated,
    ChannelJoined,
    ChannelLeft,
    ChannelDeleted,
    ChannelRename,
    ChannelArchive,
    ChannelUnarchive,
    ChannelHistoryChanged,
    ImCreated,
    ImOpen,
    ImClose,
    ImMarked,
    ImHistoryChanged,
    GroupJoined,
    GroupLeft,
    GroupOpen,
    GroupClose,
    GroupArchive,
    GroupUnarchive,
    GroupRename,
    GroupMarked,
    GroupHistoryChanged,
    FileCreated,
    FileShared,
    FileUnshared,
    FilePublic,
    FilePrivate,
    FileChange,
    FileDeleted,
    FileCommentAdded,
    FileCommentEdited,
    FileCommentDeleted,
    PinAdded,
    PinRemoved,
    PresenceChange,
    ManualPresenceChange,
    PrefChange,
    UserChange,
    TeamJoin,
    StarAdded,
    StarRemoved,
    EmojiChanged,
    CommandsChanged,
    TeamPlanChange,
    TeamPrefChange,
    TeamRename,
    TeamDomainChange,
    EmailDomainChange,
    BotAdded,
    BotChanged,
    AccountsChanged,
    TeamMigrationStarted
}

pub struct Message {
    pub event_type: Option<String>,// TODO Enum
    pub user: Option<String>,
    pub text: Option<String>,
    pub ts: Option<String>,
    pub channel: Option<String>
}

pub fn new_message_from_str(payload: &str) -> DecodeResult<Message> {
    json::decode::<Message>(payload)
}

impl Decodable for Message {
    fn decode<D: Decoder>(decoder: &mut D) -> Result<Message, D::Error> {
        decoder.read_struct("root", 0, |decoder| {
            Ok(Message {
                event_type: try!(decoder.read_struct_field("type", 0, |decoder| Decodable::decode(decoder))),
                user: try!(decoder.read_struct_field("user", 0, |decoder| Decodable::decode(decoder))),
                text: try!(decoder.read_struct_field("text", 0, |decoder| Decodable::decode(decoder))),
                ts: try!(decoder.read_struct_field("ts", 0, |decoder| Decodable::decode(decoder))),
                channel: try!(decoder.read_struct_field("channel", 0, |decoder| Decodable::decode(decoder))),
            })
        })
    }
}

#[cfg(test)]
mod test {
    use super::new_message_from_str;

    #[test]
    fn test_decode_from_json() {
        let json = "{
            \"type\": \"message\",
            \"user\": \"Timon\",
            \"text\": \"Bananas!\",
            \"ts\": \"today\",
            \"channel\": \"banter\"
        }";
        let message = new_message_from_str(json).unwrap();
        assert_eq!(message.event_type.unwrap(), "message");
        assert_eq!(message.user.unwrap(), "Timon");
        assert_eq!(message.text.unwrap(), "Bananas!");
        assert_eq!(message.ts.unwrap(), "today");
        assert_eq!(message.channel.unwrap(), "banter");
    }
}

<|endoftext|>


<commit_before>use std::any::{Any, TypeId};
use std::cell::RefCell;
use std::collections::HashMap;
use std::marker::PhantomData;
use std::mem::transmute;
use std::rc::Rc;

/// Trait for setting up mocks
///
/// The trait is implemented for all functions, so its methods can be called on any function.
///
/// Note: methods have any effect only if called on functions [annotated as mockable](https://docs.rs/mocktopus_macros).
pub trait Mockable<T, O> {

    /// Core function for setting up mocks
    ///
    /// The passed closure is called whenever the mocked function is called. Depending on variant of returned
    /// [MockResult](enum.MockResult.html) the mocked function continues to run or returns immediately.
    /// In case of continuation the function arguments can be modified or replaced.
    ///
    /// The mock closure is saved in a
    /// [thread local static storage](https://doc.rust-lang.org/std/macro.thread_local.html),
    /// so it has effect only in thread, where it was set.
    /// Each Rust test is executed in separate thread, so mocks do not leak between them.
    /// # Safety
    /// It is up to the user to make sure, that the closure is valid long enough to serve all calls to mocked function.
    /// If the mock closure uses any non-static values or references, it will silently become invalid at some point of
    /// host thread lifetime.
    ///
    /// ```
    /// #[mockable]
    /// fn get_string(context: &Context) -> &String {
    ///     context.get_string()
    /// }
    ///
    /// #[test]
    /// fn get_string_test() {
    ///     let mocked = "mocked".to_string();
    ///     unsafe {
    ///         get_string.mock_raw(|_| MockResult::Return(&mocked));
    ///     }
    ///
    ///     assert_eq!("mocked", get_string(&Context::default()));
    /// }
    /// ```
    unsafe fn mock_raw<M: FnMut<T, Output=MockResult<T, O>>>(&self, mock: M);

    /// A safe variant of [mock_raw](#tymethod.mock_raw) for static closures
    ///
    /// The safety is guaranteed by forcing passed closure to be static.
    /// This eliminates the problem of using non-static values, which may not live long enough.
    ///
    /// ```
    /// #[mockable]
    /// fn get_string() -> String {
    ///     "not mocked".to_string()
    /// }
    ///
    /// #[test]
    /// fn get_string_test() {
    ///     get_string.mock_safe(|| MockResult::Return("mocked".to_string()));
    ///
    ///     assert_eq!("mocked", get_string());
    /// }
    /// ```
    fn mock_safe<M: FnMut<T, Output=MockResult<T, O>> + 'static>(&self, mock: M);

    /// Stop mocking this function.
    ///
    /// All future invocations will be forwarded to the real implementation.
    fn clear_mock(&self);

    #[doc(hidden)]
    /// Called before every execution of a mockable function. Checks if mock is set and if it is, calls it.
    fn call_mock(&self, input: T) -> MockResult<T, O>;

    #[doc(hidden)]
    /// Returns a unique ID of the function, which is used to set and get its mock.
    unsafe fn get_mock_id(&self) -> TypeId;
}

/// Controls mocked function behavior when returned from [mock closure](trait.Mockable.html)
pub enum MockResult<T, O> {
    /// Function runs normally as if it was called with given arguments.
    /// The arguments are passed inside enum variant as a tuple.
    Continue(T),

    /// Function returns immediately with a given value. The returned value is passed inside enum variant.
    Return(O),
}

thread_local!{
    static MOCK_STORE: RefCell<HashMap<TypeId, Rc<RefCell<Box<FnMut<(), Output=()>>>>>> = RefCell::new(HashMap::new())
}

/// Clear all mocks in the ThreadLocal; only necessary if tests share threads
pub fn clear_mocks() {
    MOCK_STORE.with(|mock_ref_cell| {
        mock_ref_cell.borrow_mut().clear();
    });
}

struct ScopedMock<'a> {
    phantom: PhantomData<&'a ()>,
    id: TypeId,
}

impl<'a> ScopedMock<'a> {
    unsafe fn new<T, O, M: Mockable<T, O> + 'a, F: FnMut<T, Output=MockResult<T, O>>>(
        mockable: &M,
        mock: F,
    ) -> Self {
        mockable.mock_raw(mock);
        ScopedMock {
            phantom: PhantomData,
            id: mockable.get_mock_id(),
        }
    }
}

impl<'a> Drop for ScopedMock<'a> {
    fn drop(&mut self) {
        clear_id(self.id);
    }
}

fn clear_id(id: TypeId) {
    MOCK_STORE.with(|mock_ref_cell| {
        mock_ref_cell.borrow_mut().remove(&id);
    });
}

impl<T, O, F: FnOnce<T, Output=O>> Mockable<T, O> for F {
    unsafe fn mock_raw<M: FnMut<T, Output=MockResult<T, O>>>(&self, mock: M) {
        let id = self.get_mock_id();
        MOCK_STORE.with(|mock_ref_cell| {
            let real = Rc::new(RefCell::new(Box::new(mock) as Box<FnMut<_, Output=_>>));
            let stored = transmute(real);
            mock_ref_cell.borrow_mut()
                .insert(id, stored);
        })
    }

    fn mock_safe<M: FnMut<T, Output=MockResult<T, O>> + 'static>(&self, mock: M) {
        unsafe {
            self.mock_raw(mock)
        }
    }

    fn clear_mock(&self) {
        let id = unsafe { self.get_mock_id() };
        clear_id(id);
    }

    fn call_mock(&self, input: T) -> MockResult<T, O> {
        unsafe {
            let id = self.get_mock_id();
            let rc_opt = MOCK_STORE.with(|mock_ref_cell|
                mock_ref_cell.borrow()
                    .get(&id)
                    .cloned()
            );
            let stored_opt = rc_opt.as_ref()
                .and_then(|rc| rc.try_borrow_mut().ok());
            match stored_opt {
                Some(mut stored) => {
                    let real: &mut Box<FnMut<_, Output=_>> = transmute(&mut*stored);
                    real.call_mut(input)
                }
                None => MockResult::Continue(input),
            }
        }
    }

    unsafe fn get_mock_id(&self) -> TypeId {
        (||()).type_id()
    }
}

#[derive(Default)]
pub struct MockContext<'a> {
    planned_mocks: HashMap<TypeId, Box<FnOnce() -> ScopedMock<'a> + 'a>>,
}

impl<'a> MockContext<'a> {
    pub fn new() -> Self {
        Self::default()
    }

    pub fn mock_safe<
        Args,
        Output,
        M: Mockable<Args, Output> + 'a,
        F: FnMut<Args, Output = MockResult<Args, Output>> + 'a,
    >(
        mut self,
        mock: M,
        body: F,
    ) -> Self {
        self.planned_mocks.insert(
            unsafe { mock.get_mock_id() },
            Box::new(move || unsafe { ScopedMock::new(&mock, body) }),
        );
        self
    }

    pub fn run<T, F: FnOnce() -> T>(self, f: F) -> T {
        let _scoped_mocks = self
            .planned_mocks
            .into_iter()
            .map(|entry| entry.1())
            .collect::<Vec<_>>();
        f()
    }
}
<commit_msg>Add documentation<commit_after>use std::any::{Any, TypeId};
use std::cell::RefCell;
use std::collections::HashMap;
use std::marker::PhantomData;
use std::mem::transmute;
use std::rc::Rc;

/// Trait for setting up mocks
///
/// The trait is implemented for all functions, so its methods can be called on any function.
///
/// Note: methods have any effect only if called on functions [annotated as mockable](https://docs.rs/mocktopus_macros).
pub trait Mockable<T, O> {

    /// Core function for setting up mocks
    ///
    /// The passed closure is called whenever the mocked function is called. Depending on variant of returned
    /// [MockResult](enum.MockResult.html) the mocked function continues to run or returns immediately.
    /// In case of continuation the function arguments can be modified or replaced.
    ///
    /// The mock closure is saved in a
    /// [thread local static storage](https://doc.rust-lang.org/std/macro.thread_local.html),
    /// so it has effect only in thread, where it was set.
    /// Each Rust test is executed in separate thread, so mocks do not leak between them.
    /// # Safety
    /// It is up to the user to make sure, that the closure is valid long enough to serve all calls to mocked function.
    /// If the mock closure uses any non-static values or references, it will silently become invalid at some point of
    /// host thread lifetime.
    ///
    /// ```
    /// #[mockable]
    /// fn get_string(context: &Context) -> &String {
    ///     context.get_string()
    /// }
    ///
    /// #[test]
    /// fn get_string_test() {
    ///     let mocked = "mocked".to_string();
    ///     unsafe {
    ///         get_string.mock_raw(|_| MockResult::Return(&mocked));
    ///     }
    ///
    ///     assert_eq!("mocked", get_string(&Context::default()));
    /// }
    /// ```
    unsafe fn mock_raw<M: FnMut<T, Output=MockResult<T, O>>>(&self, mock: M);

    /// A safe variant of [mock_raw](#tymethod.mock_raw) for static closures
    ///
    /// The safety is guaranteed by forcing passed closure to be static.
    /// This eliminates the problem of using non-static values, which may not live long enough.
    ///
    /// ```
    /// #[mockable]
    /// fn get_string() -> String {
    ///     "not mocked".to_string()
    /// }
    ///
    /// #[test]
    /// fn get_string_test() {
    ///     get_string.mock_safe(|| MockResult::Return("mocked".to_string()));
    ///
    ///     assert_eq!("mocked", get_string());
    /// }
    /// ```
    fn mock_safe<M: FnMut<T, Output=MockResult<T, O>> + 'static>(&self, mock: M);

    /// Stop mocking this function.
    ///
    /// All future invocations will be forwarded to the real implementation.
    fn clear_mock(&self);

    #[doc(hidden)]
    /// Called before every execution of a mockable function. Checks if mock is set and if it is, calls it.
    fn call_mock(&self, input: T) -> MockResult<T, O>;

    #[doc(hidden)]
    /// Returns a unique ID of the function, which is used to set and get its mock.
    unsafe fn get_mock_id(&self) -> TypeId;
}

/// Controls mocked function behavior when returned from [mock closure](trait.Mockable.html)
pub enum MockResult<T, O> {
    /// Function runs normally as if it was called with given arguments.
    /// The arguments are passed inside enum variant as a tuple.
    Continue(T),

    /// Function returns immediately with a given value. The returned value is passed inside enum variant.
    Return(O),
}

thread_local!{
    static MOCK_STORE: RefCell<HashMap<TypeId, Rc<RefCell<Box<FnMut<(), Output=()>>>>>> = RefCell::new(HashMap::new())
}

/// Clear all mocks in the ThreadLocal; only necessary if tests share threads
pub fn clear_mocks() {
    MOCK_STORE.with(|mock_ref_cell| {
        mock_ref_cell.borrow_mut().clear();
    });
}

struct ScopedMock<'a> {
    phantom: PhantomData<&'a ()>,
    id: TypeId,
}

impl<'a> ScopedMock<'a> {
    unsafe fn new<T, O, M: Mockable<T, O> + 'a, F: FnMut<T, Output=MockResult<T, O>>>(
        mockable: &M,
        mock: F,
    ) -> Self {
        mockable.mock_raw(mock);
        ScopedMock {
            phantom: PhantomData,
            id: mockable.get_mock_id(),
        }
    }
}

impl<'a> Drop for ScopedMock<'a> {
    fn drop(&mut self) {
        clear_id(self.id);
    }
}

fn clear_id(id: TypeId) {
    MOCK_STORE.with(|mock_ref_cell| {
        mock_ref_cell.borrow_mut().remove(&id);
    });
}

impl<T, O, F: FnOnce<T, Output=O>> Mockable<T, O> for F {
    unsafe fn mock_raw<M: FnMut<T, Output=MockResult<T, O>>>(&self, mock: M) {
        let id = self.get_mock_id();
        MOCK_STORE.with(|mock_ref_cell| {
            let real = Rc::new(RefCell::new(Box::new(mock) as Box<FnMut<_, Output=_>>));
            let stored = transmute(real);
            mock_ref_cell.borrow_mut()
                .insert(id, stored);
        })
    }

    fn mock_safe<M: FnMut<T, Output=MockResult<T, O>> + 'static>(&self, mock: M) {
        unsafe {
            self.mock_raw(mock)
        }
    }

    fn clear_mock(&self) {
        let id = unsafe { self.get_mock_id() };
        clear_id(id);
    }

    fn call_mock(&self, input: T) -> MockResult<T, O> {
        unsafe {
            let id = self.get_mock_id();
            let rc_opt = MOCK_STORE.with(|mock_ref_cell|
                mock_ref_cell.borrow()
                    .get(&id)
                    .cloned()
            );
            let stored_opt = rc_opt.as_ref()
                .and_then(|rc| rc.try_borrow_mut().ok());
            match stored_opt {
                Some(mut stored) => {
                    let real: &mut Box<FnMut<_, Output=_>> = transmute(&mut*stored);
                    real.call_mut(input)
                }
                None => MockResult::Continue(input),
            }
        }
    }

    unsafe fn get_mock_id(&self) -> TypeId {
        (||()).type_id()
    }
}

/// `MockContext` allows for safe capture of local variables.
///
/// It does this by forcing only mocking the actual function while in the body
/// of [`run`].
///
/// # Examples
///
/// Simple function replacement:
///
/// ```
/// use mocktopus::macros::mockable;
/// use mocktopus::mocking::{MockContext, MockResult};
///
/// #[mockable]
/// fn f() -> i32 {
///     0
/// }
///
/// MockContext::new()
///     .mock_safe(f, || MockResult::Return(1))
///     .run(|| {
///         assert_eq!(f(), 1);
///     });
/// ```
///
/// Using local variables:
///
/// ```
/// use mocktopus::macros::mockable;
/// use mocktopus::mocking::{MockContext, MockResult};
///
/// #[mockable]
/// fn as_str(s: &String) -> &str {
///     &s
/// }
///
/// let mut count = 0;
/// MockContext::new()
///     .mock_safe(as_str, |s| { count += 1; MockResult::Return(&s) })
///     .run(|| {
///         assert_eq!(as_str(&"abc".to_string()), "abc");
///     });
/// assert_eq!(count, 1);
/// ```
#[derive(Default)]
pub struct MockContext<'a> {
    planned_mocks: HashMap<TypeId, Box<FnOnce() -> ScopedMock<'a> + 'a>>,
}

impl<'a> MockContext<'a> {
    /// Create a new MockContext object.
    pub fn new() -> Self {
        Self::default()
    }

    /// Set up a function to be mocked.
    ///
    /// This function doesn't actually mock the function.  It registers it as a
    /// function that will be mocked when [`run`](#method.run) is called.
    pub fn mock_safe<
        Args,
        Output,
        M: Mockable<Args, Output> + 'a,
        F: FnMut<Args, Output = MockResult<Args, Output>> + 'a,
    >(
        mut self,
        mock: M,
        body: F,
    ) -> Self {
        self.planned_mocks.insert(
            unsafe { mock.get_mock_id() },
            Box::new(move || unsafe { ScopedMock::new(&mock, body) }),
        );
        self
    }

    /// Run the function while mocking all the functions.
    ///
    /// This function will mock all functions registered for mocking, run the
    /// function passed in, then deregister those functions.  It does this in a
    /// panic-safe way.  Note that functions are only mocked in the current
    /// thread and other threads may invoke the real implementations.
    ///
    /// Register a function for mocking with [`mock_safe`](#method.mock_safe).
    pub fn run<T, F: FnOnce() -> T>(self, f: F) -> T {
        let _scoped_mocks = self
            .planned_mocks
            .into_iter()
            .map(|entry| entry.1())
            .collect::<Vec<_>>();
        f()
    }
}
<|endoftext|>


<commit_before>use ansi_term::{ANSIString, Colour, Style};
use config::Config;

/// Merges in the default values for the program
pub fn merge_defaults(c: &mut Config) {
    c.set_default("global.modules",
                     vec!["exit_code", "directory", "git", "prompt"])
        .unwrap();
    c.set_default("global.foreground", "bright_white").unwrap();
    c.set_default("global.background", "blue").unwrap();
    c.set_default("global.style", "default").unwrap();
    c.set_default("global.separator", "").unwrap();
    c.set_default("global.padding_left", " ").unwrap();
    c.set_default("global.padding_right", " ").unwrap();

    c.set_default("modules.directory.max_depth", 4).unwrap();

    c.set_default("modules.exit_code.bg_success", "green").unwrap();
    c.set_default("modules.exit_code.bg_error", "red").unwrap();

    // c.set_default("modules.git.symbol_clean", "").unwrap();
    c.set_default("modules.git.symbol_insertion", "+").unwrap();
    c.set_default("modules.git.symbol_deletion", "-").unwrap();
    c.set_default("modules.git.symbol_push", "⇡").unwrap();
    // c.set_default("modules.git.symbol_pull", "⇣").unwrap();
    c.set_default("modules.git.show_diff_stats", true).unwrap();
    c.set_default("modules.git.show_unpushed", true).unwrap();

    c.set_default("modules.prompt.output", "$").unwrap();
    c.set_default("modules.prompt.bg_success", "green").unwrap();
    c.set_default("modules.prompt.bg_error", "red").unwrap();
}

/// Generic formatting method
pub fn format_module<'a>(c: &mut Config,
                         name: &'a str,
                         output: Option<String>,
                         last_successful: Option<&str>)
                         -> (Option<&'a str>, Option<ANSIString<'static>>) {
    // Formatting was not successful if there was nothing to format
    if c.get_str(&format!("modules.{}.output", name)).is_none() && output.is_none() {
        return (None, None);
    }

    // Get config options
    let fg = c.get_str(&format!("modules.{}.foreground", name))
        .unwrap_or_else(|| c.get_str("global.foreground").unwrap_or_default());
    let fg = string_to_colour(fg);

    let bg = c.get_str(&format!("modules.{}.background", name))
        .unwrap_or_else(|| c.get_str("global.background").unwrap_or_default());
    let bg = string_to_colour(bg);

    let padding_left = c.get_str(&format!("modules.{}.padding_left", name))
        .unwrap_or_else(|| c.get_str("global.padding_left").unwrap_or_default());
    let padding_right = c.get_str(&format!("modules.{}.padding_right", name))
        .unwrap_or_else(|| c.get_str("global.padding_right").unwrap_or_default());
    let separator = c.get_str(&format!("modules.{}.separator", name))
        .unwrap_or_else(|| c.get_str("global.separator").unwrap_or_default());

    let main_style = c.get_str(&format!("modules.{}.style", name))
        .unwrap_or_else(|| c.get_str("global.style").unwrap_or_default());
    let main_style = string_to_style(main_style).on(bg).fg(fg);

    // Override the output if there is "output" in this module's config
    let output = if let Some(s) = c.get_str(&format!("modules.{}.output", name)) {
        s
    } else {
        output.unwrap()
    };

    // Format the main content
    let mut content = format!("\\[{}\\]{}{}{}\\[{}\\]",
                              main_style.prefix(),
                              padding_left,
                              output,
                              padding_right,
                              main_style.suffix());

    // Format the separator
    let main_style = main_style.on(fg).fg(bg);
    if let Some(name) = last_successful {
        // There is a visible module that comes after this one
        let next_bg = c.get_str(&format!("modules.{}.background", name))
            .unwrap_or_else(|| c.get_str("global.background").unwrap_or_default());
        let next_bg = string_to_colour(next_bg);

        content = format!("{}\\[{}\\]{}\\[{}\\]",
                          content,
                          main_style.on(next_bg).prefix(),
                          separator,
                          main_style.on(next_bg).suffix());
    } else {
        // This is the final module
        content = format!("{}\\[{}\\]{}\\[{}\\]",
                          content,
                          bg.prefix(),
                          separator,
                          bg.suffix());
    }

    (Some(name), Some(ANSIString::from(content)))
}

// Converts a string (from the config file) to a Colour
// See: https://upload.wikimedia.org/wikipedia/commons/1/15/Xterm_256color_chart.svg
fn string_to_colour(s: String) -> Colour {
    if let Ok(i) = s.parse::<u8>() {
        Colour::Fixed(i)
    } else {
        let s = s.to_lowercase();
        match s.as_ref() {
            "black" => Colour::Fixed(0),
            "bright_black" => Colour::Fixed(8),
            "red" => Colour::Fixed(1),
            "bright_red" => Colour::Fixed(9),
            "green" => Colour::Fixed(2),
            "bright_green" => Colour::Fixed(10),
            "yellow" => Colour::Fixed(3),
            "bright_yellow" => Colour::Fixed(11),
            "blue" => Colour::Fixed(4),
            "bright_blue" => Colour::Fixed(12),
            "purple" => Colour::Fixed(5),
            "bright_purple" => Colour::Fixed(13),
            "cyan" => Colour::Fixed(6),
            "bright_cyan" => Colour::Fixed(14),
            "white" => Colour::Fixed(7),
            "bright_white" => Colour::Fixed(15),
            _ => panic!("Invalid color option: {} in config file!", s),
        }
    }
}

fn string_to_style(s: String) -> Style {
    let s = s.to_lowercase();
    match s.as_ref() {
        "default" | "" | "normal" => Style::new(),
        "bold" => Style::new().bold(),
        "dimmed" => Style::new().dimmed(),
        "italic" => Style::new().italic(),
        "underline" => Style::new().underline(),
        "blink" => Style::new().blink(),
        "reverse" => Style::new().reverse(),
        "hidden" => Style::new().hidden(),
        "strikethrough" => Style::new().strikethrough(),
        _ => panic!("Unknown style property: {} in config file!", s),
    }
}

pub fn format_module_prompt<'a>(c: &mut Config,
                                last_successful: Option<&'a str>,
                                exit_code: &str)
                                -> (Option<&'a str>, Option<ANSIString<'static>>) {
    let bg = match exit_code.as_ref() {
        "0" => c.get_str("modules.prompt.bg_success").unwrap_or_default(),
        _ => c.get_str("modules.prompt.bg_error").unwrap_or_default(),
    };
    c.set("modules.prompt.background", bg).unwrap();

    let output = c.get_str("modules.prompt.output").unwrap_or_default();

    format_module(c, "prompt", Some(output), last_successful)
}

pub fn format_module_exit_code<'a>(c: &mut Config,
                                   last_successful: Option<&'a str>,
                                   exit_code: &str)
                                   -> (Option<&'a str>, Option<ANSIString<'static>>) {
    let bg = match exit_code.as_ref() {
        "0" => c.get_str("modules.exit_code.bg_success").unwrap_or_default(),
        _ => c.get_str("modules.exit_code.bg_error").unwrap_or_default(),
    };
    c.set("modules.exit_code.background", bg).unwrap();

    format_module(c, "exit_code", Some(exit_code.to_string()), last_successful)
}

pub fn format_module_directory<'a>(c: &mut Config,
                                   last_successful: Option<&'a str>)
                                   -> (Option<&'a str>, Option<ANSIString<'static>>) {
    use std::env;
    use std::path::PathBuf;

    let home = env::var("HOME").unwrap();
    let cwd = env::current_dir().unwrap();

    // Convert "/home/user/directory" to "~/directory"
    let mut shortened_cwd: PathBuf;
    if let Ok(stripped_cwd) = cwd.strip_prefix(&home) {
        shortened_cwd = PathBuf::from("~").join(stripped_cwd);
    } else {
        shortened_cwd = env::current_dir().unwrap();
    }

    let depth = shortened_cwd.components().count();

    // Max number of directories we want to see
    let max_depth = c.get_int("modules.directory.max_depth").unwrap_or_default() as usize;

    if depth > max_depth {
        let comp_iter = shortened_cwd.clone();
        let comp_iter = comp_iter.components();

        shortened_cwd = PathBuf::new();
        for (i, component) in comp_iter.enumerate() {
            if i < (max_depth / 2) || i >= (depth - (max_depth / 2)) {
                shortened_cwd.push(component.as_os_str());
            } else if i == (max_depth / 2) {
                shortened_cwd.push("...");
            }
        }
    }

    format_module(c,
                  "directory",
                  Some(format!("{}", shortened_cwd.display())),
                  last_successful)
}

pub fn format_module_git<'a>(c: &mut Config,
                             last_successful: Option<&'a str>)
                             -> (Option<&'a str>, Option<ANSIString<'static>>) {
    use git2::{Branch, Error, Oid, Reference, Repository};
    use std::env;

    let mut output = String::new();

    if let Ok(repo) = Repository::discover(env::current_dir().unwrap_or_default()) {
        let local = repo.head().unwrap();

        // Output current branch name
        output.push_str(local.shorthand().unwrap());

        let local = Branch::wrap(local);

        // Show local insertions and deletions
        let show_diffs = c.get_bool("modules.git.show_diff_stats").unwrap_or_default();
        if show_diffs {
            let diff_stats = repo.diff_index_to_workdir(None, None).unwrap();
            let diff_stats = diff_stats.stats().unwrap();

            if diff_stats.files_changed() > 0 {
                let symbol_deletion = c.get_str("modules.git.symbol_deletion").unwrap_or_default();
                let symbol_insertion = c.get_str("modules.git.symbol_insertion")
                    .unwrap_or_default();

                output.push_str(&format!(" ({}{}, {}{})",
                                         symbol_deletion,
                                         diff_stats.deletions(),
                                         symbol_insertion,
                                         diff_stats.insertions()));
            }
        }

        // Show unpushed commits
        let show_unpushed = c.get_bool("modules.git.show_unpushed").unwrap_or_default();
        if show_unpushed {
            if let Ok(upstream) = local.upstream() {
                println!("We have an upstream!");
            }
        }
    }

    // let repo: Rc<Result<Repository, Error>> = Rc::from(Repository::discover(env::current_dir()
    //                                                                             .unwrap()));
    // let local: Option<Reference> = match repo.clone().borrow() {
    //     Ok(r) => if let Ok(e) = r.head() { Some(e) } else { None },
    //     _ => None,
    // };

    /*     if let Ok(repo) = repo {
        if let Ok(local) = repo.head() {
            // Current branch name
            output.push_str(local.shorthand().unwrap());

            let show_diffs = c.get_bool("modules.git.show_diff_stats").unwrap_or_default();
            // Insertions and deletions
            if show_diffs {
                if let Ok(diff) = repo.diff_index_to_workdir(None, None) {
                    if let Ok(stats) = diff.stats() {
                        if stats.files_changed() > 0 {
                            let symbol_deletion = c.get_str("modules.git.symbol_deletion")
                                .unwrap_or_default();
                            let symbol_insertion = c.get_str("modules.git.symbol_insertion")
                                .unwrap_or_default();

                            output.push_str(&format!(" ({}{}, {}{})",
                                                     symbol_deletion,
                                                     stats.deletions(),
                                                     symbol_insertion,
                                                     stats.insertions()));
                        }
                    }
                }
            }

            let show_unpushed = c.get_bool("modules.git.show_unpushed").unwrap_or_default();
            // Unpushed commits
            if show_unpushed {
                let local_branch = Branch::wrap(local);
                if let Ok(upstream) = local_branch.upstream() {
                    let upstream_oid = Oid::from_str(upstream.name().unwrap().unwrap()).unwrap();
                    let local_oid = Oid::from_str(local_branch.name().unwrap().unwrap()).unwrap();
                    if let Ok((a, b)) = repo.graph_ahead_behind(local_oid, upstream_oid) {
                        let symbol_push = c.get_str("modules.git.symbol_push").unwrap_or_default();
                        println!("(a, b): ({}, {})", a, b);
                    }
                }
            }
        }
    } */

    if output.is_empty() {
        (None, None)
    } else {
        format_module(c, "git", Some(output), last_successful)
    }
    // let symbol_clean = c.get_str("modules.git.symbol_clean").unwrap_or_default();
    // let symbol_pull = c.get_str("modules.git.symbol_pull").unwrap_or_default();
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_string_to_colour() {
        const CONTENT: &'static str = "hi";

        struct Test<'a> {
            input: &'static str,
            expected: &'a str,
        }

        let tests = [Test {
                         input: "green",
                         expected: &format!("\x1B[38;5;2m{}\x1B[0m", CONTENT),
                     },
                     Test {
                         input: "bright_green",
                         expected: &format!("\x1B[38;5;10m{}\x1B[0m", CONTENT),
                     }];

        for test in &tests {
            let result = string_to_colour(test.input.to_string());
            let result = format!("{}", result.paint(CONTENT));

            assert_eq!(test.expected, result);
        }
    }

    #[test]
    #[should_panic]
    fn test_string_to_colour_invalid_input() {
        struct Test {
            input: &'static str,
        }

        let tests = [Test { input: "green" }, Test { input: "invalid" }];

        for test in &tests {
            string_to_colour(test.input.to_string());
        }
    }
}
<commit_msg>feat: show unpulled/unpushed commits from upstream<commit_after>use ansi_term::{ANSIString, Colour, Style};
use config::Config;

/// Merges in the default values for the program
pub fn merge_defaults(c: &mut Config) {
    c.set_default("global.modules",
                     vec!["exit_code", "directory", "git", "prompt"])
        .unwrap();
    c.set_default("global.foreground", "bright_white").unwrap();
    c.set_default("global.background", "blue").unwrap();
    c.set_default("global.style", "default").unwrap();
    c.set_default("global.separator", "").unwrap();
    c.set_default("global.padding_left", " ").unwrap();
    c.set_default("global.padding_right", " ").unwrap();

    c.set_default("modules.directory.max_depth", 4).unwrap();

    c.set_default("modules.exit_code.bg_success", "green").unwrap();
    c.set_default("modules.exit_code.bg_error", "red").unwrap();

    c.set_default("modules.git.symbol_insertion", "+").unwrap();
    c.set_default("modules.git.symbol_deletion", "-").unwrap();
    c.set_default("modules.git.symbol_push", "⇡").unwrap();
    c.set_default("modules.git.symbol_pull", "⇣").unwrap();
    c.set_default("modules.git.show_changed", true).unwrap();
    c.set_default("modules.git.show_diff_stats", false).unwrap();
    c.set_default("modules.git.show_unpushed", true).unwrap();

    c.set_default("modules.prompt.output", "$").unwrap();
    c.set_default("modules.prompt.bg_success", "green").unwrap();
    c.set_default("modules.prompt.bg_error", "red").unwrap();
}

/// Generic formatting method
pub fn format_module<'a>(c: &mut Config,
                         name: &'a str,
                         output: Option<String>,
                         last_successful: Option<&str>)
                         -> (Option<&'a str>, Option<ANSIString<'static>>) {
    // Formatting was not successful if there was nothing to format
    if c.get_str(&format!("modules.{}.output", name)).is_none() && output.is_none() {
        return (None, None);
    }

    // Get config options
    let fg = c.get_str(&format!("modules.{}.foreground", name))
        .unwrap_or_else(|| c.get_str("global.foreground").unwrap_or_default());
    let fg = string_to_colour(fg);

    let bg = c.get_str(&format!("modules.{}.background", name))
        .unwrap_or_else(|| c.get_str("global.background").unwrap_or_default());
    let bg = string_to_colour(bg);

    let padding_left = c.get_str(&format!("modules.{}.padding_left", name))
        .unwrap_or_else(|| c.get_str("global.padding_left").unwrap_or_default());
    let padding_right = c.get_str(&format!("modules.{}.padding_right", name))
        .unwrap_or_else(|| c.get_str("global.padding_right").unwrap_or_default());
    let separator = c.get_str(&format!("modules.{}.separator", name))
        .unwrap_or_else(|| c.get_str("global.separator").unwrap_or_default());

    let main_style = c.get_str(&format!("modules.{}.style", name))
        .unwrap_or_else(|| c.get_str("global.style").unwrap_or_default());
    let main_style = string_to_style(main_style).on(bg).fg(fg);

    // Override the output if there is "output" in this module's config
    let output = if let Some(s) = c.get_str(&format!("modules.{}.output", name)) {
        s
    } else {
        output.unwrap()
    };

    // Format the main content
    let mut content = format!("\\[{}\\]{}{}{}\\[{}\\]",
                              main_style.prefix(),
                              padding_left,
                              output,
                              padding_right,
                              main_style.suffix());

    // Format the separator
    let main_style = main_style.on(fg).fg(bg);
    if let Some(name) = last_successful {
        // There is a visible module that comes after this one
        let next_bg = c.get_str(&format!("modules.{}.background", name))
            .unwrap_or_else(|| c.get_str("global.background").unwrap_or_default());
        let next_bg = string_to_colour(next_bg);

        content = format!("{}\\[{}\\]{}\\[{}\\]",
                          content,
                          main_style.on(next_bg).prefix(),
                          separator,
                          main_style.on(next_bg).suffix());
    } else {
        // This is the final module
        content = format!("{}\\[{}\\]{}\\[{}\\]",
                          content,
                          bg.prefix(),
                          separator,
                          bg.suffix());
    }

    (Some(name), Some(ANSIString::from(content)))
}

// Converts a string (from the config file) to a Colour
// See: https://upload.wikimedia.org/wikipedia/commons/1/15/Xterm_256color_chart.svg
fn string_to_colour(s: String) -> Colour {
    if let Ok(i) = s.parse::<u8>() {
        Colour::Fixed(i)
    } else {
        let s = s.to_lowercase();
        match s.as_ref() {
            "black" => Colour::Fixed(0),
            "bright_black" => Colour::Fixed(8),
            "red" => Colour::Fixed(1),
            "bright_red" => Colour::Fixed(9),
            "green" => Colour::Fixed(2),
            "bright_green" => Colour::Fixed(10),
            "yellow" => Colour::Fixed(3),
            "bright_yellow" => Colour::Fixed(11),
            "blue" => Colour::Fixed(4),
            "bright_blue" => Colour::Fixed(12),
            "purple" => Colour::Fixed(5),
            "bright_purple" => Colour::Fixed(13),
            "cyan" => Colour::Fixed(6),
            "bright_cyan" => Colour::Fixed(14),
            "white" => Colour::Fixed(7),
            "bright_white" => Colour::Fixed(15),
            _ => panic!("Invalid color option: {} in config file!", s),
        }
    }
}

fn string_to_style(s: String) -> Style {
    let s = s.to_lowercase();
    match s.as_ref() {
        "default" | "" | "normal" => Style::new(),
        "bold" => Style::new().bold(),
        "dimmed" => Style::new().dimmed(),
        "italic" => Style::new().italic(),
        "underline" => Style::new().underline(),
        "blink" => Style::new().blink(),
        "reverse" => Style::new().reverse(),
        "hidden" => Style::new().hidden(),
        "strikethrough" => Style::new().strikethrough(),
        _ => panic!("Unknown style property: {} in config file!", s),
    }
}

pub fn format_module_prompt<'a>(c: &mut Config,
                                last_successful: Option<&'a str>,
                                exit_code: &str)
                                -> (Option<&'a str>, Option<ANSIString<'static>>) {
    let bg = match exit_code.as_ref() {
        "0" => c.get_str("modules.prompt.bg_success").unwrap_or_default(),
        _ => c.get_str("modules.prompt.bg_error").unwrap_or_default(),
    };
    c.set("modules.prompt.background", bg).unwrap();

    let output = c.get_str("modules.prompt.output").unwrap_or_default();

    format_module(c, "prompt", Some(output), last_successful)
}

pub fn format_module_exit_code<'a>(c: &mut Config,
                                   last_successful: Option<&'a str>,
                                   exit_code: &str)
                                   -> (Option<&'a str>, Option<ANSIString<'static>>) {
    let bg = match exit_code.as_ref() {
        "0" => c.get_str("modules.exit_code.bg_success").unwrap_or_default(),
        _ => c.get_str("modules.exit_code.bg_error").unwrap_or_default(),
    };
    c.set("modules.exit_code.background", bg).unwrap();

    format_module(c, "exit_code", Some(exit_code.to_string()), last_successful)
}

pub fn format_module_directory<'a>(c: &mut Config,
                                   last_successful: Option<&'a str>)
                                   -> (Option<&'a str>, Option<ANSIString<'static>>) {
    use std::env;
    use std::path::PathBuf;

    let home = env::var("HOME").unwrap();
    let cwd = env::current_dir().unwrap();

    // Convert "/home/user/directory" to "~/directory"
    let mut shortened_cwd: PathBuf;
    if let Ok(stripped_cwd) = cwd.strip_prefix(&home) {
        shortened_cwd = PathBuf::from("~").join(stripped_cwd);
    } else {
        shortened_cwd = env::current_dir().unwrap();
    }

    let depth = shortened_cwd.components().count();

    // Max number of directories we want to see
    let max_depth = c.get_int("modules.directory.max_depth").unwrap_or_default() as usize;

    if depth > max_depth {
        let comp_iter = shortened_cwd.clone();
        let comp_iter = comp_iter.components();

        shortened_cwd = PathBuf::new();
        for (i, component) in comp_iter.enumerate() {
            if i < (max_depth / 2) || i >= (depth - (max_depth / 2)) {
                shortened_cwd.push(component.as_os_str());
            } else if i == (max_depth / 2) {
                shortened_cwd.push("...");
            }
        }
    }

    format_module(c,
                  "directory",
                  Some(format!("{}", shortened_cwd.display())),
                  last_successful)
}

pub fn format_module_git<'a>(c: &mut Config,
                             last_successful: Option<&'a str>)
                             -> (Option<&'a str>, Option<ANSIString<'static>>) {
    use git2::{Branch, Repository};
    use std::env;

    let mut output = String::new();

    if let Ok(repo) = Repository::discover(env::current_dir().unwrap_or_default()) {
        let local = repo.head().unwrap();

        // Output current branch name
        output.push_str(local.shorthand().unwrap());

        // Show local changes
        let show_diffs = c.get_bool("modules.git.show_diff_stats").unwrap_or_default();
        let show_changed = c.get_bool("modules.git.show_changed").unwrap_or_default();
        if show_changed {
            let diff_stats = repo.diff_index_to_workdir(None, None).unwrap();
            let diff_stats = diff_stats.stats().unwrap();

            if diff_stats.files_changed() > 0 {
                let symbol_insertion = c.get_str("modules.git.symbol_insertion")
                    .unwrap_or_default();

                if show_diffs {
                    // Show actual number of insertions or deletions
                    let symbol_deletion = c.get_str("modules.git.symbol_deletion")
                        .unwrap_or_default();
                    output.push_str(&format!(" ({}{}, {}{})",
                                             symbol_deletion,
                                             diff_stats.deletions(),
                                             symbol_insertion,
                                             diff_stats.insertions()));
                } else {
                    // Do not show insertions nor deletions, just say
                    // something was changed
                    output.push_str(&format!(" {}", symbol_insertion));
                }
            }
        }

        let local = Branch::wrap(local);

        // Show unpushed/unpulled commits
        let show_unpushed = c.get_bool("modules.git.show_unpushed").unwrap_or_default();
        if show_unpushed {
            if let Ok(upstream) = local.upstream() {
                let local_ref = local.get();
                let upstream_ref = upstream.get();

                if let Ok((ahead, behind)) =
                    repo.graph_ahead_behind(local_ref.target().unwrap(),
                                            upstream_ref.target().unwrap()) {

                    if ahead != 0 {
                        let symbol_push = c.get_str("modules.git.symbol_push").unwrap_or_default();
                        output.push_str(&format!(" {}{}", symbol_push, ahead));
                    }

                    if behind != 0 {
                        let symbol_pull = c.get_str("modules.git.symbol_pull").unwrap_or_default();
                        output.push_str(&format!(" {}{}", symbol_pull, behind));
                    }
                }
            }
        }
    }

    if output.is_empty() {
        (None, None)
    } else {
        format_module(c, "git", Some(output), last_successful)
    }
    // let symbol_clean = c.get_str("modules.git.symbol_clean").unwrap_or_default();
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_string_to_colour() {
        const CONTENT: &'static str = "hi";

        struct Test<'a> {
            input: &'static str,
            expected: &'a str,
        }

        let tests = [Test {
                         input: "green",
                         expected: &format!("\x1B[38;5;2m{}\x1B[0m", CONTENT),
                     },
                     Test {
                         input: "bright_green",
                         expected: &format!("\x1B[38;5;10m{}\x1B[0m", CONTENT),
                     }];

        for test in &tests {
            let result = string_to_colour(test.input.to_string());
            let result = format!("{}", result.paint(CONTENT));

            assert_eq!(test.expected, result);
        }
    }

    #[test]
    #[should_panic]
    fn test_string_to_colour_invalid_input() {
        struct Test {
            input: &'static str,
        }

        let tests = [Test { input: "green" }, Test { input: "invalid" }];

        for test in &tests {
            string_to_colour(test.input.to_string());
        }
    }
}
<|endoftext|>


<commit_before>//! Statuses interface

use self::super::Github;
use rep::{Status, StatusReq};
use rustc_serialize::json;
use std::io::Result;

pub struct Statuses<'a> {
  github: &'a Github<'a>,
  owner: &'static str,
  repo: &'static str
}

impl<'a> Statuses<'a> {
  pub fn new(github: &'a Github<'a>, owner: &'static str, repo: &'static str) -> Statuses<'a> {
    Statuses {
      github: github,
      owner: owner,
      repo: repo
    }
  }

  fn path(&self, more: &str) -> String {
    format!("/repos/{}/{}/statuses{}", self.owner, self.repo, more)
  }

  fn create(&self, sha: &'static str, status: &StatusReq) -> Result<Status> {
    let data = json::encode(&status).unwrap();
    let body = try!(
      self.github.post(
        &self.path(&format!("/{}", sha)),
        data.as_bytes()
      )
    );
    Ok(json::decode::<Status>(&body).unwrap())
  }

  pub fn list(&self, sha: &'static str) -> Result<Vec<Status>> {
    let body = try!(
      self.github.get(
        &format!(
          "/repos/{}/{}/commit/{}/statuses", self.owner, self.repo, sha
        )
      )
    );
    Ok(json::decode::<Vec<Status>>(&body).unwrap())
  }

  pub fn combined(&self, sha: &'static str) -> Result<String> {
    let body = try!(
      self.github.get(
        &format!(
          "/repos/{}/{}/commit/{}/status", self.owner, self.repo, sha
        )
      )
    );
    Ok(body)
//    Ok(json::decode::<Vec<Status>>(&body).unwrap())
  }

}
<commit_msg>commit -> commits<commit_after>//! Statuses interface

use self::super::Github;
use rep::{Status, StatusReq};
use rustc_serialize::json;
use std::io::Result;

pub struct Statuses<'a> {
  github: &'a Github<'a>,
  owner: &'static str,
  repo: &'static str
}

impl<'a> Statuses<'a> {
  pub fn new(github: &'a Github<'a>, owner: &'static str, repo: &'static str) -> Statuses<'a> {
    Statuses {
      github: github,
      owner: owner,
      repo: repo
    }
  }

  fn path(&self, more: &str) -> String {
    format!("/repos/{}/{}/statuses{}", self.owner, self.repo, more)
  }

  fn create(&self, sha: &'static str, status: &StatusReq) -> Result<Status> {
    let data = json::encode(&status).unwrap();
    let body = try!(
      self.github.post(
        &self.path(&format!("/{}", sha)),
        data.as_bytes()
      )
    );
    Ok(json::decode::<Status>(&body).unwrap())
  }

  pub fn list(&self, sha: &'static str) -> Result<Vec<Status>> {
    let body = try!(
      self.github.get(
        &format!(
          "/repos/{}/{}/commits/{}/statuses", self.owner, self.repo, sha
        )
      )
    );
    Ok(json::decode::<Vec<Status>>(&body).unwrap())
  }

  pub fn combined(&self, sha: &'static str) -> Result<String> {
    let body = try!(
      self.github.get(
        &format!(
          "/repos/{}/{}/commits/{}/status", self.owner, self.repo, sha
        )
      )
    );
    Ok(body)
//    Ok(json::decode::<Vec<Status>>(&body).unwrap())
  }

}
<|endoftext|>


<commit_before>pub extern crate rosc;

// Re-export rosc items.
//
// Remove `Osc` prefix as items are already namespaced via a module, e.g. `OscMessage` becomes
// `osc::Message`.
#[doc(inline)]
pub use self::rosc::{decoder, encoder, OscBundle as Bundle, OscColor as Color,
                     OscMessage as Message, OscMidiMessage as MidiMessage, OscError as Error,
                     OscType as Type};
pub use self::recv::Receiver;
pub use self::send::Sender;

use std;
use std::net::{Ipv4Addr, SocketAddr};

pub mod recv;
pub mod send;

/// Indicates that a `Sender` is not currently connected to a target address, and that the target
/// address will have to be supplied manually when sending packets.
pub struct Unconnected;

/// Indicates that a `Sender` is currently connected to a specific target address.
pub struct Connected {
    addr: SocketAddr,
}

/// An *OSC packet* can contain an OSC message or a bundle of nested packets which is called an
/// *OSC bundle*.
#[derive(Clone, Debug, PartialEq)]
pub enum Packet {
    Message(Message),
    Bundle(Bundle),
}

impl From<Message> for Packet {
    fn from(msg: Message) -> Self {
        Packet::Message(msg)
    }
}

impl From<Bundle> for Packet {
    fn from(bundle: Bundle) -> Self {
        Packet::Bundle(bundle)
    }
}

impl From<rosc::OscPacket> for Packet {
    fn from(packet: rosc::OscPacket) -> Self {
        match packet {
            rosc::OscPacket::Message(msg) => msg.into(),
            rosc::OscPacket::Bundle(bundle) => bundle.into(),
        }
    }
}

impl<A> From<(A, Vec<Type>)> for Packet
    where A: Into<String>,
{
    fn from((addr, args): (A, Vec<Type>)) -> Self {
        msg(addr, args).into()
    }
}

impl Into<rosc::OscPacket> for Packet {
    fn into(self) -> rosc::OscPacket {
        match self {
            Packet::Message(msg) => rosc::OscPacket::Message(msg),
            Packet::Bundle(bundle) => rosc::OscPacket::Bundle(bundle),
        }
    }
}

/// The default local IP address.
pub fn default_ipv4_addr() -> Ipv4Addr {
    Ipv4Addr::new(127, 0, 0, 1)
}

/// A simple wrapper around the most commonly used `Receiver` constructor.
pub fn receiver(port: u16) -> Result<Receiver, std::io::Error> {
    Receiver::bind(port)
}

/// A simple wrapper around the most commonly used `Sender` constructor.
pub fn sender() -> Result<Sender, std::io::Error> {
    Sender::bind()
}

/// A simplified constructor for an OSC `Message`.
pub fn msg<A>(addr: A, args: Vec<Type>) -> Message
    where A: Into<String>,
{
    let addr = addr.into();
    let args = Some(args);
    Message { addr, args }
}

/// Decodes the given slice of `bytes` into a `Packet`.
///
/// Returns an `Error` if the slice does not contain a valid OSC packet.
pub fn decode(bytes: &[u8]) -> Result<Packet, Error> {
    rosc::decoder::decode(bytes).map(|p| p.into())
}

/// Encodes the given `Packet` into a `Vec` of bytes.
///
/// Returns an `Error` if the packet is invalid.
pub fn encode(packet: Packet) -> Result<Vec<u8>, Error> {
    let rosc_packet = packet.into();
    rosc::encoder::encode(&rosc_packet)
}

/// Errors that might occur whilst attempting to send or receive an OSC packet.
#[derive(Debug)]
pub enum CommunicationError {
    Io(std::io::Error),
    Osc(Error),
    Poisoned,
}

impl From<std::io::Error> for CommunicationError {
    fn from(err: std::io::Error) -> Self {
        CommunicationError::Io(err)
    }
}

impl From<Error> for CommunicationError {
    fn from(err: Error) -> Self {
        CommunicationError::Osc(err)
    }
}

impl<T> From<std::sync::PoisonError<T>> for CommunicationError {
    fn from(_: std::sync::PoisonError<T>) -> Self {
        CommunicationError::Poisoned
    }
}

impl std::error::Error for CommunicationError {
    fn description(&self) -> &str {
        match *self {
            CommunicationError::Io(ref err) => std::error::Error::description(err),
            // TODO: Error isn't implemented for OscError - should fix this upstream.
            CommunicationError::Osc(ref _err) => "Failed to decode the OSC packet",
            // CommunicationError::Osc(ref err) => std::error::Error::description(err),
            CommunicationError::Poisoned => "The inner buffer's mutex was poisoned",
        }
    }
    fn cause(&self) -> Option<&std::error::Error> {
        match *self {
            CommunicationError::Io(ref err) => Some(err),
            // TODO: Error isn't implemented for OscError - should fix this upstream.
            CommunicationError::Osc(ref _err) => None,
            // CommunicationError::Osc(ref err) => Some(err),
            _ => None,
        }
    }
}

impl std::fmt::Display for CommunicationError {
    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
        write!(f, "{}", std::error::Error::description(self))
    }
}
<commit_msg>Add methods for unfolding an osc::Packet into osc::Messages<commit_after>pub extern crate rosc;

// Re-export rosc items.
//
// Remove `Osc` prefix as items are already namespaced via a module, e.g. `OscMessage` becomes
// `osc::Message`.
#[doc(inline)]
pub use self::rosc::{decoder, encoder, OscBundle as Bundle, OscColor as Color,
                     OscMessage as Message, OscMidiMessage as MidiMessage, OscError as Error,
                     OscType as Type};
pub use self::recv::Receiver;
pub use self::send::Sender;

use std;
use std::net::{Ipv4Addr, SocketAddr};

pub mod recv;
pub mod send;

/// Indicates that a `Sender` is not currently connected to a target address, and that the target
/// address will have to be supplied manually when sending packets.
pub struct Unconnected;

/// Indicates that a `Sender` is currently connected to a specific target address.
pub struct Connected {
    addr: SocketAddr,
}

/// An *OSC packet* can contain an OSC message or a bundle of nested packets which is called an
/// *OSC bundle*.
#[derive(Clone, Debug, PartialEq)]
pub enum Packet {
    Message(Message),
    Bundle(Bundle),
}

impl From<Message> for Packet {
    fn from(msg: Message) -> Self {
        Packet::Message(msg)
    }
}

impl From<Bundle> for Packet {
    fn from(bundle: Bundle) -> Self {
        Packet::Bundle(bundle)
    }
}

impl From<rosc::OscPacket> for Packet {
    fn from(packet: rosc::OscPacket) -> Self {
        match packet {
            rosc::OscPacket::Message(msg) => msg.into(),
            rosc::OscPacket::Bundle(bundle) => bundle.into(),
        }
    }
}

impl<A> From<(A, Vec<Type>)> for Packet
    where A: Into<String>,
{
    fn from((addr, args): (A, Vec<Type>)) -> Self {
        msg(addr, args).into()
    }
}

impl Into<rosc::OscPacket> for Packet {
    fn into(self) -> rosc::OscPacket {
        match self {
            Packet::Message(msg) => rosc::OscPacket::Message(msg),
            Packet::Bundle(bundle) => rosc::OscPacket::Bundle(bundle),
        }
    }
}

impl Packet {
    /// A recursive function that unfolds the packet into the end of the given buffer of messages.
    pub fn unfold(self, msgs: &mut Vec<Message>) {
        match self {
            Packet::Message(msg) => msgs.push(msg),
            Packet::Bundle(bundle) => for packet in bundle.content {
                Packet::unfold(packet.into(), msgs);
            },
        }
    }

    /// Convert the `Packet` into a Vec containing all `Message`s contained within.
    ///
    /// This uses the `unfold` method internally.
    pub fn into_msgs(self) -> Vec<Message> {
        let mut msgs = vec![];
        self.unfold(&mut msgs);
        msgs
    }
}

/// The default local IP address.
pub fn default_ipv4_addr() -> Ipv4Addr {
    Ipv4Addr::new(127, 0, 0, 1)
}

/// A simple wrapper around the most commonly used `Receiver` constructor.
pub fn receiver(port: u16) -> Result<Receiver, std::io::Error> {
    Receiver::bind(port)
}

/// A simple wrapper around the most commonly used `Sender` constructor.
pub fn sender() -> Result<Sender, std::io::Error> {
    Sender::bind()
}

/// A simplified constructor for an OSC `Message`.
pub fn msg<A>(addr: A, args: Vec<Type>) -> Message
    where A: Into<String>,
{
    let addr = addr.into();
    let args = Some(args);
    Message { addr, args }
}

/// Decodes the given slice of `bytes` into a `Packet`.
///
/// Returns an `Error` if the slice does not contain a valid OSC packet.
pub fn decode(bytes: &[u8]) -> Result<Packet, Error> {
    rosc::decoder::decode(bytes).map(|p| p.into())
}

/// Encodes the given `Packet` into a `Vec` of bytes.
///
/// Returns an `Error` if the packet is invalid.
pub fn encode(packet: Packet) -> Result<Vec<u8>, Error> {
    let rosc_packet = packet.into();
    rosc::encoder::encode(&rosc_packet)
}

/// Errors that might occur whilst attempting to send or receive an OSC packet.
#[derive(Debug)]
pub enum CommunicationError {
    Io(std::io::Error),
    Osc(Error),
    Poisoned,
}

impl From<std::io::Error> for CommunicationError {
    fn from(err: std::io::Error) -> Self {
        CommunicationError::Io(err)
    }
}

impl From<Error> for CommunicationError {
    fn from(err: Error) -> Self {
        CommunicationError::Osc(err)
    }
}

impl<T> From<std::sync::PoisonError<T>> for CommunicationError {
    fn from(_: std::sync::PoisonError<T>) -> Self {
        CommunicationError::Poisoned
    }
}

impl std::error::Error for CommunicationError {
    fn description(&self) -> &str {
        match *self {
            CommunicationError::Io(ref err) => std::error::Error::description(err),
            // TODO: Error isn't implemented for OscError - should fix this upstream.
            CommunicationError::Osc(ref _err) => "Failed to decode the OSC packet",
            // CommunicationError::Osc(ref err) => std::error::Error::description(err),
            CommunicationError::Poisoned => "The inner buffer's mutex was poisoned",
        }
    }
    fn cause(&self) -> Option<&std::error::Error> {
        match *self {
            CommunicationError::Io(ref err) => Some(err),
            // TODO: Error isn't implemented for OscError - should fix this upstream.
            CommunicationError::Osc(ref _err) => None,
            // CommunicationError::Osc(ref err) => Some(err),
            _ => None,
        }
    }
}

impl std::fmt::Display for CommunicationError {
    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
        write!(f, "{}", std::error::Error::description(self))
    }
}
<|endoftext|>