<commit_before>//! Register information and driver to program xAPIC, X2APIC and I/O APIC

pub mod ioapic;
pub mod x2apic;
pub mod xapic;

/// Specify IPI Delivery Mode
#[derive(Debug, Eq, PartialEq)]
#[repr(u64)]
pub enum DeliveryMode {
    /// Delivers the interrupt specified in the vector field to the target processor or processors.
    Fixed = 0b000,
    /// Same as fixed mode, except that the interrupt is delivered to the processor executing at the
    /// lowest priority among the set of processors specified in the destination field. The ability
    /// for a processor to send a lowest priority IPI is model specific and should be avoided by
    /// BIOS and operating system software.
    LowestPriority = 0b001,
    /// Delivers an SMI interrupt to the target processor or processors.
    /// The vector field must be programmed to 00H for future compatibility.
    SMI = 0b010,
    /// Reserved
    _Reserved = 0b11,
    /// Delivers an NMI interrupt to the target processor or processors.
    /// The vector information is ignored.
    NMI = 0b100,
    /// Delivers an INIT request to the target processor or processors, which causes them to perform an INIT.
    Init = 0b101,
    /// Sends a special start-up IPI (called a SIPI) to the target processor or processors.
    /// The vector typically points to a start-up routine that is part of the
    /// BIOS boot-strap code (see Section 8.4, Multiple-Processor (MP) Initialization). I
    /// PIs sent with this delivery mode are not automatically retried if the source
    /// APIC is unable to deliver it. It is up to the software to deter- mine if the
    /// SIPI was not successfully delivered and to reissue the SIPI if necessary.
    StartUp = 0b110,
}

/// Sepcify IPI Destination Mode.
#[derive(Debug, Eq, PartialEq)]
#[repr(u64)]
pub enum DestinationMode {
    Physical = 0,
    Logical = 1,
}

/// Specify Delivery Status
#[derive(Debug, Eq, PartialEq)]
#[repr(u64)]
pub enum DeliveryStatus {
    Idle = 0,
    SendPending = 1,
}

/// IPI Level
#[derive(Debug, Eq, PartialEq)]
#[repr(u64)]
pub enum Level {
    Deassert = 0,
    Assert = 1,
}

/// IPI Trigger Mode
#[derive(Debug, Eq, PartialEq)]
#[repr(u64)]
pub enum TriggerMode {
    Edge = 0,
    Level = 1,
}

/// IPI Destination Shorthand
#[derive(Debug, Eq, PartialEq)]
#[repr(u64)]
pub enum DestinationShorthand {
    NoShorthand = 0b00,
    Myself = 0b01,
    AllIncludingSelf = 0b10,
    AllExcludingSelf = 0b11,
}

/// Abstract the IPI control register
#[derive(Debug, Eq, PartialEq)]
pub struct Icr(u64);

impl Icr {
    /// Short-hand to create a Icr value.
    #[allow(clippy::too_many_arguments)]
    pub fn new(
        vector: u8,
        destination: ApicId,
        destination_shorthand: DestinationShorthand,
        delivery_mode: DeliveryMode,
        destination_mode: DestinationMode,
        delivery_status: DeliveryStatus,
        level: Level,
        trigger_mode: TriggerMode,
    ) -> Icr {
        let destination: u8 = match destination {
            ApicId::XApic(d) => d,
            ApicId::X2Apic(_d) => {
                unreachable!("x2APIC destinations currently unsupported, adjust Icr construction!")
            }
        };

        Icr((destination as u64) << 56
            | (destination_shorthand as u64) << 18
            | (trigger_mode as u64) << 15
            | (level as u64) << 14
            | (delivery_status as u64) << 12
            | (destination_mode as u64) << 11
            | (delivery_mode as u64) << 8
            | (vector as u64))
    }

    /// Get lower 32-bits of the Icr register.
    pub fn lower(&self) -> u32 {
        self.0 as u32
    }

    /// Get upper 32-bits of the Icr register.
    pub fn upper(&self) -> u32 {
        (self.0 >> 32) as u32
    }
}

/// Encodes the id of a core.
#[derive(Debug, Eq, PartialEq, Copy, Clone)]
pub enum ApicId {
    /// A core destination encoded as an xAPIC ID.
    XApic(u8),
    /// A core destination encoded as an x2APIC ID.
    X2Apic(u32),
}

/// Abstracts common interface of local APIC (x2APIC, xAPIC) hardware devices.
pub trait ApicControl {
    /// Is a bootstrap processor?
    fn bsp(&self) -> bool;

    /// Return APIC ID.
    fn id(&self) -> u32;

    /// Read APIC version
    fn version(&self) -> u32;

    /// End Of Interrupt -- Acknowledge interrupt delivery.
    fn eoi(&mut self);

    /// Enable TSC deadline timer.
    fn tsc_enable(&mut self, vector: u8);

    /// Set TSC deadline value.
    fn tsc_set(&self, value: u64);

    /// Send a INIT IPI to a core.
    unsafe fn ipi_init(&mut self, core: ApicId);

    /// Deassert INIT IPI.
    unsafe fn ipi_init_deassert(&mut self);

    /// Send a STARTUP IPI to a core.
    unsafe fn ipi_startup(&mut self, core: ApicId, start_page: u8);

    /// Send a generic IPI.
    unsafe fn send_ipi(&mut self, icr: Icr);
}
<commit_msg>Implement Into<usize> for ApicId.<commit_after>//! Register information and driver to program xAPIC, X2APIC and I/O APIC

pub mod ioapic;
pub mod x2apic;
pub mod xapic;

/// Specify IPI Delivery Mode
#[derive(Debug, Eq, PartialEq)]
#[repr(u64)]
pub enum DeliveryMode {
    /// Delivers the interrupt specified in the vector field to the target processor or processors.
    Fixed = 0b000,
    /// Same as fixed mode, except that the interrupt is delivered to the processor executing at the
    /// lowest priority among the set of processors specified in the destination field. The ability
    /// for a processor to send a lowest priority IPI is model specific and should be avoided by
    /// BIOS and operating system software.
    LowestPriority = 0b001,
    /// Delivers an SMI interrupt to the target processor or processors.
    /// The vector field must be programmed to 00H for future compatibility.
    SMI = 0b010,
    /// Reserved
    _Reserved = 0b11,
    /// Delivers an NMI interrupt to the target processor or processors.
    /// The vector information is ignored.
    NMI = 0b100,
    /// Delivers an INIT request to the target processor or processors, which causes them to perform an INIT.
    Init = 0b101,
    /// Sends a special start-up IPI (called a SIPI) to the target processor or processors.
    /// The vector typically points to a start-up routine that is part of the
    /// BIOS boot-strap code (see Section 8.4, Multiple-Processor (MP) Initialization). I
    /// PIs sent with this delivery mode are not automatically retried if the source
    /// APIC is unable to deliver it. It is up to the software to deter- mine if the
    /// SIPI was not successfully delivered and to reissue the SIPI if necessary.
    StartUp = 0b110,
}

/// Sepcify IPI Destination Mode.
#[derive(Debug, Eq, PartialEq)]
#[repr(u64)]
pub enum DestinationMode {
    Physical = 0,
    Logical = 1,
}

/// Specify Delivery Status
#[derive(Debug, Eq, PartialEq)]
#[repr(u64)]
pub enum DeliveryStatus {
    Idle = 0,
    SendPending = 1,
}

/// IPI Level
#[derive(Debug, Eq, PartialEq)]
#[repr(u64)]
pub enum Level {
    Deassert = 0,
    Assert = 1,
}

/// IPI Trigger Mode
#[derive(Debug, Eq, PartialEq)]
#[repr(u64)]
pub enum TriggerMode {
    Edge = 0,
    Level = 1,
}

/// IPI Destination Shorthand
#[derive(Debug, Eq, PartialEq)]
#[repr(u64)]
pub enum DestinationShorthand {
    NoShorthand = 0b00,
    Myself = 0b01,
    AllIncludingSelf = 0b10,
    AllExcludingSelf = 0b11,
}

/// Abstract the IPI control register
#[derive(Debug, Eq, PartialEq)]
pub struct Icr(u64);

impl Icr {
    /// Short-hand to create a Icr value.
    #[allow(clippy::too_many_arguments)]
    pub fn new(
        vector: u8,
        destination: ApicId,
        destination_shorthand: DestinationShorthand,
        delivery_mode: DeliveryMode,
        destination_mode: DestinationMode,
        delivery_status: DeliveryStatus,
        level: Level,
        trigger_mode: TriggerMode,
    ) -> Icr {
        let destination: u8 = match destination {
            ApicId::XApic(d) => d,
            ApicId::X2Apic(_d) => {
                unreachable!("x2APIC destinations currently unsupported, adjust Icr construction!")
            }
        };

        Icr((destination as u64) << 56
            | (destination_shorthand as u64) << 18
            | (trigger_mode as u64) << 15
            | (level as u64) << 14
            | (delivery_status as u64) << 12
            | (destination_mode as u64) << 11
            | (delivery_mode as u64) << 8
            | (vector as u64))
    }

    /// Get lower 32-bits of the Icr register.
    pub fn lower(&self) -> u32 {
        self.0 as u32
    }

    /// Get upper 32-bits of the Icr register.
    pub fn upper(&self) -> u32 {
        (self.0 >> 32) as u32
    }
}

/// Encodes the id of a core.
#[derive(Debug, Eq, PartialEq, Copy, Clone)]
pub enum ApicId {
    /// A core destination encoded as an xAPIC ID.
    XApic(u8),
    /// A core destination encoded as an x2APIC ID.
    X2Apic(u32),
}

impl Into<usize> for ApicId {
    fn into(self) -> usize {
        match self {
            ApicId::XApic(id) => id as usize,
            ApicId::X2Apic(id) => id as usize,
        }
    }
}

/// Abstracts common interface of local APIC (x2APIC, xAPIC) hardware devices.
pub trait ApicControl {
    /// Is a bootstrap processor?
    fn bsp(&self) -> bool;

    /// Return APIC ID.
    fn id(&self) -> u32;

    /// Read APIC version
    fn version(&self) -> u32;

    /// End Of Interrupt -- Acknowledge interrupt delivery.
    fn eoi(&mut self);

    /// Enable TSC deadline timer.
    fn tsc_enable(&mut self, vector: u8);

    /// Set TSC deadline value.
    fn tsc_set(&self, value: u64);

    /// Send a INIT IPI to a core.
    unsafe fn ipi_init(&mut self, core: ApicId);

    /// Deassert INIT IPI.
    unsafe fn ipi_init_deassert(&mut self);

    /// Send a STARTUP IPI to a core.
    unsafe fn ipi_startup(&mut self, core: ApicId, start_page: u8);

    /// Send a generic IPI.
    unsafe fn send_ipi(&mut self, icr: Icr);
}
<|endoftext|>


<commit_before>extern crate game_of_life;
#[macro_use]
extern crate glium;

use game_of_life::simulation::{GameOfLife, Grid};
use glium::{DisplayBuild, Program, Surface, VertexBuffer};
use glium::glutin::ElementState::Pressed;
use glium::glutin::{Event, WindowBuilder, VirtualKeyCode};
use glium::index;
use glium::uniforms::EmptyUniforms;

const FRAMES_PER_CYCLE: u32 = 20;
const GRID_HEIGHT: usize = 20;
const GRID_WIDTH: usize = 20;
const X_OFFSET: usize = 9;
const Y_OFFSET: usize = 9;

fn main() {
    let display = WindowBuilder::new().build_glium().unwrap();

    let mut grid = Grid::new(GRID_HEIGHT, GRID_WIDTH);
    for point in &[(X_OFFSET + 1, Y_OFFSET + 1),
                   (X_OFFSET, Y_OFFSET + 2),
                   (X_OFFSET + 1, Y_OFFSET + 2),
                   (X_OFFSET + 2, Y_OFFSET + 2),
                   (X_OFFSET, Y_OFFSET + 3),
                   (X_OFFSET + 2, Y_OFFSET + 3),
                   (X_OFFSET + 1, Y_OFFSET + 4)] {
        grid[*point] = true;
    }

    let program = {
        let vertex_shader_src = include_str!("../assets/vs.glsl");
        let fragment_shader_src = include_str!("../assets/fs.glsl");

        Program::from_source(&display, vertex_shader_src, fragment_shader_src, None).unwrap()
    };

    let mut passed_frames = 0;
    loop {
        let alive_cells = {
            let mut triangles = Vec::new();

            for x in 0..grid.cols() {
                for y in 0..grid.rows() {
                    if grid[(x, y)] {
                        let x = x as f32;
                        let y = y as f32;

                        triangles.push(Vertex { v_position: convert_coordinates(&grid, (x, y)) });
                        triangles.push(Vertex {
                            v_position: convert_coordinates(&grid, (x + 1.0, y)),
                        });
                        triangles.push(Vertex {
                            v_position: convert_coordinates(&grid, (x, y + 1.0)),
                        });
                        triangles.push(Vertex {
                            v_position: convert_coordinates(&grid, (x, y + 1.0)),
                        });
                        triangles.push(Vertex {
                            v_position: convert_coordinates(&grid, (x + 1.0, y + 1.0)),
                        });
                        triangles.push(Vertex {
                            v_position: convert_coordinates(&grid, (x + 1.0, y)),
                        });
                    }
                }
            }

            VertexBuffer::new(&display, &triangles).unwrap()
        };
        let alive_indices = index::NoIndices(index::PrimitiveType::TrianglesList);

        // listing the events produced by the window and waiting to be received
        for ev in display.poll_events() {
            match ev {
                Event::Closed |
                Event::KeyboardInput(Pressed, _, Some(VirtualKeyCode::Escape)) => return,
                _ => (),
            }
        }

        let mut target = display.draw();
        target.clear_color(0.9, 0.9, 0.9, 1.0);
        target.draw(&alive_cells,
                  &alive_indices,
                  &program,
                  &EmptyUniforms,
                  &Default::default())
            .unwrap();
        target.finish().unwrap();

        passed_frames += 1;
        if passed_frames > FRAMES_PER_CYCLE {
            grid = grid.simulate();
            passed_frames = 0;
        }
    }
}

/// Convert coordinates from a `Gridn` to screen coordinates, assuming OpenGL's default coordinate
/// system.
fn convert_coordinates(grid: &Grid, (x, y): (f32, f32)) -> [f32; 2] {
    [x / grid.cols() as f32 * 2.0 - 1.0, y / grid.rows() as f32 * 2.0 - 1.0]
}

#[derive(Copy, Clone)]
struct Vertex {
    v_position: [f32; 2],
}

implement_vertex!(Vertex, v_position);
<commit_msg>Flip the Y-axis so the pattern gets draw as expected<commit_after>extern crate game_of_life;
#[macro_use]
extern crate glium;

use game_of_life::simulation::{GameOfLife, Grid};
use glium::{DisplayBuild, Program, Surface, VertexBuffer};
use glium::glutin::ElementState::Pressed;
use glium::glutin::{Event, WindowBuilder, VirtualKeyCode};
use glium::index;
use glium::uniforms::EmptyUniforms;

const FRAMES_PER_CYCLE: u32 = 20;
const GRID_HEIGHT: usize = 20;
const GRID_WIDTH: usize = 20;
const X_OFFSET: usize = 9;
const Y_OFFSET: usize = 9;

fn main() {
    let display = WindowBuilder::new().build_glium().unwrap();

    let mut grid = Grid::new(GRID_HEIGHT, GRID_WIDTH);
    for point in &[(X_OFFSET + 1, Y_OFFSET + 1),
                   (X_OFFSET, Y_OFFSET + 2),
                   (X_OFFSET + 1, Y_OFFSET + 2),
                   (X_OFFSET + 2, Y_OFFSET + 2),
                   (X_OFFSET, Y_OFFSET + 3),
                   (X_OFFSET + 2, Y_OFFSET + 3),
                   (X_OFFSET + 1, Y_OFFSET + 4)] {
        grid[*point] = true;
    }

    let program = {
        let vertex_shader_src = include_str!("../assets/vs.glsl");
        let fragment_shader_src = include_str!("../assets/fs.glsl");

        Program::from_source(&display, vertex_shader_src, fragment_shader_src, None).unwrap()
    };

    let mut passed_frames = 0;
    loop {
        let alive_cells = {
            let mut triangles = Vec::new();

            for x in 0..grid.cols() {
                for y in 0..grid.rows() {
                    if grid[(x, y)] {
                        let x = x as f32;
                        let y = y as f32;

                        triangles.push(Vertex { v_position: convert_coordinates(&grid, (x, y)) });
                        triangles.push(Vertex {
                            v_position: convert_coordinates(&grid, (x + 1.0, y)),
                        });
                        triangles.push(Vertex {
                            v_position: convert_coordinates(&grid, (x, y + 1.0)),
                        });
                        triangles.push(Vertex {
                            v_position: convert_coordinates(&grid, (x, y + 1.0)),
                        });
                        triangles.push(Vertex {
                            v_position: convert_coordinates(&grid, (x + 1.0, y + 1.0)),
                        });
                        triangles.push(Vertex {
                            v_position: convert_coordinates(&grid, (x + 1.0, y)),
                        });
                    }
                }
            }

            VertexBuffer::new(&display, &triangles).unwrap()
        };
        let alive_indices = index::NoIndices(index::PrimitiveType::TrianglesList);

        // listing the events produced by the window and waiting to be received
        for ev in display.poll_events() {
            match ev {
                Event::Closed |
                Event::KeyboardInput(Pressed, _, Some(VirtualKeyCode::Escape)) => return,
                _ => (),
            }
        }

        let mut target = display.draw();
        target.clear_color(0.9, 0.9, 0.9, 1.0);
        target.draw(&alive_cells,
                  &alive_indices,
                  &program,
                  &EmptyUniforms,
                  &Default::default())
            .unwrap();
        target.finish().unwrap();

        passed_frames += 1;
        if passed_frames > FRAMES_PER_CYCLE {
            grid = grid.simulate();
            passed_frames = 0;
        }
    }
}

/// Convert coordinates from a `Gridn` to screen coordinates, assuming OpenGL's default coordinate
/// system.
fn convert_coordinates(grid: &Grid, (x, y): (f32, f32)) -> [f32; 2] {
    [x / grid.cols() as f32 * 2.0 - 1.0, y / grid.rows() as f32 * -2.0 + 1.0]
}

#[derive(Copy, Clone)]
struct Vertex {
    v_position: [f32; 2],
}

implement_vertex!(Vertex, v_position);
<|endoftext|>


<commit_before>
extern crate mprovision;
#[macro_use(version)]
extern crate version;
extern crate chrono;
#[cfg(test)]
#[macro_use(expect)]
extern crate expectest;
extern crate clap;

use mprovision as mp;
use cli::Command;
use std::env;
use chrono::*;

mod cli;

fn main() {
    let result = cli::parse(env::args()).and_then(|command| {
        match command {
            Command::List(cli::ListParams { filter, expires_in_days, directory }) => {
                mp::with_directory(directory)
                    .and_then(|dir| mp::entries(&dir).map(|entries| entries.collect::<Vec<_>>()))
                    .map_err(|err| err.into())
                    .map(|entries| {
                        let total = entries.len();
                        let date = expires_in_days.map(|days| UTC::now() + Duration::days(days));
                        let filter_string = filter.as_ref();
                        let profiles = mp::filter(entries, |profile| {
                            match (date, filter_string) {
                                (Some(date), Some(string)) => {
                                    profile.expiration_date <= date && profile.contains(&string)
                                }
                                (Some(date), _) => profile.expiration_date <= date,
                                (_, Some(string)) => profile.contains(&string),
                                (_, _) => false,
                            }
                        });
                        (total, profiles)
                    })
                    .and_then(|(total, profiles)| {
                        if profiles.is_empty() {
                            Ok(println!("Nothing found"))
                        } else {
                            for profile in &profiles {
                                println!("\n{}", profile.description());
                            }
                            Ok(println!("\nFound {} of {}", profiles.len(), total))
                        }
                    })
            }
            Command::ShowUuid(uuid, directory) => {
                mp::with_directory(directory)
                    .and_then(|directory| {
                        mp::find_by_uuid(&directory, &uuid).and_then(|profile| {
                            mp::show(&profile.path).map(|xml| println!("{}", xml))
                        })
                    })
                    .map_err(|err| err.into())
            }
            Command::ShowPath(file_path) => {
                mp::show(&file_path)
                    .map(|xml| println!("{}", xml))
                    .map_err(|err| err.into())
            }
            Command::Remove(uuid, directory) => {
                mp::with_directory(directory)
                    .and_then(|directory| {
                        mp::find_by_uuid(&directory, &uuid)
                            .and_then(|profile| mp::remove(&profile.path))
                            .map(|_| println!("'{}' was removed", uuid))
                    })
                    .map_err(|err| err.into())
            }
            Command::Cleanup(directory) => {
                mp::with_directory(directory)
                    .and_then(|dir| mp::entries(&dir).map(|entries| entries.collect::<Vec<_>>()))
                    .map_err(|err| err.into())
                    .map(|entries| {
                        let date = UTC::now();
                        let profiles = mp::filter(entries,
                                                  |profile| profile.expiration_date <= date);
                        profiles
                    })
                    .and_then(|profiles| {
                        if profiles.is_empty() {
                            Ok(println!("All provisioning profiles are valid"))
                        } else {
                            profiles.iter()
                                .map(|profile| {
                                    std::fs::remove_file(&profile.path)
                                        .map(|_| format!("'{}' was removed", profile.uuid))
                                        .map_err(|err| format!("'{}' {}", profile.uuid, err))
                                })
                                .fold(Ok(String::new()), |acc, s| {
                                    match (acc, s) {
                                        (Ok(acc), Ok(s)) => Ok(concat(acc, s)),
                                        (Err(acc), Ok(s)) => Err(concat(acc, s)),
                                        (Err(acc), Err(s)) => Err(concat(acc, s)),
                                        (Ok(acc), Err(s)) => Err(concat(acc, s)),
                                    }
                                })
                                .map(|s| println!("{}", s))
                                .map_err(|err| cli::Error::Custom(err))
                        }
                    })
            }
        }
    });
    if let Err(e) = result {
        e.exit();
    }
}

fn concat(mut s1: String, s2: String) -> String {
    s1.push_str(&s2);
    s1
}
<commit_msg>Refactor commands into smaller functions<commit_after>
extern crate mprovision;
#[macro_use(version)]
extern crate version;
extern crate chrono;
#[cfg(test)]
#[macro_use(expect)]
extern crate expectest;
extern crate clap;

use mprovision as mp;
use cli::Command;
use std::env;
use std::path::PathBuf;
use chrono::*;

mod cli;

fn main() {
    let result = cli::parse(env::args()).and_then(|command| {
        match command {
            Command::List(cli::ListParams { filter, expires_in_days, directory }) => {
                list(filter, expires_in_days, directory)
            }
            Command::ShowUuid(uuid, directory) => show_uuid(uuid, directory),
            Command::ShowPath(file_path) => show_path(file_path),
            Command::Remove(uuid, directory) => remove(uuid, directory),
            Command::Cleanup(directory) => cleanup(directory),
        }
    });
    if let Err(e) = result {
        e.exit();
    }
}

fn list(filter: Option<String>,
        expires_in_days: Option<i64>,
        directory: Option<PathBuf>)
        -> Result<(), cli::Error> {
    mp::with_directory(directory)
        .and_then(|dir| mp::entries(&dir).map(|entries| entries.collect::<Vec<_>>()))
        .map_err(|err| err.into())
        .map(|entries| {
            let total = entries.len();
            let date = expires_in_days.map(|days| UTC::now() + Duration::days(days));
            let filter_string = filter.as_ref();
            let profiles = mp::filter(entries, |profile| {
                match (date, filter_string) {
                    (Some(date), Some(string)) => {
                        profile.expiration_date <= date && profile.contains(&string)
                    }
                    (Some(date), _) => profile.expiration_date <= date,
                    (_, Some(string)) => profile.contains(&string),
                    (_, _) => false,
                }
            });
            (total, profiles)
        })
        .and_then(|(total, profiles)| {
            if profiles.is_empty() {
                Ok(println!("Nothing found"))
            } else {
                for profile in &profiles {
                    println!("\n{}", profile.description());
                }
                Ok(println!("\nFound {} of {}", profiles.len(), total))
            }
        })
}

fn show_uuid(uuid: String, directory: Option<PathBuf>) -> Result<(), cli::Error> {
    mp::with_directory(directory)
        .and_then(|directory| {
            mp::find_by_uuid(&directory, &uuid)
                .and_then(|profile| mp::show(&profile.path).map(|xml| println!("{}", xml)))
        })
        .map_err(|err| err.into())
}

fn show_path(file_path: PathBuf) -> Result<(), cli::Error> {
    mp::show(&file_path)
        .map(|xml| println!("{}", xml))
        .map_err(|err| err.into())
}

fn remove(uuid: String, directory: Option<PathBuf>) -> Result<(), cli::Error> {
    mp::with_directory(directory)
        .and_then(|directory| {
            mp::find_by_uuid(&directory, &uuid)
                .and_then(|profile| mp::remove(&profile.path))
                .map(|_| println!("'{}' was removed", uuid))
        })
        .map_err(|err| err.into())
}

fn cleanup(directory: Option<PathBuf>) -> Result<(), cli::Error> {

    fn concat(mut s1: String, s2: String) -> String {
        s1.push_str(&s2);
        s1
    }

    mp::with_directory(directory)
        .and_then(|dir| mp::entries(&dir).map(|entries| entries.collect::<Vec<_>>()))
        .map_err(|err| err.into())
        .map(|entries| {
            let date = UTC::now();
            mp::filter(entries, |profile| profile.expiration_date <= date)
        })
        .and_then(|profiles| {
            if profiles.is_empty() {
                Ok(println!("All provisioning profiles are valid"))
            } else {
                profiles.iter()
                    .map(|profile| {
                        std::fs::remove_file(&profile.path)
                            .map(|_| format!("'{}' was removed", profile.uuid))
                            .map_err(|err| format!("'{}' {}", profile.uuid, err))
                    })
                    .fold(Ok(String::new()), |acc, s| {
                        match (acc, s) {
                            (Ok(acc), Ok(s)) => Ok(concat(acc, s)),
                            (Err(acc), Ok(s)) => Err(concat(acc, s)),
                            (Err(acc), Err(s)) => Err(concat(acc, s)),
                            (Ok(acc), Err(s)) => Err(concat(acc, s)),
                        }
                    })
                    .map(|s| println!("{}", s))
                    .map_err(|err| cli::Error::Custom(err))
            }
        })
}
<|endoftext|>


<commit_before>
extern crate mprovision;
#[macro_use(version)]
extern crate version;
extern crate chrono;
#[cfg(test)]
#[macro_use(expect)]
extern crate expectest;
extern crate clap;

use mprovision as mp;
use cli::Command;
use std::env;
use chrono::*;

mod cli;

fn main() {
    let result = cli::parse(env::args()).and_then(|command| {
        match command {
            Command::List(list_params) => Ok(()),
            Command::ShowUuid(uuid, directory) => Ok(()),
            Command::ShowPath(file_path) => Ok(()),
            Command::RemoveUuid(uuid, directory) => {
                mp::with_dir(directory, |dir| mp::remove(dir, &uuid))?;
                Ok(println!("'{}' was removed", uuid))
            }
            Command::RemovePath(file_path) => Ok(()),
            Command::Cleanup(directory) => {
                let info = mp::with_dir(directory, |dir| mp::expired_profiles(dir, UTC::now()))?;
                if info.profiles.is_empty() {
                    Ok(println!("All provisioning profiles are valid"))
                } else {
                    let mut errors_counter = 0;
                    let mut removals_counter = 0;
                    for profile in info.profiles {
                        match std::fs::remove_file(&profile.path) {
                            Ok(_) => {
                                removals_counter += 1;
                                println!("'{}' was removed", profile.uuid)
                            }
                            Err(e) => {
                                errors_counter += 1;
                                println!("Error while trying to remove '{}'", profile.uuid);
                                println!("{}", e);
                            }
                        }
                    }
                    println!("Removed {} of {}", removals_counter, info.total);
                    if errors_counter > 0 {
                        Err(cli::Error::Custom("There were some errors while removing \
                                                provisioning profiles"
                            .into()))
                    } else {
                        Ok(())
                    }
                }
            }
        }
    });
    if let Err(e) = result {
        e.exit();
    }
}

// fn search(args: &::docopt::ArgvMap) -> CliResult {
//    let text = args.get_str("<text>");
//    if text.is_empty() {
//        return Err(CliError::EmptyParameter("<text>"));
//    }
//
//    let info = mp::with_dir(directory(args), |dir| mp::search(dir, text))?;
//    if info.profiles.is_empty() {
//        println!("Nothing found for '{}'", text);
//    } else {
//        for profile in &info.profiles {
//            println!("\n{}", profile.description());
//        }
//        println!("\nFound {} of {}", info.profiles.len(), info.total);
//    }
//    Ok(())
// }
//
// fn show_xml(args: &::docopt::ArgvMap) -> CliResult {
//    let uuid = args.get_str("<uuid>");
//    if uuid.is_empty() {
//        return Err(CliError::EmptyParameter("<uuid>"));
//    }
//
//    let xml = mp::with_dir(directory(args), |dir| mp::xml(dir, uuid))?;
//    println!("{}", xml);
//    Ok(())
// }
//
// fn show_expired(args: &::docopt::ArgvMap) -> CliResult {
//    use chrono::*;
//
//    let mut date = UTC::now();
//    if let Some(days) = args.get_str("<days>").parse::<i64>().ok() {
//        if days < 0 || days > 365 {
//            return Err(CliError::Custom("<days> should be between 0 and 365".to_string()));
//        }
//        date = date + Duration::days(days);
//    }
//
//    let info = mp::with_dir(directory(args), |dir| mp::expired_profiles(dir, date))?;
//    if info.profiles.is_empty() {
//        println!("All provisioning profiles are valid");
//    } else {
//        for profile in &info.profiles {
//            println!("\n{}", profile.description());
//        }
//        println!("\nFound {} of {}", info.profiles.len(), info.total);
//    }
//    Ok(())
// }
<commit_msg>Handle remove path command.<commit_after>
extern crate mprovision;
#[macro_use(version)]
extern crate version;
extern crate chrono;
#[cfg(test)]
#[macro_use(expect)]
extern crate expectest;
extern crate clap;

use mprovision as mp;
use cli::Command;
use std::env;
use chrono::*;
use std::error::Error;

mod cli;

fn main() {
    let result = cli::parse(env::args()).and_then(|command| {
        match command {
            Command::List(list_params) => Ok(()),
            Command::ShowUuid(uuid, directory) => Ok(()),
            Command::ShowPath(file_path) => Ok(()),
            Command::RemoveUuid(uuid, directory) => {
                mp::with_dir(directory, |dir| mp::remove(dir, &uuid))?;
                Ok(println!("'{}' was removed", uuid))
            }
            Command::RemovePath(file_path) => {
                if file_path.extension().map(|ext| ext == "mobileprovision").unwrap_or(false) {
                    if file_path.exists() {
                        std::fs::remove_file(&file_path)
                            .map_err(|err| cli::Error::Custom(err.description().to_string()))?;
                        Ok(println!("'{}' was removed", file_path.display()))
                    } else {
                        Err(cli::Error::Custom(format!("'{}' doesn't exist", file_path.display())))
                    }
                } else {
                    Err(cli::Error::Custom(format!("'{}' doesn't have 'mobileprovision' \
                                                    extension",
                                                   file_path.display())))
                }
            }
            Command::Cleanup(directory) => {
                let info = mp::with_dir(directory, |dir| mp::expired_profiles(dir, UTC::now()))?;
                if info.profiles.is_empty() {
                    Ok(println!("All provisioning profiles are valid"))
                } else {
                    let mut errors_counter = 0;
                    let mut removals_counter = 0;
                    for profile in info.profiles {
                        match std::fs::remove_file(&profile.path) {
                            Ok(_) => {
                                removals_counter += 1;
                                println!("'{}' was removed", profile.uuid)
                            }
                            Err(e) => {
                                errors_counter += 1;
                                println!("Error while trying to remove '{}'", profile.uuid);
                                println!("{}", e);
                            }
                        }
                    }
                    println!("Removed {} of {}", removals_counter, info.total);
                    if errors_counter > 0 {
                        Err(cli::Error::Custom("There were some errors while removing \
                                                provisioning profiles"
                            .into()))
                    } else {
                        Ok(())
                    }
                }
            }
        }
    });
    if let Err(e) = result {
        e.exit();
    }
}

// fn search(args: &::docopt::ArgvMap) -> CliResult {
//    let text = args.get_str("<text>");
//    if text.is_empty() {
//        return Err(CliError::EmptyParameter("<text>"));
//    }
//
//    let info = mp::with_dir(directory(args), |dir| mp::search(dir, text))?;
//    if info.profiles.is_empty() {
//        println!("Nothing found for '{}'", text);
//    } else {
//        for profile in &info.profiles {
//            println!("\n{}", profile.description());
//        }
//        println!("\nFound {} of {}", info.profiles.len(), info.total);
//    }
//    Ok(())
// }
//
// fn show_xml(args: &::docopt::ArgvMap) -> CliResult {
//    let uuid = args.get_str("<uuid>");
//    if uuid.is_empty() {
//        return Err(CliError::EmptyParameter("<uuid>"));
//    }
//
//    let xml = mp::with_dir(directory(args), |dir| mp::xml(dir, uuid))?;
//    println!("{}", xml);
//    Ok(())
// }
//
// fn show_expired(args: &::docopt::ArgvMap) -> CliResult {
//    use chrono::*;
//
//    let mut date = UTC::now();
//    if let Some(days) = args.get_str("<days>").parse::<i64>().ok() {
//        if days < 0 || days > 365 {
//            return Err(CliError::Custom("<days> should be between 0 and 365".to_string()));
//        }
//        date = date + Duration::days(days);
//    }
//
//    let info = mp::with_dir(directory(args), |dir| mp::expired_profiles(dir, date))?;
//    if info.profiles.is_empty() {
//        println!("All provisioning profiles are valid");
//    } else {
//        for profile in &info.profiles {
//            println!("\n{}", profile.description());
//        }
//        println!("\nFound {} of {}", info.profiles.len(), info.total);
//    }
//    Ok(())
// }
<|endoftext|>


<commit_before>//
// MSX CAS Packager
// Copyright (c) 2015 Alvaro Polo
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.

use std::io::Read;
use std::io::Error as IoError;
use std::str::from_utf8;

#[derive(Debug)]
pub struct Block { data: Vec<u8>, }

impl Block {

    pub fn is_bin_header(&self) -> bool {
        self.data.len() >= 16 &&
            self.data[..10] == [0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0]
    }

    pub fn file_name(&self) -> Option<&str> {
        if self.is_bin_header() { from_utf8(&self.data[10..16]).ok() }
        else { None }
    }
}

#[derive(Debug)]
pub enum File {
	Bin(String, usize, usize, usize, Vec<u8>),
    Custom(Vec<u8>)
}

#[derive(Debug)]
pub struct Tape {
    blocks: Vec<Block>,
	files: Vec<File>,
}

#[derive(Debug)]
pub enum LoadError {
	Io(IoError),
}

impl From<IoError> for LoadError {
	fn from(e: IoError) -> LoadError { LoadError::Io(e) }
}

impl Tape {

	#[allow(dead_code)]
	pub fn read(input: &mut Read) -> Result<Tape, LoadError> {
		let mut bytes: Vec<u8> = vec![];
		try!(input.read_to_end(&mut bytes));
		Tape::from_bytes(&bytes[..])
	}

	pub fn from_bytes(bytes: &[u8]) -> Result<Tape, LoadError> {
		let mut tape = Tape { blocks: Tape::parse_blocks(bytes), files: vec![] };
        let mut i = 0;
        while i < tape.blocks.len() {
            let block = &tape.blocks[i];
            if block.is_bin_header() {
                let name = block.file_name().unwrap().to_string();
                let content = &tape.blocks[i+1].data;
                let begin = (content[0] as usize) | (content[1] as usize) << 8;
                let end = (content[2] as usize) | (content[3] as usize) << 8;
                let start = (content[4] as usize) | (content[5] as usize) << 8;
                let data = &content[6..];
                tape.files.push(File::Bin(name, begin, end, start, Vec::from(data)));
                i = i + 2;
            } else {
                tape.files.push(File::Custom(block.data.clone()));
                i = i + 1;
            }
        }
		Ok(tape)
	}

    fn parse_blocks(bytes: &[u8]) -> Vec<Block> {
        let mut blocks: Vec<Block> = vec![];
        let mut hindex: Vec<usize> = vec![];
        let mut i = 0;

        // First of all, we compute the indices of all block headers.
        for win in bytes.windows(8) {
            if win == [0x1f, 0xa6, 0xde, 0xba, 0xcc, 0x13, 0x7d, 0x74] {
                hindex.push(i);
            }
            i = i + 1;
        }

        // Now we use the block header indices to generate the blocks
        for i in 0..hindex.len() {
            let from = hindex[i] + 8;
            let to = if i == hindex.len() - 1 { bytes.len() } else { hindex[i+1] };
            let block = Block { data: Vec::from(&bytes[from..to]) };
            blocks.push(block);
        }
        blocks
    }
}

#[cfg(test)]
mod test {

    use super::*;

    macro_rules! assert_bin {
        ($f:expr, $n:expr, $b:expr, $e:expr, $s:expr, $d:expr) => {
            match $f {
            &File::Bin(ref name, begin, end, start, ref data) => {
                assert_eq!($n, name);
                assert_eq!($b, begin);
                assert_eq!($e, end);
                assert_eq!($s, start);
                assert_eq!($d, &data[..]);
            },
            _ => panic!("unexpected file"),
        }
        }
    }

    #[test]
    fn should_load_empty_tape() {
    	let bytes: Vec<u8> = vec![];
    	let tape = Tape::from_bytes(&bytes);
        assert!(tape.is_ok());
        assert_eq!(0, tape.unwrap().files.len());
    }

    #[test]
    fn should_load_bin_file() {
        let bytes: Vec<u8> = vec![
            0x1f, 0xa6, 0xde, 0xba, 0xcc, 0x13, 0x7d, 0x74,
            0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0,
            0x46, 0x4f, 0x4f, 0x42, 0x41, 0x52,
            0x1f, 0xa6, 0xde, 0xba, 0xcc, 0x13, 0x7d, 0x74,
            0x00, 0x80, 0x08, 0x80, 0x00, 0x00,
            0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07
        ];
        let tape = Tape::from_bytes(&bytes).unwrap();
        assert_eq!(1, tape.files.len());
        assert_bin!(&tape.files[0],
            "FOOBAR", 0x8000, 0x8008, 0x0000, &[0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07]);
    }
}
<commit_msg>Use a `Files` iterator in `Tape` instead of storing the files<commit_after>//
// MSX CAS Packager
// Copyright (c) 2015 Alvaro Polo
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.

use std::io::Read;
use std::io::Error as IoError;
use std::str::from_utf8;

#[derive(Debug)]
pub struct Block { data: Vec<u8>, }

impl Block {

    pub fn is_bin_header(&self) -> bool {
        self.data.len() >= 16 &&
            self.data[..10] == [0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0]
    }

    pub fn file_name(&self) -> Option<&str> {
        if self.is_bin_header() { from_utf8(&self.data[10..16]).ok() }
        else { None }
    }
}

#[derive(Debug, PartialEq)]
pub enum File {
	Bin(String, usize, usize, usize, Vec<u8>),
    Custom(Vec<u8>)
}

pub struct Files<'a> {
    tape: &'a Tape,
    i: usize,
}

impl<'a> Iterator for Files<'a> {
    type Item = File;
    fn next(&mut self) -> Option<File> {
        while self.i < self.tape.blocks.len() {
            let block = &self.tape.blocks[self.i];
            if block.is_bin_header() {
                let name = block.file_name().unwrap().to_string();
                let content = &self.tape.blocks[self.i+1].data;
                let begin = (content[0] as usize) | (content[1] as usize) << 8;
                let end = (content[2] as usize) | (content[3] as usize) << 8;
                let start = (content[4] as usize) | (content[5] as usize) << 8;
                let data = &content[6..];
                self.i = self.i + 2;
                return Some(File::Bin(name, begin, end, start, Vec::from(data)));
            } else {
                self.i = self.i + 1;
                return Some(File::Custom(block.data.clone()));
            }
        }
        None
    }
}

#[derive(Debug)]
pub struct Tape {
    blocks: Vec<Block>,
}

#[derive(Debug)]
pub enum LoadError {
	Io(IoError),
}

impl From<IoError> for LoadError {
	fn from(e: IoError) -> LoadError { LoadError::Io(e) }
}

impl Tape {

	#[allow(dead_code)]
	pub fn read(input: &mut Read) -> Result<Tape, LoadError> {
		let mut bytes: Vec<u8> = vec![];
		try!(input.read_to_end(&mut bytes));
		Tape::from_bytes(&bytes[..])
	}

	pub fn from_bytes(bytes: &[u8]) -> Result<Tape, LoadError> {
		Ok(Tape { blocks: Tape::parse_blocks(bytes) })
	}

    pub fn files(&self) -> Files { Files { tape: self, i: 0 } }

    fn parse_blocks(bytes: &[u8]) -> Vec<Block> {
        let mut blocks: Vec<Block> = vec![];
        let mut hindex: Vec<usize> = vec![];
        let mut i = 0;

        // First of all, we compute the indices of all block headers.
        for win in bytes.windows(8) {
            if win == [0x1f, 0xa6, 0xde, 0xba, 0xcc, 0x13, 0x7d, 0x74] {
                hindex.push(i);
            }
            i = i + 1;
        }

        // Now we use the block header indices to generate the blocks
        for i in 0..hindex.len() {
            let from = hindex[i] + 8;
            let to = if i == hindex.len() - 1 { bytes.len() } else { hindex[i+1] };
            let block = Block { data: Vec::from(&bytes[from..to]) };
            blocks.push(block);
        }
        blocks
    }
}

#[cfg(test)]
mod test {

    use super::*;

    macro_rules! assert_bin {
        ($f:expr, $n:expr, $b:expr, $e:expr, $s:expr, $d:expr) => {
            match $f {
            &File::Bin(ref name, begin, end, start, ref data) => {
                assert_eq!($n, name);
                assert_eq!($b, begin);
                assert_eq!($e, end);
                assert_eq!($s, start);
                assert_eq!($d, &data[..]);
            },
            _ => panic!("unexpected file"),
        }
        }
    }

    #[test]
    fn should_load_empty_tape() {
    	let bytes: Vec<u8> = vec![];
    	let tape = Tape::from_bytes(&bytes);
        assert!(tape.is_ok());
        assert_eq!(None, tape.unwrap().files().next());
    }

    #[test]
    fn should_load_bin_file() {
        let bytes: Vec<u8> = vec![
            0x1f, 0xa6, 0xde, 0xba, 0xcc, 0x13, 0x7d, 0x74,
            0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0,
            0x46, 0x4f, 0x4f, 0x42, 0x41, 0x52,
            0x1f, 0xa6, 0xde, 0xba, 0xcc, 0x13, 0x7d, 0x74,
            0x00, 0x80, 0x08, 0x80, 0x00, 0x00,
            0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07
        ];
        let tape = Tape::from_bytes(&bytes).unwrap();
        let file = tape.files().next().unwrap();
        assert_bin!(&file,
            "FOOBAR", 0x8000, 0x8008, 0x0000, &[0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07]);
    }
}
<|endoftext|>


<commit_before>use std::env;
use std::fs::File;
use std::io::{stderr, Read, Write};
use std::process;
use std::str;

fn main() {
    if let Some(url) = env::args().nth(1) {
        let (scheme, reference) = url.split_at(url.find(':').unwrap_or(0));
        if scheme == "http" {
            let mut parts = reference.split('/').skip(2); //skip first two slashes
            let remote = parts.next().unwrap_or("");
            let path = parts.next().unwrap_or("/");

            let mut remote_parts = remote.split(':');
            let host = remote_parts.next().unwrap_or("127.0.0.1");
            let port = remote_parts.next().unwrap_or("80");

            write!(stderr(), "* Connecting to {}:{}\n", host, port).unwrap();

            let tcp = format!("tcp:{}:{}", host, port);
            let mut stream = File::open(tcp).unwrap();

            write!(stderr(), "* Requesting {}\n", path).unwrap();

            let request = format!("GET {} HTTP/1.0\r\n\r\n", path);
            stream.write(request.as_bytes()).unwrap();
            stream.flush().unwrap();

            write!(stderr(), "* Waiting for response\n").unwrap();

            let mut response = [0; 8192];
            let count = stream.read(&mut response).unwrap();

            let mut headers = true;
            for line in unsafe { str::from_utf8_unchecked(&response[.. count]) }.lines() {
                if headers {
                    if line.is_empty() {
                        headers = false;
                    } else {
                        write!(stderr(), "> {}\n", line).unwrap();
                    }
                } else {
                    println!("{}", line);
                }
            }
        } else {
            write!(stderr(), "wget: unknown scheme '{}'\n", scheme).unwrap();
            process::exit(1);
        }
    } else {
        write!(stderr(), "wget: http://host:port/path\n").unwrap();
        process::exit(1);
    }
}
<commit_msg>Fix wget path<commit_after>use std::env;
use std::fs::File;
use std::io::{stderr, Read, Write};
use std::process;
use std::str;

fn main() {
    if let Some(url) = env::args().nth(1) {
        let (scheme, reference) = url.split_at(url.find(':').unwrap_or(0));
        if scheme == "http" {
            let mut parts = reference.split('/').skip(2); //skip first two slashes
            let remote = parts.next().unwrap_or("");
            let mut path = parts.next().unwrap_or("").to_string();
            for part in parts {
                path.push('/');
                path.push_str(part);
            }

            let mut remote_parts = remote.split(':');
            let host = remote_parts.next().unwrap_or("127.0.0.1");
            let port = remote_parts.next().unwrap_or("80");

            write!(stderr(), "* Connecting to {}:{}\n", host, port).unwrap();

            let tcp = format!("tcp:{}:{}", host, port);
            let mut stream = File::open(tcp).unwrap();

            write!(stderr(), "* Requesting {}\n", path).unwrap();

            let request = format!("GET /{} HTTP/1.0\r\n\r\n", path);
            stream.write(request.as_bytes()).unwrap();
            stream.flush().unwrap();

            write!(stderr(), "* Waiting for response\n").unwrap();

            let mut response = [0; 8192];
            let count = stream.read(&mut response).unwrap();

            let mut headers = true;
            for line in unsafe { str::from_utf8_unchecked(&response[.. count]) }.lines() {
                if headers {
                    if line.is_empty() {
                        headers = false;
                    } else {
                        write!(stderr(), "> {}\n", line).unwrap();
                    }
                } else {
                    println!("{}", line);
                }
            }
        } else {
            write!(stderr(), "wget: unknown scheme '{}'\n", scheme).unwrap();
            process::exit(1);
        }
    } else {
        write!(stderr(), "wget: http://host:port/path\n").unwrap();
        process::exit(1);
    }
}
<|endoftext|>


<commit_before>// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use syntax::{ast, ptr};
use syntax::codemap::Span;
use syntax::parse::classify;

use codemap::SpanUtils;
use expr::{block_contains_comment, is_simple_block, is_unsafe_block, rewrite_cond, ToExpr};
use items::{span_hi_for_arg, span_lo_for_arg};
use lists::{definitive_tactic, itemize_list, write_list, DefinitiveListTactic, ListFormatting,
            ListTactic, Separator, SeparatorPlace, SeparatorTactic};
use rewrite::{Rewrite, RewriteContext};
use shape::Shape;
use utils::{last_line_width, left_most_sub_expr, stmt_expr};

// This module is pretty messy because of the rules around closures and blocks:
// FIXME - the below is probably no longer true in full.
//   * if there is a return type, then there must be braces,
//   * given a closure with braces, whether that is parsed to give an inner block
//     or not depends on if there is a return type and if there are statements
//     in that block,
//   * if the first expression in the body ends with a block (i.e., is a
//     statement without needing a semi-colon), then adding or removing braces
//     can change whether it is treated as an expression or statement.

pub fn rewrite_closure(
    capture: ast::CaptureBy,
    fn_decl: &ast::FnDecl,
    body: &ast::Expr,
    span: Span,
    context: &RewriteContext,
    shape: Shape,
) -> Option<String> {
    debug!("rewrite_closure {:?}", body);

    let (prefix, extra_offset) =
        rewrite_closure_fn_decl(capture, fn_decl, body, span, context, shape)?;
    // 1 = space between `|...|` and body.
    let body_shape = shape.offset_left(extra_offset)?;

    if let ast::ExprKind::Block(ref block) = body.node {
        // The body of the closure is an empty block.
        if block.stmts.is_empty() && !block_contains_comment(block, context.codemap) {
            return Some(format!("{} {{}}", prefix));
        }

        let result = match fn_decl.output {
            ast::FunctionRetTy::Default(_) => {
                try_rewrite_without_block(body, &prefix, context, shape, body_shape)
            }
            _ => None,
        };

        result.or_else(|| {
            // Either we require a block, or tried without and failed.
            rewrite_closure_block(block, &prefix, context, body_shape)
        })
    } else {
        rewrite_closure_expr(body, &prefix, context, body_shape).or_else(|| {
            // The closure originally had a non-block expression, but we can't fit on
            // one line, so we'll insert a block.
            rewrite_closure_with_block(body, &prefix, context, body_shape)
        })
    }
}

fn try_rewrite_without_block(
    expr: &ast::Expr,
    prefix: &str,
    context: &RewriteContext,
    shape: Shape,
    body_shape: Shape,
) -> Option<String> {
    let expr = get_inner_expr(expr, prefix, context);

    if is_block_closure_forced(context, expr) {
        rewrite_closure_with_block(expr, prefix, context, shape)
    } else {
        rewrite_closure_expr(expr, prefix, context, body_shape)
    }
}

fn get_inner_expr<'a>(
    expr: &'a ast::Expr,
    prefix: &str,
    context: &RewriteContext,
) -> &'a ast::Expr {
    if let ast::ExprKind::Block(ref block) = expr.node {
        if !needs_block(block, prefix, context) {
            // block.stmts.len() == 1
            if let Some(expr) = stmt_expr(&block.stmts[0]) {
                return get_inner_expr(expr, prefix, context);
            }
        }
    }

    expr
}

// Figure out if a block is necessary.
fn needs_block(block: &ast::Block, prefix: &str, context: &RewriteContext) -> bool {
    is_unsafe_block(block) || block.stmts.len() > 1
        || block_contains_comment(block, context.codemap) || prefix.contains('\n')
}

// Rewrite closure with a single expression wrapping its body with block.
fn rewrite_closure_with_block(
    body: &ast::Expr,
    prefix: &str,
    context: &RewriteContext,
    shape: Shape,
) -> Option<String> {
    let left_most = left_most_sub_expr(body);
    let veto_block = left_most != body && !classify::expr_requires_semi_to_be_stmt(left_most);
    if veto_block {
        return None;
    }

    let block = ast::Block {
        stmts: vec![
            ast::Stmt {
                id: ast::NodeId::new(0),
                node: ast::StmtKind::Expr(ptr::P(body.clone())),
                span: body.span,
            },
        ],
        id: ast::NodeId::new(0),
        rules: ast::BlockCheckMode::Default,
        span: body.span,
    };
    let block = ::expr::rewrite_block_with_visitor(context, "", &block, shape, false)?;
    Some(format!("{} {}", prefix, block))
}

// Rewrite closure with a single expression without wrapping its body with block.
fn rewrite_closure_expr(
    expr: &ast::Expr,
    prefix: &str,
    context: &RewriteContext,
    shape: Shape,
) -> Option<String> {
    fn allow_multi_line(expr: &ast::Expr) -> bool {
        match expr.node {
            ast::ExprKind::Match(..)
            | ast::ExprKind::Block(..)
            | ast::ExprKind::Catch(..)
            | ast::ExprKind::Loop(..)
            | ast::ExprKind::Struct(..) => true,

            ast::ExprKind::AddrOf(_, ref expr)
            | ast::ExprKind::Box(ref expr)
            | ast::ExprKind::Try(ref expr)
            | ast::ExprKind::Unary(_, ref expr)
            | ast::ExprKind::Cast(ref expr, _) => allow_multi_line(expr),

            _ => false,
        }
    }

    // When rewriting closure's body without block, we require it to fit in a single line
    // unless it is a block-like expression or we are inside macro call.
    let veto_multiline = (!allow_multi_line(expr) && !context.inside_macro)
        || context.config.force_multiline_blocks();
    expr.rewrite(context, shape)
        .and_then(|rw| {
            if veto_multiline && rw.contains('\n') {
                None
            } else {
                Some(rw)
            }
        })
        .map(|rw| format!("{} {}", prefix, rw))
}

// Rewrite closure whose body is block.
fn rewrite_closure_block(
    block: &ast::Block,
    prefix: &str,
    context: &RewriteContext,
    shape: Shape,
) -> Option<String> {
    Some(format!("{} {}", prefix, block.rewrite(context, shape)?))
}

// Return type is (prefix, extra_offset)
fn rewrite_closure_fn_decl(
    capture: ast::CaptureBy,
    fn_decl: &ast::FnDecl,
    body: &ast::Expr,
    span: Span,
    context: &RewriteContext,
    shape: Shape,
) -> Option<(String, usize)> {
    let mover = if capture == ast::CaptureBy::Value {
        "move "
    } else {
        ""
    };
    // 4 = "|| {".len(), which is overconservative when the closure consists of
    // a single expression.
    let nested_shape = shape.shrink_left(mover.len())?.sub_width(4)?;

    // 1 = |
    let argument_offset = nested_shape.indent + 1;
    let arg_shape = nested_shape.offset_left(1)?.visual_indent(0);
    let ret_str = fn_decl.output.rewrite(context, arg_shape)?;

    let arg_items = itemize_list(
        context.codemap,
        fn_decl.inputs.iter(),
        "|",
        ",",
        |arg| span_lo_for_arg(arg),
        |arg| span_hi_for_arg(context, arg),
        |arg| arg.rewrite(context, arg_shape),
        context.codemap.span_after(span, "|"),
        body.span.lo(),
        false,
    );
    let item_vec = arg_items.collect::<Vec<_>>();
    // 1 = space between arguments and return type.
    let horizontal_budget = nested_shape
        .width
        .checked_sub(ret_str.len() + 1)
        .unwrap_or(0);
    let tactic = definitive_tactic(
        &item_vec,
        ListTactic::HorizontalVertical,
        Separator::Comma,
        horizontal_budget,
    );
    let arg_shape = match tactic {
        DefinitiveListTactic::Horizontal => arg_shape.sub_width(ret_str.len() + 1)?,
        _ => arg_shape,
    };

    let fmt = ListFormatting {
        tactic: tactic,
        separator: ",",
        trailing_separator: SeparatorTactic::Never,
        separator_place: SeparatorPlace::Back,
        shape: arg_shape,
        ends_with_newline: false,
        preserve_newline: true,
        config: context.config,
    };
    let list_str = write_list(&item_vec, &fmt)?;
    let mut prefix = format!("{}|{}|", mover, list_str);

    if !ret_str.is_empty() {
        if prefix.contains('\n') {
            prefix.push('\n');
            prefix.push_str(&argument_offset.to_string(context.config));
        } else {
            prefix.push(' ');
        }
        prefix.push_str(&ret_str);
    }
    // 1 = space between `|...|` and body.
    let extra_offset = last_line_width(&prefix) + 1;

    Some((prefix, extra_offset))
}

// Rewriting closure which is placed at the end of the function call's arg.
// Returns `None` if the reformatted closure 'looks bad'.
pub fn rewrite_last_closure(
    context: &RewriteContext,
    expr: &ast::Expr,
    shape: Shape,
) -> Option<String> {
    if let ast::ExprKind::Closure(capture, ref fn_decl, ref body, _) = expr.node {
        let body = match body.node {
            ast::ExprKind::Block(ref block)
                if !is_unsafe_block(block) && is_simple_block(block, context.codemap) =>
            {
                stmt_expr(&block.stmts[0]).unwrap_or(body)
            }
            _ => body,
        };
        let (prefix, extra_offset) =
            rewrite_closure_fn_decl(capture, fn_decl, body, expr.span, context, shape)?;
        // If the closure goes multi line before its body, do not overflow the closure.
        if prefix.contains('\n') {
            return None;
        }

        let body_shape = shape.offset_left(extra_offset)?;

        // We force to use block for the body of the closure for certain kinds of expressions.
        if is_block_closure_forced(context, body) {
            return rewrite_closure_with_block(body, &prefix, context, body_shape).and_then(
                |body_str| {
                    // If the expression can fit in a single line, we need not force block closure.
                    if body_str.lines().count() <= 7 {
                        match rewrite_closure_expr(body, &prefix, context, shape) {
                            Some(ref single_line_body_str)
                                if !single_line_body_str.contains('\n') =>
                            {
                                Some(single_line_body_str.clone())
                            }
                            _ => Some(body_str),
                        }
                    } else {
                        Some(body_str)
                    }
                },
            );
        }

        // When overflowing the closure which consists of a single control flow expression,
        // force to use block if its condition uses multi line.
        let is_multi_lined_cond = rewrite_cond(context, body, body_shape)
            .map(|cond| cond.contains('\n') || cond.len() > body_shape.width)
            .unwrap_or(false);
        if is_multi_lined_cond {
            return rewrite_closure_with_block(body, &prefix, context, body_shape);
        }

        // Seems fine, just format the closure in usual manner.
        return expr.rewrite(context, shape);
    }
    None
}

/// Returns true if the given vector of arguments has more than one `ast::ExprKind::Closure`.
pub fn args_have_many_closure<T>(args: &[&T]) -> bool
where
    T: ToExpr,
{
    args.iter()
        .filter(|arg| {
            arg.to_expr()
                .map(|e| match e.node {
                    ast::ExprKind::Closure(..) => true,
                    _ => false,
                })
                .unwrap_or(false)
        })
        .count() > 1
}

fn is_block_closure_forced(context: &RewriteContext, expr: &ast::Expr) -> bool {
    // If we are inside macro, we do not want to add or remove block from closure body.
    if context.inside_macro {
        false
    } else {
        is_block_closure_forced_inner(expr)
    }
}

fn is_block_closure_forced_inner(expr: &ast::Expr) -> bool {
    match expr.node {
        ast::ExprKind::If(..)
        | ast::ExprKind::IfLet(..)
        | ast::ExprKind::While(..)
        | ast::ExprKind::WhileLet(..)
        | ast::ExprKind::ForLoop(..) => true,
        ast::ExprKind::AddrOf(_, ref expr)
        | ast::ExprKind::Box(ref expr)
        | ast::ExprKind::Try(ref expr)
        | ast::ExprKind::Unary(_, ref expr)
        | ast::ExprKind::Cast(ref expr, _) => is_block_closure_forced_inner(expr),
        _ => false,
    }
}
<commit_msg>Rustup to rustc 1.24.0-nightly (5165ee9e2 2017-12-22)<commit_after>// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use syntax::{ast, ptr};
use syntax::codemap::Span;
use syntax::parse::classify;

use codemap::SpanUtils;
use expr::{block_contains_comment, is_simple_block, is_unsafe_block, rewrite_cond, ToExpr};
use items::{span_hi_for_arg, span_lo_for_arg};
use lists::{definitive_tactic, itemize_list, write_list, DefinitiveListTactic, ListFormatting,
            ListTactic, Separator, SeparatorPlace, SeparatorTactic};
use rewrite::{Rewrite, RewriteContext};
use shape::Shape;
use utils::{last_line_width, left_most_sub_expr, stmt_expr};

// This module is pretty messy because of the rules around closures and blocks:
// FIXME - the below is probably no longer true in full.
//   * if there is a return type, then there must be braces,
//   * given a closure with braces, whether that is parsed to give an inner block
//     or not depends on if there is a return type and if there are statements
//     in that block,
//   * if the first expression in the body ends with a block (i.e., is a
//     statement without needing a semi-colon), then adding or removing braces
//     can change whether it is treated as an expression or statement.

pub fn rewrite_closure(
    capture: ast::CaptureBy,
    fn_decl: &ast::FnDecl,
    body: &ast::Expr,
    span: Span,
    context: &RewriteContext,
    shape: Shape,
) -> Option<String> {
    debug!("rewrite_closure {:?}", body);

    let (prefix, extra_offset) =
        rewrite_closure_fn_decl(capture, fn_decl, body, span, context, shape)?;
    // 1 = space between `|...|` and body.
    let body_shape = shape.offset_left(extra_offset)?;

    if let ast::ExprKind::Block(ref block) = body.node {
        // The body of the closure is an empty block.
        if block.stmts.is_empty() && !block_contains_comment(block, context.codemap) {
            return Some(format!("{} {{}}", prefix));
        }

        let result = match fn_decl.output {
            ast::FunctionRetTy::Default(_) => {
                try_rewrite_without_block(body, &prefix, context, shape, body_shape)
            }
            _ => None,
        };

        result.or_else(|| {
            // Either we require a block, or tried without and failed.
            rewrite_closure_block(block, &prefix, context, body_shape)
        })
    } else {
        rewrite_closure_expr(body, &prefix, context, body_shape).or_else(|| {
            // The closure originally had a non-block expression, but we can't fit on
            // one line, so we'll insert a block.
            rewrite_closure_with_block(body, &prefix, context, body_shape)
        })
    }
}

fn try_rewrite_without_block(
    expr: &ast::Expr,
    prefix: &str,
    context: &RewriteContext,
    shape: Shape,
    body_shape: Shape,
) -> Option<String> {
    let expr = get_inner_expr(expr, prefix, context);

    if is_block_closure_forced(context, expr) {
        rewrite_closure_with_block(expr, prefix, context, shape)
    } else {
        rewrite_closure_expr(expr, prefix, context, body_shape)
    }
}

fn get_inner_expr<'a>(
    expr: &'a ast::Expr,
    prefix: &str,
    context: &RewriteContext,
) -> &'a ast::Expr {
    if let ast::ExprKind::Block(ref block) = expr.node {
        if !needs_block(block, prefix, context) {
            // block.stmts.len() == 1
            if let Some(expr) = stmt_expr(&block.stmts[0]) {
                return get_inner_expr(expr, prefix, context);
            }
        }
    }

    expr
}

// Figure out if a block is necessary.
fn needs_block(block: &ast::Block, prefix: &str, context: &RewriteContext) -> bool {
    is_unsafe_block(block) || block.stmts.len() > 1
        || block_contains_comment(block, context.codemap) || prefix.contains('\n')
}

// Rewrite closure with a single expression wrapping its body with block.
fn rewrite_closure_with_block(
    body: &ast::Expr,
    prefix: &str,
    context: &RewriteContext,
    shape: Shape,
) -> Option<String> {
    let left_most = left_most_sub_expr(body);
    let veto_block = left_most != body && !classify::expr_requires_semi_to_be_stmt(left_most);
    if veto_block {
        return None;
    }

    let block = ast::Block {
        stmts: vec![
            ast::Stmt {
                id: ast::NodeId::new(0),
                node: ast::StmtKind::Expr(ptr::P(body.clone())),
                span: body.span,
            },
        ],
        id: ast::NodeId::new(0),
        rules: ast::BlockCheckMode::Default,
        span: body.span,
        recovered: false,
    };
    let block = ::expr::rewrite_block_with_visitor(context, "", &block, shape, false)?;
    Some(format!("{} {}", prefix, block))
}

// Rewrite closure with a single expression without wrapping its body with block.
fn rewrite_closure_expr(
    expr: &ast::Expr,
    prefix: &str,
    context: &RewriteContext,
    shape: Shape,
) -> Option<String> {
    fn allow_multi_line(expr: &ast::Expr) -> bool {
        match expr.node {
            ast::ExprKind::Match(..)
            | ast::ExprKind::Block(..)
            | ast::ExprKind::Catch(..)
            | ast::ExprKind::Loop(..)
            | ast::ExprKind::Struct(..) => true,

            ast::ExprKind::AddrOf(_, ref expr)
            | ast::ExprKind::Box(ref expr)
            | ast::ExprKind::Try(ref expr)
            | ast::ExprKind::Unary(_, ref expr)
            | ast::ExprKind::Cast(ref expr, _) => allow_multi_line(expr),

            _ => false,
        }
    }

    // When rewriting closure's body without block, we require it to fit in a single line
    // unless it is a block-like expression or we are inside macro call.
    let veto_multiline = (!allow_multi_line(expr) && !context.inside_macro)
        || context.config.force_multiline_blocks();
    expr.rewrite(context, shape)
        .and_then(|rw| {
            if veto_multiline && rw.contains('\n') {
                None
            } else {
                Some(rw)
            }
        })
        .map(|rw| format!("{} {}", prefix, rw))
}

// Rewrite closure whose body is block.
fn rewrite_closure_block(
    block: &ast::Block,
    prefix: &str,
    context: &RewriteContext,
    shape: Shape,
) -> Option<String> {
    Some(format!("{} {}", prefix, block.rewrite(context, shape)?))
}

// Return type is (prefix, extra_offset)
fn rewrite_closure_fn_decl(
    capture: ast::CaptureBy,
    fn_decl: &ast::FnDecl,
    body: &ast::Expr,
    span: Span,
    context: &RewriteContext,
    shape: Shape,
) -> Option<(String, usize)> {
    let mover = if capture == ast::CaptureBy::Value {
        "move "
    } else {
        ""
    };
    // 4 = "|| {".len(), which is overconservative when the closure consists of
    // a single expression.
    let nested_shape = shape.shrink_left(mover.len())?.sub_width(4)?;

    // 1 = |
    let argument_offset = nested_shape.indent + 1;
    let arg_shape = nested_shape.offset_left(1)?.visual_indent(0);
    let ret_str = fn_decl.output.rewrite(context, arg_shape)?;

    let arg_items = itemize_list(
        context.codemap,
        fn_decl.inputs.iter(),
        "|",
        ",",
        |arg| span_lo_for_arg(arg),
        |arg| span_hi_for_arg(context, arg),
        |arg| arg.rewrite(context, arg_shape),
        context.codemap.span_after(span, "|"),
        body.span.lo(),
        false,
    );
    let item_vec = arg_items.collect::<Vec<_>>();
    // 1 = space between arguments and return type.
    let horizontal_budget = nested_shape
        .width
        .checked_sub(ret_str.len() + 1)
        .unwrap_or(0);
    let tactic = definitive_tactic(
        &item_vec,
        ListTactic::HorizontalVertical,
        Separator::Comma,
        horizontal_budget,
    );
    let arg_shape = match tactic {
        DefinitiveListTactic::Horizontal => arg_shape.sub_width(ret_str.len() + 1)?,
        _ => arg_shape,
    };

    let fmt = ListFormatting {
        tactic: tactic,
        separator: ",",
        trailing_separator: SeparatorTactic::Never,
        separator_place: SeparatorPlace::Back,
        shape: arg_shape,
        ends_with_newline: false,
        preserve_newline: true,
        config: context.config,
    };
    let list_str = write_list(&item_vec, &fmt)?;
    let mut prefix = format!("{}|{}|", mover, list_str);

    if !ret_str.is_empty() {
        if prefix.contains('\n') {
            prefix.push('\n');
            prefix.push_str(&argument_offset.to_string(context.config));
        } else {
            prefix.push(' ');
        }
        prefix.push_str(&ret_str);
    }
    // 1 = space between `|...|` and body.
    let extra_offset = last_line_width(&prefix) + 1;

    Some((prefix, extra_offset))
}

// Rewriting closure which is placed at the end of the function call's arg.
// Returns `None` if the reformatted closure 'looks bad'.
pub fn rewrite_last_closure(
    context: &RewriteContext,
    expr: &ast::Expr,
    shape: Shape,
) -> Option<String> {
    if let ast::ExprKind::Closure(capture, ref fn_decl, ref body, _) = expr.node {
        let body = match body.node {
            ast::ExprKind::Block(ref block)
                if !is_unsafe_block(block) && is_simple_block(block, context.codemap) =>
            {
                stmt_expr(&block.stmts[0]).unwrap_or(body)
            }
            _ => body,
        };
        let (prefix, extra_offset) =
            rewrite_closure_fn_decl(capture, fn_decl, body, expr.span, context, shape)?;
        // If the closure goes multi line before its body, do not overflow the closure.
        if prefix.contains('\n') {
            return None;
        }

        let body_shape = shape.offset_left(extra_offset)?;

        // We force to use block for the body of the closure for certain kinds of expressions.
        if is_block_closure_forced(context, body) {
            return rewrite_closure_with_block(body, &prefix, context, body_shape).and_then(
                |body_str| {
                    // If the expression can fit in a single line, we need not force block closure.
                    if body_str.lines().count() <= 7 {
                        match rewrite_closure_expr(body, &prefix, context, shape) {
                            Some(ref single_line_body_str)
                                if !single_line_body_str.contains('\n') =>
                            {
                                Some(single_line_body_str.clone())
                            }
                            _ => Some(body_str),
                        }
                    } else {
                        Some(body_str)
                    }
                },
            );
        }

        // When overflowing the closure which consists of a single control flow expression,
        // force to use block if its condition uses multi line.
        let is_multi_lined_cond = rewrite_cond(context, body, body_shape)
            .map(|cond| cond.contains('\n') || cond.len() > body_shape.width)
            .unwrap_or(false);
        if is_multi_lined_cond {
            return rewrite_closure_with_block(body, &prefix, context, body_shape);
        }

        // Seems fine, just format the closure in usual manner.
        return expr.rewrite(context, shape);
    }
    None
}

/// Returns true if the given vector of arguments has more than one `ast::ExprKind::Closure`.
pub fn args_have_many_closure<T>(args: &[&T]) -> bool
where
    T: ToExpr,
{
    args.iter()
        .filter(|arg| {
            arg.to_expr()
                .map(|e| match e.node {
                    ast::ExprKind::Closure(..) => true,
                    _ => false,
                })
                .unwrap_or(false)
        })
        .count() > 1
}

fn is_block_closure_forced(context: &RewriteContext, expr: &ast::Expr) -> bool {
    // If we are inside macro, we do not want to add or remove block from closure body.
    if context.inside_macro {
        false
    } else {
        is_block_closure_forced_inner(expr)
    }
}

fn is_block_closure_forced_inner(expr: &ast::Expr) -> bool {
    match expr.node {
        ast::ExprKind::If(..)
        | ast::ExprKind::IfLet(..)
        | ast::ExprKind::While(..)
        | ast::ExprKind::WhileLet(..)
        | ast::ExprKind::ForLoop(..) => true,
        ast::ExprKind::AddrOf(_, ref expr)
        | ast::ExprKind::Box(ref expr)
        | ast::ExprKind::Try(ref expr)
        | ast::ExprKind::Unary(_, ref expr)
        | ast::ExprKind::Cast(ref expr, _) => is_block_closure_forced_inner(expr),
        _ => false,
    }
}
<|endoftext|>


<commit_before>//! The Actual RethinkDB Commands

use errors::*;
use conn::{Connection, ConnectOpts};
use serde_json;
use ql2::proto;
use std::io::Write;
use byteorder::{WriteBytesExt, LittleEndian};
use std::io::Read;
use std::str;
use protobuf::ProtobufEnum;
use byteorder::ReadBytesExt;
use super::session::Client;
use super::{Result, r};

pub struct RootCommand(Result<String>);
pub struct Command;
pub struct Query;

pub trait IntoCommandArg {
    fn to_arg(&self) -> Result<String>;
}

impl<'a> IntoCommandArg for &'a str {
    fn to_arg(&self) -> Result<String> {
        Ok(format!("{:?}", self))
    }
}

impl IntoCommandArg for String {
    fn to_arg(&self) -> Result<String> {
        Ok(format!("{:?}", self))
    }
}

impl IntoCommandArg for serde_json::Value {
    fn to_arg(&self) -> Result<String> {
        let arg = try!(serde_json::to_string(self).map_err(|e| DriverError::Json(e)));
        Ok(format!("{}", arg))
    }
}

impl Client {
    pub fn connection(&self) -> ConnectOpts {
        Self::config().read().clone()
    }

    pub fn db_create<T>(&self, name: T) -> RootCommand
        where T: IntoCommandArg
    {
        RootCommand(Command::wrap(proto::Term_TermType::DB_CREATE,
                                     Some(name),
                                     None,
                                     None))
    }

    pub fn db_drop<T>(&self, name: T) -> RootCommand
        where T: IntoCommandArg
    {
        RootCommand(Command::wrap(proto::Term_TermType::DB_DROP,
                                     Some(name),
                                     None,
                                     None))
    }

    pub fn db<T>(&self, name: T) -> RootCommand
        where T: IntoCommandArg
    {
        RootCommand(Command::wrap(proto::Term_TermType::DB,
                                     Some(name),
                                     None,
                                     None))
    }

    pub fn table_create<T>(&self, name: T) -> RootCommand
        where T: IntoCommandArg
    {
        let config = Client::config().read();
        r.db(config.db).table_create(name)
    }

    pub fn table<T>(&self, name: T) -> RootCommand
        where T: IntoCommandArg
    {
        let config = Client::config().read();
        r.db(config.db).table(name)
    }

    pub fn object(&self) -> serde_json::builder::ObjectBuilder {
        serde_json::builder::ObjectBuilder::new()
    }

    pub fn array(&self) -> serde_json::builder::ArrayBuilder {
        serde_json::builder::ArrayBuilder::new()
    }
}

impl RootCommand {
    pub fn table_create<T>(self, name: T) -> RootCommand
        where T: IntoCommandArg
    {
        let commands = match self.0 {
            Ok(t) => t,
            Err(e) => return RootCommand(Err(e)),
        };
        RootCommand(Command::wrap(proto::Term_TermType::TABLE_CREATE,
                                     Some(name),
                                     None,
                                     Some(&commands)))
    }

    pub fn table<T>(self, name: T) -> RootCommand
        where T: IntoCommandArg
    {
        let commands = match self.0 {
            Ok(t) => t,
            Err(e) => return RootCommand(Err(e)),
        };
        RootCommand(Command::wrap(proto::Term_TermType::TABLE,
                                     Some(name),
                                     None,
                                     Some(&commands)))
    }

    pub fn insert<T>(self, data: T) -> RootCommand
        where T: IntoCommandArg
    {
        let commands = match self.0 {
            Ok(t) => t,
            Err(e) => return RootCommand(Err(e)),
        };
        RootCommand(Command::wrap(proto::Term_TermType::INSERT,
                                     Some(data),
                                     None,
                                     Some(&commands)))
    }

    pub fn delete(self) -> RootCommand {
        let commands = match self.0 {
            Ok(t) => t,
            Err(e) => return RootCommand(Err(e)),
        };
        RootCommand(Command::wrap(proto::Term_TermType::DELETE, None as Option<&str>, None as Option<&str>, Some(&commands)))
    }

    pub fn filter<T>(self, filter: T) -> RootCommand
        where T: IntoCommandArg
    {
        let commands = match self.0 {
            Ok(t) => t,
            Err(e) => return RootCommand(Err(e)),
        };
        RootCommand(Command::wrap(proto::Term_TermType::FILTER,
                                     Some(filter),
                                     None,
                                     Some(&commands)))
    }

    pub fn run(self) -> Result<String> {
        let logger = Client::logger().read();
        trace!(logger, "Calling r.run()");
        let commands = try!(self.0);
        let cfg = Client::config().read();
        let query = Query::wrap(proto::Query_QueryType::START, Some(&commands), None);
        debug!(logger, "{}", query);
        let mut conn = try!(Client::conn());
        // Try sending the query
        {
            let mut i = 0;
            let mut write = true;
            let mut connect = false;
            while i < cfg.retries {
                debug!(logger, "Getting connection...");
                if connect {
                    drop(&mut conn);
                    conn = match Client::conn() {
                        Ok(c) => c,
                        Err(error) => {
                            if i == cfg.retries - 1 {
                                // The last error
                                return Err(From::from(error));
                            } else {
                                debug!(logger, "Failed getting a connection. Retrying...");
                                i += 1;
                                continue;
                            }
                        }
                    };
                }
                debug!(logger, "Connection aquired.");
                conn.token += 1;
                if write {
                    debug!(logger, "Writing query...");
                    if let Err(error) = Query::write(&query, &mut conn) {
                        connect = true;
                        if i == cfg.retries - 1 {
                            // The last error
                            return Err(From::from(error));
                        } else {
                            debug!(logger, "Failed to write query. Retrying...");
                            i += 1;
                            continue;
                        }
                    }
                    debug!(logger, "Query written...");
                    connect = false;
                }
                debug!(logger, "Reading query...");
                match Query::read(&mut conn) {
                    Ok(resp) => {
                        let result = try!(str::from_utf8(&resp));
                        debug!(logger, "{}", result);
                        // If the write operation failed, retry it
                        // {"t":18,"e":4100000,"r":["Cannot perform write: primary replica for
                        // shard [\"\", +inf) not available"],"b":[]}
                        let msg = r#"{"t":18,"e":4100000,"r":["Cannot perform write: primary replica for shard"#;
                        if result.starts_with(msg) {
                            write = true;
                            if i == cfg.retries - 1 {
                                // The last error
                                return Err(
                                From::from(
                                    AvailabilityError::OpFailed(
                                        String::from("Not available")
                                        )));
                            } else {
                                debug!(logger, "Write operation failed. Retrying...");
                                i += 1;
                                continue;
                            }
                        } else {
                            debug!(logger, "Query successfully read.");
                            // This is a successful operation
                            break;
                        }
                    }
                    Err(error) => {
                        write = false;
                        if i == cfg.retries - 1 {
                            // The last error
                            return Err(From::from(error));
                        } else {
                            debug!(logger, "Failed to read query. Retrying...");
                            i += 1;
                            continue;
                        }
                    }
                }
            }
        }
        Ok(String::new())
    }
}

impl Command {
    pub fn wrap<T>(command: proto::Term_TermType,
                arguments: Option<T>,
                options: Option<T>,
                commands: Option<&str>)
                -> Result<String>
        where T: IntoCommandArg
    {
        let mut cmds = format!("[{},", command.value());
        let mut args = String::new();
        if let Some(commands) = commands {
            args.push_str(commands);
            if arguments.is_some() {
                args.push_str(",");
            }
        }
        if let Some(arguments) = arguments {
            args.push_str(&try!(arguments.to_arg()));
        }
        cmds.push_str(&format!("[{}]", args));
        if let Some(options) = options {
            cmds.push_str(&format!(",{{{}}}", try!(options.to_arg())));
        }
        cmds.push(']');
        Ok(cmds)
    }
}

impl Query {
    pub fn wrap(query_type: proto::Query_QueryType,
                query: Option<&str>,
                options: Option<&str>)
                -> String {
        let mut qry = format!("[{}", query_type.value());
        if let Some(query) = query {
            qry.push_str(&format!(",{}", query));
        }
        if let Some(options) = options {
            qry.push_str(&format!(",{}", options));
        }
        qry.push_str("]");
        qry
    }

    pub fn write(query: &str, conn: &mut Connection) -> Result<()> {
        let query = query.as_bytes();
        let token = conn.token;
        if let Err(error) = conn.stream.write_u64::<LittleEndian>(token) {
            conn.broken = true;
            return Err(From::from(error));
        }
        if let Err(error) = conn.stream.write_u32::<LittleEndian>(query.len() as u32) {
            conn.broken = true;
            return Err(From::from(error));
        }
        if let Err(error) = conn.stream.write_all(query) {
            conn.broken = true;
            return Err(From::from(error));
        }
        if let Err(error) = conn.stream.flush() {
            conn.broken = true;
            return Err(From::from(error));
        }
        Ok(())
    }

    pub fn read(conn: &mut Connection) -> Result<Vec<u8>> {
        // @TODO use response_token to implement parallel reads and writes?
        // let response_token = try!(conn.stream.read_u64::<LittleEndian>());
        let _ = match conn.stream.read_u64::<LittleEndian>() {
            Ok(token) => token,
            Err(error) => {
                conn.broken = true;
                return Err(From::from(error));
            }
        };
        let len = match conn.stream.read_u32::<LittleEndian>() {
            Ok(len) => len,
            Err(error) => {
                conn.broken = true;
                return Err(From::from(error));
            }
        };
        let mut resp = vec![0u8; len as usize];
        if let Err(error) = conn.stream.read_exact(&mut resp) {
            conn.broken = true;
            return Err(From::from(error));
        }
        Ok(resp)
    }
}
<commit_msg>Allow passing RootCommand as argument<commit_after>//! The Actual RethinkDB Commands

use errors::*;
use conn::{Connection, ConnectOpts};
use serde_json;
use ql2::proto;
use std::io::Write;
use byteorder::{WriteBytesExt, LittleEndian};
use std::io::Read;
use std::str;
use protobuf::ProtobufEnum;
use byteorder::ReadBytesExt;
use super::session::Client;
use super::{Result, r};
use std::fmt;
use std::error::Error as StdError;

pub struct RootCommand(Result<String>);

impl fmt::Display for RootCommand {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self.0 {
            Ok(ref cmd) => write!(f, "{}", cmd),
            Err(_) => Err(fmt::Error),
        }
    }
}

pub struct Command;
pub struct Query;

pub trait IntoCommandArg : fmt::Display {
    fn to_arg(&self) -> Result<String> {
        Ok(format!("{}", self))
    }
}

impl<'a> IntoCommandArg for &'a str {
    fn to_arg(&self) -> Result<String> {
        Ok(format!("{:?}", self))
    }
}

impl IntoCommandArg for String {
    fn to_arg(&self) -> Result<String> {
        Ok(format!("{:?}", self))
    }
}

impl IntoCommandArg for serde_json::Value {
    fn to_arg(&self) -> Result<String> {
        match serde_json::to_string(self) {
            Ok(cmd) => Ok(cmd),
            Err(e) => Err(From::from(DriverError::Json(e))),
        }
    }
}

impl IntoCommandArg for RootCommand {
    fn to_arg(&self) -> Result<String> {
        match self.0 {
            Ok(ref cmd) => Ok(cmd.to_string()),
            Err(ref e) => Err(From::from(DriverError::Other(e.description().to_string()))),
        }
    }
}

impl Client {
    pub fn connection(&self) -> ConnectOpts {
        Self::config().read().clone()
    }

    pub fn db_create<T>(&self, name: T) -> RootCommand
        where T: IntoCommandArg
    {
        RootCommand(Command::wrap(proto::Term_TermType::DB_CREATE,
                                     Some(name),
                                     None,
                                     None))
    }

    pub fn db_drop<T>(&self, name: T) -> RootCommand
        where T: IntoCommandArg
    {
        RootCommand(Command::wrap(proto::Term_TermType::DB_DROP,
                                     Some(name),
                                     None,
                                     None))
    }

    pub fn db<T>(&self, name: T) -> RootCommand
        where T: IntoCommandArg
    {
        RootCommand(Command::wrap(proto::Term_TermType::DB,
                                     Some(name),
                                     None,
                                     None))
    }

    pub fn table_create<T>(&self, name: T) -> RootCommand
        where T: IntoCommandArg
    {
        let config = Client::config().read();
        r.db(config.db).table_create(name)
    }

    pub fn table<T>(&self, name: T) -> RootCommand
        where T: IntoCommandArg
    {
        let config = Client::config().read();
        r.db(config.db).table(name)
    }

    pub fn object(&self) -> serde_json::builder::ObjectBuilder {
        serde_json::builder::ObjectBuilder::new()
    }

    pub fn array(&self) -> serde_json::builder::ArrayBuilder {
        serde_json::builder::ArrayBuilder::new()
    }
}

impl RootCommand {
    pub fn table_create<T>(self, name: T) -> RootCommand
        where T: IntoCommandArg
    {
        let commands = match self.0 {
            Ok(t) => t,
            Err(e) => return RootCommand(Err(e)),
        };
        RootCommand(Command::wrap(proto::Term_TermType::TABLE_CREATE,
                                     Some(name),
                                     None,
                                     Some(&commands)))
    }

    pub fn table<T>(self, name: T) -> RootCommand
        where T: IntoCommandArg
    {
        let commands = match self.0 {
            Ok(t) => t,
            Err(e) => return RootCommand(Err(e)),
        };
        RootCommand(Command::wrap(proto::Term_TermType::TABLE,
                                     Some(name),
                                     None,
                                     Some(&commands)))
    }

    pub fn insert<T>(self, data: T) -> RootCommand
        where T: IntoCommandArg
    {
        let commands = match self.0 {
            Ok(t) => t,
            Err(e) => return RootCommand(Err(e)),
        };
        RootCommand(Command::wrap(proto::Term_TermType::INSERT,
                                     Some(data),
                                     None,
                                     Some(&commands)))
    }

    pub fn delete(self) -> RootCommand {
        let commands = match self.0 {
            Ok(t) => t,
            Err(e) => return RootCommand(Err(e)),
        };
        RootCommand(Command::wrap(proto::Term_TermType::DELETE, None as Option<&str>, None as Option<&str>, Some(&commands)))
    }

    pub fn filter<T>(self, filter: T) -> RootCommand
        where T: IntoCommandArg
    {
        let commands = match self.0 {
            Ok(t) => t,
            Err(e) => return RootCommand(Err(e)),
        };
        RootCommand(Command::wrap(proto::Term_TermType::FILTER,
                                     Some(filter),
                                     None,
                                     Some(&commands)))
    }

    pub fn run(self) -> Result<String> {
        let logger = Client::logger().read();
        trace!(logger, "Calling r.run()");
        let commands = try!(self.0);
        let cfg = Client::config().read();
        let query = Query::wrap(proto::Query_QueryType::START, Some(&commands), None);
        debug!(logger, "{}", query);
        let mut conn = try!(Client::conn());
        // Try sending the query
        {
            let mut i = 0;
            let mut write = true;
            let mut connect = false;
            while i < cfg.retries {
                debug!(logger, "Getting connection...");
                if connect {
                    drop(&mut conn);
                    conn = match Client::conn() {
                        Ok(c) => c,
                        Err(error) => {
                            if i == cfg.retries - 1 {
                                // The last error
                                return Err(From::from(error));
                            } else {
                                debug!(logger, "Failed getting a connection. Retrying...");
                                i += 1;
                                continue;
                            }
                        }
                    };
                }
                debug!(logger, "Connection aquired.");
                conn.token += 1;
                if write {
                    debug!(logger, "Writing query...");
                    if let Err(error) = Query::write(&query, &mut conn) {
                        connect = true;
                        if i == cfg.retries - 1 {
                            // The last error
                            return Err(From::from(error));
                        } else {
                            debug!(logger, "Failed to write query. Retrying...");
                            i += 1;
                            continue;
                        }
                    }
                    debug!(logger, "Query written...");
                    connect = false;
                }
                debug!(logger, "Reading query...");
                match Query::read(&mut conn) {
                    Ok(resp) => {
                        let result = try!(str::from_utf8(&resp));
                        debug!(logger, "{}", result);
                        // If the write operation failed, retry it
                        // {"t":18,"e":4100000,"r":["Cannot perform write: primary replica for
                        // shard [\"\", +inf) not available"],"b":[]}
                        let msg = r#"{"t":18,"e":4100000,"r":["Cannot perform write: primary replica for shard"#;
                        if result.starts_with(msg) {
                            write = true;
                            if i == cfg.retries - 1 {
                                // The last error
                                return Err(
                                From::from(
                                    AvailabilityError::OpFailed(
                                        String::from("Not available")
                                        )));
                            } else {
                                debug!(logger, "Write operation failed. Retrying...");
                                i += 1;
                                continue;
                            }
                        } else {
                            debug!(logger, "Query successfully read.");
                            // This is a successful operation
                            break;
                        }
                    }
                    Err(error) => {
                        write = false;
                        if i == cfg.retries - 1 {
                            // The last error
                            return Err(From::from(error));
                        } else {
                            debug!(logger, "Failed to read query. Retrying...");
                            i += 1;
                            continue;
                        }
                    }
                }
            }
        }
        Ok(String::new())
    }
}

impl Command {
    pub fn wrap<T>(command: proto::Term_TermType,
                arguments: Option<T>,
                options: Option<T>,
                commands: Option<&str>)
                -> Result<String>
        where T: IntoCommandArg
    {
        let mut cmds = format!("[{},", command.value());
        let mut args = String::new();
        if let Some(commands) = commands {
            args.push_str(commands);
            if arguments.is_some() {
                args.push_str(",");
            }
        }
        if let Some(arguments) = arguments {
            args.push_str(&try!(arguments.to_arg()));
        }
        cmds.push_str(&format!("[{}]", args));
        if let Some(options) = options {
            cmds.push_str(&format!(",{{{}}}", try!(options.to_arg())));
        }
        cmds.push(']');
        Ok(cmds)
    }
}

impl Query {
    pub fn wrap(query_type: proto::Query_QueryType,
                query: Option<&str>,
                options: Option<&str>)
                -> String {
        let mut qry = format!("[{}", query_type.value());
        if let Some(query) = query {
            qry.push_str(&format!(",{}", query));
        }
        if let Some(options) = options {
            qry.push_str(&format!(",{}", options));
        }
        qry.push_str("]");
        qry
    }

    pub fn write(query: &str, conn: &mut Connection) -> Result<()> {
        let query = query.as_bytes();
        let token = conn.token;
        if let Err(error) = conn.stream.write_u64::<LittleEndian>(token) {
            conn.broken = true;
            return Err(From::from(error));
        }
        if let Err(error) = conn.stream.write_u32::<LittleEndian>(query.len() as u32) {
            conn.broken = true;
            return Err(From::from(error));
        }
        if let Err(error) = conn.stream.write_all(query) {
            conn.broken = true;
            return Err(From::from(error));
        }
        if let Err(error) = conn.stream.flush() {
            conn.broken = true;
            return Err(From::from(error));
        }
        Ok(())
    }

    pub fn read(conn: &mut Connection) -> Result<Vec<u8>> {
        // @TODO use response_token to implement parallel reads and writes?
        // let response_token = try!(conn.stream.read_u64::<LittleEndian>());
        let _ = match conn.stream.read_u64::<LittleEndian>() {
            Ok(token) => token,
            Err(error) => {
                conn.broken = true;
                return Err(From::from(error));
            }
        };
        let len = match conn.stream.read_u32::<LittleEndian>() {
            Ok(len) => len,
            Err(error) => {
                conn.broken = true;
                return Err(From::from(error));
            }
        };
        let mut resp = vec![0u8; len as usize];
        if let Err(error) = conn.stream.read_exact(&mut resp) {
            conn.broken = true;
            return Err(From::from(error));
        }
        Ok(resp)
    }
}
<|endoftext|>