<commit_before>// Copyright (c) 2016 Rene van der Meer
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.

//! A Rust library that provides an interface for the Pimoroni Blinkt!, and any
//! similar APA102 strips or boards, on a Raspberry Pi.
//!
//! Blinkt accesses the BCM2708/BCM2709 GPIO peripheral either through
//! `/dev/gpiomem` (preferred) or `/dev/mem`. Both the original APA102, and the
//! alternate version with a smaller, darker die, are supported. The APA102 RGB
//! LED/driver ICs are referred to as pixels throughout the code and documentation.
//!
//! Each pixel has a red, green and blue LED with possible values between 0-255.
//! Additionally, the overall brightness of each pixel can be set to 0.0-1.0, which
//! is converted to a 5-bit value.
//!
//! Blinkt stores all color and brightness changes in a local buffer. Use
//! `show()` to send the buffered values to the pixels.
//!
//! # Examples
//!
//! A complete example that cycles all pixels through red, green and blue.
//!
//! ```rust,no_run
//! extern crate blinkt;
//!
//! use std::{thread, mem};
//! use std::time::Duration;
//!
//! use blinkt::Blinkt;
//!
//! fn main() {
//!     let mut blinkt = Blinkt::new().unwrap();
//!     let (red, green, blue) = (&mut 255, &mut 0, &mut 0);
//!
//!     loop {
//!         blinkt.set_all_pixels(*red, *green, *blue);
//!         blinkt.show();
//!
//!         thread::sleep(Duration::from_millis(250));
//!
//!         mem::swap(red, green);
//!         mem::swap(red, blue);
//!     }
//! }
//! ```
//!
//! By default, all pixels are cleared when Blinkt goes out of
//! scope. Use `set_clear_on_drop(false)` to disable this behavior. Note that
//! drop methods aren't called when a program is abnormally terminated (for
//! instance when a SIGINT isn't caught).
//!
//! ```rust,no_run
//! use blinkt::Blinkt;
//!
//! let mut blinkt = Blinkt::new().unwrap();
//! blinkt.set_clear_on_drop(false);
//!
//! for n in 0..8 {
//!     blinkt.set_pixel(n, 36 * n as u8, 0, 255 - (36 * n as u8));
//! }
//!
//! blinkt.show();
//! ```
//!

#![recursion_limit="128"]   // Needed for the quick_error! macro

extern crate libc;
extern crate num;
#[macro_use]
extern crate enum_primitive;
#[macro_use]
extern crate quick_error;

mod gpio;
mod system;

use std::result;

use gpio::{GPIO, Level, Mode};

pub use gpio::Error as GPIOError;

// Default values for the Pimoroni Blinkt! board
const DAT: u8 = 23;
const CLK: u8 = 24;
const NUM_PIXELS: usize = 8;

const DEFAULT_BRIGHTNESS: u8 = 7;

quick_error! {
    #[derive(Debug)]
/// Errors that can occur when creating a new Blinkt.
    pub enum Error {
/// Accessing the GPIO peripheral returned an error.
///
/// Some of these errors can be fixed by changing file permissions, or upgrading
/// to a newer version of Raspbian.
        GPIO(err: GPIOError) { description(err.description()) from() }
    }
}

/// Result type returned from methods that can have `blinkt::Error`s.
pub type Result<T> = result::Result<T, Error>;

#[derive(Debug, Copy, Clone)]
struct Pixel {
    red: u8,
    green: u8,
    blue: u8,
    brightness: u8,
}

impl Default for Pixel {
    fn default() -> Pixel {
        Pixel {
            red: 0,
            green: 0,
            blue: 0,
            brightness: DEFAULT_BRIGHTNESS,
        }
    }
}

/// Interface for a Blinkt! or any similar APA102 strips/boards.
///
/// By default, Blinkt is set up to communicate with an 8-pixel board through
/// data pin 23 and clock pin 24. These settings can be changed to support
/// alternate configurations.
pub struct Blinkt {
    gpio: GPIO,
    pixels: Vec<Pixel>,
    clear_on_drop: bool,
    pin_data: u8,
    pin_clock: u8,
    endframe_pulses: usize,
}

impl Blinkt {
    /// Creates a new `Blinkt` using the default settings for a Pimoroni
    /// Blinkt! board.
    ///
    /// This sets the data pin to 23, the clock pin to 24, and number of pixels
    /// to 8.
    pub fn new() -> Result<Blinkt> {
        Blinkt::with_settings(DAT, CLK, NUM_PIXELS)
    }

    /// Creates a new `Blinkt` using custom settings for the data pin, clock
    /// pin, and number of pixels.
    pub fn with_settings(pin_data: u8, pin_clock: u8, num_pixels: usize) -> Result<Blinkt> {
        // GPIO init might fail with an error the user could solve
        let mut gpio = try!(GPIO::new());

        gpio.set_mode(pin_data, Mode::Output);
        gpio.write(pin_data, Level::Low);
        gpio.set_mode(pin_clock, Mode::Output);
        gpio.write(pin_clock, Level::Low);

        let blinkt = Blinkt {
            gpio: gpio,
            pixels: vec![Pixel::default(); num_pixels],
            clear_on_drop: true,
            pin_data: pin_data,
            pin_clock: pin_clock,
            endframe_pulses: ((num_pixels as f32 * 0.5) + 0.5) as usize,
        };

        Ok(blinkt)
    }

    /// When enabled, clears all pixels when the `Blinkt` goes out of scope.
    ///
    /// Drop methods aren't called when a program is abnormally terminated,
    /// for instance when a user presses Ctrl-C, and the SIGINT signal isn't
    /// caught. You'll either have to catch those using crates such as
    /// `simple_signal`, or manually call `cleanup()`.
    ///
    /// Enabled by default.
    pub fn set_clear_on_drop(&mut self, clear_on_drop: bool) {
        self.clear_on_drop = clear_on_drop;
    }

    /// Changes the GPIO pin mode for the data and clock pins back to their
    /// original state, and optionally clears all pixels.
    ///
    /// Normally, this method is automatically called when Blinkt goes out of
    /// scope, but you can manually call it to handle early/abnormal termination.
    /// After calling this method, any future calls to `show()` won't have any
    /// result.
    pub fn cleanup(&mut self) {
        if self.clear_on_drop {
            self.clear();
            self.show();
        }

        self.gpio.cleanup();
    }

    /// Sets the red, green and blue values for a single pixel in the local
    /// buffer.
    ///
    /// For an 8-pixel board, valid values for pixel are 0-7. Valid values
    /// for red, green and blue are 0-255.
    pub fn set_pixel(&mut self, pixel: usize, red: u8, green: u8, blue: u8) {
        if let Some(pixel) = self.pixels.get_mut(pixel) {
            pixel.red = red;
            pixel.green = green;
            pixel.blue = blue;
        }
    }

    /// Sets the red, green, blue and brightness values for a single pixel in
    /// the local buffer.
    ///
    /// For an 8-pixel board, valid values for pixel are 0-7. Valid
    /// values for red, green and blue are 0-255. Valid values for brightness
    /// are 0.0-1.0, which is converted to a 5-bit value.
    pub fn set_pixel_rgbb(&mut self, pixel: usize, red: u8, green: u8, blue: u8, brightness: f32) {
        if let Some(pixel) = self.pixels.get_mut(pixel) {
            pixel.red = red;
            pixel.green = green;
            pixel.blue = blue;
            pixel.brightness = (31.0 * if brightness > 1.0 { 1.0 } else if brightness < 0.0 { 0.0 } else { brightness }) as u8;
        }
    }

    /// Sets the brightness value for a single pixel in the local buffer.
    ///
    /// For an 8-pixel board, valid values for pixel are 0-7. Valid
    /// values for brightness are 0.0-1.0, which is converted to a
    /// 5-bit value.
    pub fn set_pixel_brightness(&mut self, pixel: usize, brightness: f32) {
        if let Some(pixel) = self.pixels.get_mut(pixel) {
            pixel.brightness = (31.0 * if brightness > 1.0 { 1.0 } else if brightness < 0.0 { 0.0 } else { brightness }) as u8;
        }
    }

    /// Sets the red, green and blue values for all pixels in the local buffer.
    ///
    /// Valid values for red, green and blue are 0-255.
    pub fn set_all_pixels(&mut self, red: u8, green: u8, blue: u8) {
        for pixel in &mut self.pixels {
            pixel.red = red;
            pixel.green = green;
            pixel.blue = blue;
        }
    }

    /// Sets the red, green, blue and brightness values for all pixels in the
    /// local buffer.
    ///
    /// Valid values for red, green and blue are 0-255. Valid values for
    /// brightness are 0.0-1.0, which is converted to a 5-bit value.
    pub fn set_all_pixels_rgbb(&mut self, red: u8, green: u8, blue: u8, brightness: f32) {
        let brightness: u8 = (31.0 * if brightness > 1.0 { 1.0 } else if brightness < 0.0 { 0.0 } else { brightness }) as u8;
        for pixel in &mut self.pixels {
            pixel.red = red;
            pixel.green = green;
            pixel.blue = blue;
            pixel.brightness = brightness;
        }
    }

    /// Sets the brightness value for all pixels in the local buffer.
    ///
    /// Valid values for brightness are 0.0-1.0, which is converted to a 5-bit
    /// value.
    pub fn set_all_pixels_brightness(&mut self, brightness: f32) {
        let brightness: u8 = (31.0 * if brightness > 1.0 { 1.0 } else if brightness < 0.0 { 0.0 } else { brightness }) as u8;
        for pixel in &mut self.pixels {
            pixel.brightness = brightness;
        }
    }

    /// Sets the red, green and blue values to 0 for all pixels in the local
    /// buffer.
    pub fn clear(&mut self) {
        self.set_all_pixels(0, 0, 0);
    }

    /// Sends the contents of the local buffer to the pixels, updating their
    /// LED colors and brightness.
    pub fn show(&self) {
        // Start frame (32x0)
        self.write_byte(0);
        self.write_byte(0);
        self.write_byte(0);
        self.write_byte(0);

        // LED frames
        for pixel in &self.pixels {
            self.write_byte(0b11100000 | pixel.brightness); // 3-bit header + 5-bit brightness
            self.write_byte(pixel.blue);
            self.write_byte(pixel.green);
            self.write_byte(pixel.red);
        }

        // We send another start frame immediately after our end frame, because
        // the APA102 version with a smaller, darker die, won't update the
        // pixels until it receives the next start frame. We still start show()
        // with a start frame, basically sending it twice, in case the user
        // connects a Blinkt! while the code is already running. This workaround
        // is compatible with both the normal and the 'different' APA102.
        self.gpio.write(self.pin_data, Level::Low);
        for _ in 0..32 + self.endframe_pulses {
            self.gpio.write(self.pin_clock, Level::High);
            self.gpio.write(self.pin_clock, Level::Low);
        }
    }

    fn write_byte(&self, byte: u8) {
        for n in 0..8 {
            if (byte & (1 << (7 - n))) > 0 {
                self.gpio.write(self.pin_data, Level::High);
            } else {
                self.gpio.write(self.pin_data, Level::Low);
            }

            self.gpio.write(self.pin_clock, Level::High);
            self.gpio.write(self.pin_clock, Level::Low);
        }
    }
}

impl Drop for Blinkt {
    fn drop(&mut self) {
        self.cleanup();
    }
}

#[test]
fn test_new() {
    let mut blinkt = match Blinkt::new() {
        // GPIO errors are acceptable, since they're likely caused by outside
        // distro/filesystem issues.
        Err(Error::GPIO(_)) => return,
        Ok(blinkt) => blinkt,
    };

    blinkt.set_clear_on_drop(false);
}
<commit_msg>Remove temporary blinkt variable binding in new()<commit_after>// Copyright (c) 2016 Rene van der Meer
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.

//! A Rust library that provides an interface for the Pimoroni Blinkt!, and any
//! similar APA102 strips or boards, on a Raspberry Pi.
//!
//! Blinkt accesses the BCM2708/BCM2709 GPIO peripheral either through
//! `/dev/gpiomem` (preferred) or `/dev/mem`. Both the original APA102, and the
//! alternate version with a smaller, darker die, are supported. The APA102 RGB
//! LED/driver ICs are referred to as pixels throughout the code and documentation.
//!
//! Each pixel has a red, green and blue LED with possible values between 0-255.
//! Additionally, the overall brightness of each pixel can be set to 0.0-1.0, which
//! is converted to a 5-bit value.
//!
//! Blinkt stores all color and brightness changes in a local buffer. Use
//! `show()` to send the buffered values to the pixels.
//!
//! # Examples
//!
//! A complete example that cycles all pixels through red, green and blue.
//!
//! ```rust,no_run
//! extern crate blinkt;
//!
//! use std::{thread, mem};
//! use std::time::Duration;
//!
//! use blinkt::Blinkt;
//!
//! fn main() {
//!     let mut blinkt = Blinkt::new().unwrap();
//!     let (red, green, blue) = (&mut 255, &mut 0, &mut 0);
//!
//!     loop {
//!         blinkt.set_all_pixels(*red, *green, *blue);
//!         blinkt.show();
//!
//!         thread::sleep(Duration::from_millis(250));
//!
//!         mem::swap(red, green);
//!         mem::swap(red, blue);
//!     }
//! }
//! ```
//!
//! By default, all pixels are cleared when Blinkt goes out of
//! scope. Use `set_clear_on_drop(false)` to disable this behavior. Note that
//! drop methods aren't called when a program is abnormally terminated (for
//! instance when a SIGINT isn't caught).
//!
//! ```rust,no_run
//! use blinkt::Blinkt;
//!
//! let mut blinkt = Blinkt::new().unwrap();
//! blinkt.set_clear_on_drop(false);
//!
//! for n in 0..8 {
//!     blinkt.set_pixel(n, 36 * n as u8, 0, 255 - (36 * n as u8));
//! }
//!
//! blinkt.show();
//! ```
//!

#![recursion_limit="128"]   // Needed for the quick_error! macro

extern crate libc;
extern crate num;
#[macro_use]
extern crate enum_primitive;
#[macro_use]
extern crate quick_error;

mod gpio;
mod system;

use std::result;

use gpio::{GPIO, Level, Mode};

pub use gpio::Error as GPIOError;

// Default values for the Pimoroni Blinkt! board
const DAT: u8 = 23;
const CLK: u8 = 24;
const NUM_PIXELS: usize = 8;

const DEFAULT_BRIGHTNESS: u8 = 7;

quick_error! {
    #[derive(Debug)]
/// Errors that can occur when creating a new Blinkt.
    pub enum Error {
/// Accessing the GPIO peripheral returned an error.
///
/// Some of these errors can be fixed by changing file permissions, or upgrading
/// to a newer version of Raspbian.
        GPIO(err: GPIOError) { description(err.description()) from() }
    }
}

/// Result type returned from methods that can have `blinkt::Error`s.
pub type Result<T> = result::Result<T, Error>;

#[derive(Debug, Copy, Clone)]
struct Pixel {
    red: u8,
    green: u8,
    blue: u8,
    brightness: u8,
}

impl Default for Pixel {
    fn default() -> Pixel {
        Pixel {
            red: 0,
            green: 0,
            blue: 0,
            brightness: DEFAULT_BRIGHTNESS,
        }
    }
}

/// Interface for a Blinkt! or any similar APA102 strips/boards.
///
/// By default, Blinkt is set up to communicate with an 8-pixel board through
/// data pin 23 and clock pin 24. These settings can be changed to support
/// alternate configurations.
pub struct Blinkt {
    gpio: GPIO,
    pixels: Vec<Pixel>,
    clear_on_drop: bool,
    pin_data: u8,
    pin_clock: u8,
    endframe_pulses: usize,
}

impl Blinkt {
    /// Creates a new `Blinkt` using the default settings for a Pimoroni
    /// Blinkt! board.
    ///
    /// This sets the data pin to 23, the clock pin to 24, and number of pixels
    /// to 8.
    pub fn new() -> Result<Blinkt> {
        Blinkt::with_settings(DAT, CLK, NUM_PIXELS)
    }

    /// Creates a new `Blinkt` using custom settings for the data pin, clock
    /// pin, and number of pixels.
    pub fn with_settings(pin_data: u8, pin_clock: u8, num_pixels: usize) -> Result<Blinkt> {
        // GPIO init might fail with an error the user could solve
        let mut gpio = try!(GPIO::new());

        gpio.set_mode(pin_data, Mode::Output);
        gpio.write(pin_data, Level::Low);
        gpio.set_mode(pin_clock, Mode::Output);
        gpio.write(pin_clock, Level::Low);

        Ok(Blinkt {
            gpio: gpio,
            pixels: vec![Pixel::default(); num_pixels],
            clear_on_drop: true,
            pin_data: pin_data,
            pin_clock: pin_clock,
            endframe_pulses: ((num_pixels as f32 * 0.5) + 0.5) as usize,
        })
    }

    /// When enabled, clears all pixels when the `Blinkt` goes out of scope.
    ///
    /// Drop methods aren't called when a program is abnormally terminated,
    /// for instance when a user presses Ctrl-C, and the SIGINT signal isn't
    /// caught. You'll either have to catch those using crates such as
    /// `simple_signal`, or manually call `cleanup()`.
    ///
    /// Enabled by default.
    pub fn set_clear_on_drop(&mut self, clear_on_drop: bool) {
        self.clear_on_drop = clear_on_drop;
    }

    /// Changes the GPIO pin mode for the data and clock pins back to their
    /// original state, and optionally clears all pixels.
    ///
    /// Normally, this method is automatically called when Blinkt goes out of
    /// scope, but you can manually call it to handle early/abnormal termination.
    /// After calling this method, any future calls to `show()` won't have any
    /// result.
    pub fn cleanup(&mut self) {
        if self.clear_on_drop {
            self.clear();
            self.show();
        }

        self.gpio.cleanup();
    }

    /// Sets the red, green and blue values for a single pixel in the local
    /// buffer.
    ///
    /// For an 8-pixel board, valid values for pixel are 0-7. Valid values
    /// for red, green and blue are 0-255.
    pub fn set_pixel(&mut self, pixel: usize, red: u8, green: u8, blue: u8) {
        if let Some(pixel) = self.pixels.get_mut(pixel) {
            pixel.red = red;
            pixel.green = green;
            pixel.blue = blue;
        }
    }

    /// Sets the red, green, blue and brightness values for a single pixel in
    /// the local buffer.
    ///
    /// For an 8-pixel board, valid values for pixel are 0-7. Valid
    /// values for red, green and blue are 0-255. Valid values for brightness
    /// are 0.0-1.0, which is converted to a 5-bit value.
    pub fn set_pixel_rgbb(&mut self, pixel: usize, red: u8, green: u8, blue: u8, brightness: f32) {
        if let Some(pixel) = self.pixels.get_mut(pixel) {
            pixel.red = red;
            pixel.green = green;
            pixel.blue = blue;
            pixel.brightness = (31.0 * if brightness > 1.0 { 1.0 } else if brightness < 0.0 { 0.0 } else { brightness }) as u8;
        }
    }

    /// Sets the brightness value for a single pixel in the local buffer.
    ///
    /// For an 8-pixel board, valid values for pixel are 0-7. Valid
    /// values for brightness are 0.0-1.0, which is converted to a
    /// 5-bit value.
    pub fn set_pixel_brightness(&mut self, pixel: usize, brightness: f32) {
        if let Some(pixel) = self.pixels.get_mut(pixel) {
            pixel.brightness = (31.0 * if brightness > 1.0 { 1.0 } else if brightness < 0.0 { 0.0 } else { brightness }) as u8;
        }
    }

    /// Sets the red, green and blue values for all pixels in the local buffer.
    ///
    /// Valid values for red, green and blue are 0-255.
    pub fn set_all_pixels(&mut self, red: u8, green: u8, blue: u8) {
        for pixel in &mut self.pixels {
            pixel.red = red;
            pixel.green = green;
            pixel.blue = blue;
        }
    }

    /// Sets the red, green, blue and brightness values for all pixels in the
    /// local buffer.
    ///
    /// Valid values for red, green and blue are 0-255. Valid values for
    /// brightness are 0.0-1.0, which is converted to a 5-bit value.
    pub fn set_all_pixels_rgbb(&mut self, red: u8, green: u8, blue: u8, brightness: f32) {
        let brightness: u8 = (31.0 * if brightness > 1.0 { 1.0 } else if brightness < 0.0 { 0.0 } else { brightness }) as u8;
        for pixel in &mut self.pixels {
            pixel.red = red;
            pixel.green = green;
            pixel.blue = blue;
            pixel.brightness = brightness;
        }
    }

    /// Sets the brightness value for all pixels in the local buffer.
    ///
    /// Valid values for brightness are 0.0-1.0, which is converted to a 5-bit
    /// value.
    pub fn set_all_pixels_brightness(&mut self, brightness: f32) {
        let brightness: u8 = (31.0 * if brightness > 1.0 { 1.0 } else if brightness < 0.0 { 0.0 } else { brightness }) as u8;
        for pixel in &mut self.pixels {
            pixel.brightness = brightness;
        }
    }

    /// Sets the red, green and blue values to 0 for all pixels in the local
    /// buffer.
    pub fn clear(&mut self) {
        self.set_all_pixels(0, 0, 0);
    }

    /// Sends the contents of the local buffer to the pixels, updating their
    /// LED colors and brightness.
    pub fn show(&self) {
        // Start frame (32x0)
        self.write_byte(0);
        self.write_byte(0);
        self.write_byte(0);
        self.write_byte(0);

        // LED frames
        for pixel in &self.pixels {
            self.write_byte(0b11100000 | pixel.brightness); // 3-bit header + 5-bit brightness
            self.write_byte(pixel.blue);
            self.write_byte(pixel.green);
            self.write_byte(pixel.red);
        }

        // We send another start frame immediately after our end frame, because
        // the APA102 version with a smaller, darker die, won't update the
        // pixels until it receives the next start frame. We still start show()
        // with a start frame, basically sending it twice, in case the user
        // connects a Blinkt! while the code is already running. This workaround
        // is compatible with both the normal and the 'different' APA102.
        self.gpio.write(self.pin_data, Level::Low);
        for _ in 0..32 + self.endframe_pulses {
            self.gpio.write(self.pin_clock, Level::High);
            self.gpio.write(self.pin_clock, Level::Low);
        }
    }

    fn write_byte(&self, byte: u8) {
        for n in 0..8 {
            if (byte & (1 << (7 - n))) > 0 {
                self.gpio.write(self.pin_data, Level::High);
            } else {
                self.gpio.write(self.pin_data, Level::Low);
            }

            self.gpio.write(self.pin_clock, Level::High);
            self.gpio.write(self.pin_clock, Level::Low);
        }
    }
}

impl Drop for Blinkt {
    fn drop(&mut self) {
        self.cleanup();
    }
}

#[test]
fn test_new() {
    let mut blinkt = match Blinkt::new() {
        // GPIO errors are acceptable, since they're likely caused by outside
        // distro/filesystem issues.
        Err(Error::GPIO(_)) => return,
        Ok(blinkt) => blinkt,
    };

    blinkt.set_clear_on_drop(false);
}
<|endoftext|>


<commit_before>// 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/.

#![feature(box_patterns, num_bits_bytes)]

extern crate byteorder;

pub mod types;
pub mod values;
pub mod decoder;
pub mod encoder;

#[cfg(test)]
extern crate rustc_serialize;

#[cfg(feature="arbitraries")]
extern crate quickcheck;

#[cfg(feature="arbitraries")]
extern crate rand;

#[cfg(feature="arbitraries")]
pub mod arbitraries;
<commit_msg>Re-export most common types.<commit_after>// 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/.

#![feature(box_patterns, num_bits_bytes)]

extern crate byteorder;

pub mod types;
pub mod values;
pub mod decoder;
pub mod encoder;

pub use decoder::{Decoder, DecodeError, DecodeResult, Config};
pub use encoder::{Encoder, EncodeError, EncodeResult};

#[cfg(test)]
extern crate rustc_serialize;

#[cfg(feature="arbitraries")]
extern crate quickcheck;

#[cfg(feature="arbitraries")]
extern crate rand;

#[cfg(feature="arbitraries")]
pub mod arbitraries;
<|endoftext|>


<commit_before>#![feature(drain)]
#![feature(plugin)]
#![plugin(phf_macros)]

extern crate phf;
extern crate itertools;
extern crate unicode_segmentation;
extern crate unicode_normalization;
extern crate rustc_serialize;

mod utils;
mod suffix;
mod nickname;
mod title;
mod surname;
mod namecase;
mod namepart;

use itertools::Itertools;
use utils::*;
use namepart::{NamePart, Location};

#[derive(RustcDecodable, RustcEncodable)]
pub struct Name {
  pub given_name: Option<String>,
  pub surname: String,
  pub middle_names: Option<String>,
  pub first_initial: char,
  pub middle_initials: Option<String>,
}

// Strip suffixes and titles, and find the start of the surname.
// These tasks are intrinsically connected because commas may indicate
// either a sort-ordered surname ("Smith, John") or a suffix ("John Smith, esq")
//
// This is where the meat of the parsing takes place
fn name_words_and_surname_index(name: &str, mixed_case: bool) -> (Vec<NamePart>, usize) {
    let mut words: Vec<NamePart> = Vec::new();
    let mut postfixes: Vec<NamePart> = Vec::new();
    let mut surname_index = 0;
    let mut found_first_name_or_initial = false;

    // Separate comma-separated titles and suffixes, then flip remaining words
    // around remaining comma, if any
    for (i, part) in name.split(",").enumerate() {
        if i == 0 || words.is_empty() {
            // We're in the surname part (if the format is "Smith, John"),
            // or the only actual name part (if the format is "John Smith,
            // esq." or just "John Smith")
            words.extend(NamePart::all_from_text(part, mixed_case, Location::End));
            if words.is_empty() { continue }

            // Check for title as prefix (e.g. "Dr. John Smith" or "Right Hon.
            // John Smith"); finding a prefix title means the next word is a
            // first name or initial (we don't support "Dr. Smith, John")
            let mut prefix_len = words.len() - 1;
            while prefix_len > 0 && !found_first_name_or_initial {
                found_first_name_or_initial = {
                    let next_word = &words[prefix_len];
                    if words.len() - prefix_len <= 1 && words[prefix_len-1].is_initials() {
                        false
                    }
                    else {
                        // If there is only one word after the prefix, e.g. "DR SMITH",
                        // given prefix of "DR", we treat ambiguous strings like "DR"
                        // as more likely to be initials than a title (there are no
                        // similarly ambiguous given names among our title word list)
                        (next_word.is_namelike() || next_word.is_initials()) &&
                            title::is_prefix_title(&words[0..prefix_len])
                    }
                };

                if found_first_name_or_initial {
                    words.drain(0..prefix_len);
                }

                prefix_len -= 1;
            }

            // Strip non-comma-separated titles & suffixes (e.g. "John Smith Jr.")
            let postfix_position = words.iter().skip(1).position( |word|
                suffix::is_suffix(&word) || title::is_postfix_title(&word)
            );
            if postfix_position.is_some() {
                let range = (postfix_position.unwrap() + 1)..words.len(); // Off-by-one since we skipped the first word
                postfixes.extend(words.drain(range));
            }

            if !found_first_name_or_initial {
                found_first_name_or_initial = surname::find_surname_index(&*words) > 0;
            }
        }
        else if found_first_name_or_initial {
            // We already found the full name, so this is a comma-separated
            // postfix title or suffix
            postfixes.extend(NamePart::all_from_text(part, mixed_case, Location::End));
        }
        else {
            // We already processed one comma-separated part, which may
            // have been the surname (if this is the given name), or the full
            // name (if this is a suffix or title)
            let mut given_middle_or_postfix_words: Vec<NamePart> =
                NamePart::all_from_text(part, mixed_case, Location::Start).collect();
            if given_middle_or_postfix_words.is_empty() { continue }

            // Check for (unusual) formats like "Smith, Dr. John M."
            if !found_first_name_or_initial && given_middle_or_postfix_words.len() > 1 {
                let mut prefix_len = given_middle_or_postfix_words.len() - 1;
                while prefix_len > 0 && !found_first_name_or_initial {
                    found_first_name_or_initial = {
                        let next_word = &given_middle_or_postfix_words[prefix_len];
                        (next_word.is_namelike() || next_word.is_initials()) &&
                            title::is_prefix_title(&given_middle_or_postfix_words[0..prefix_len])
                    };

                    if found_first_name_or_initial {
                        given_middle_or_postfix_words.drain(0..prefix_len);
                    }

                    prefix_len -= 1;
                }
            }

            // Check for (more common) formats like "Smith, John" or "Smith, J. M."
            if !found_first_name_or_initial {
                let word = given_middle_or_postfix_words.first().unwrap();
                if word.is_namelike() {
                    found_first_name_or_initial = true;
                } else if word.is_initials() {
                    // Handle a special case like "Ben Smith, II" or "John E Smith,
                    // III", where we might have mistakenly classified the whole
                    // first comma-separated part as a surname (due to the "ben"
                    // prefix and "e" conjunction rules respectively)
                    found_first_name_or_initial = words.len() == 1 ||
                        given_middle_or_postfix_words.iter().any( |word|
                            !suffix::is_suffix(word) && !title::is_postfix_title(word)
                        );
                }
            }

            // Now we've decided: either this is the given name or first initial,
            // in which case we put it in front, or it's a suffix or title
            if found_first_name_or_initial {
                // Check for (unusual) formats like "Smith, Dr. John Jr." (but
                // only look for suffixes or abbreviations, anything title-like
                // that might be a name or initials is more likely the latter)
                let postfix_position = given_middle_or_postfix_words.iter().position( |word|
                    word.is_abbreviation() || suffix::is_suffix(&word)
                );

                if postfix_position.is_some() {
                    let range = postfix_position.unwrap()..given_middle_or_postfix_words.len();
                    postfixes.extend(given_middle_or_postfix_words.drain(range));
                }

                let surname_words = words;
                words = given_middle_or_postfix_words;
                surname_index = words.len();
                words.extend(surname_words);
            }
            else {
                postfixes.extend(given_middle_or_postfix_words);
            }
        }
    }

    // If there are two or fewer words, e.g. "JOHN MA", we treat
    // ambiguous strings like "MA" as surnames rather than titles
    // (not initials, which should only be at the end of the input
    // if they are comma-separated, and we already handled that case)
    if words.len() < 2 && !postfixes.is_empty() && postfixes[0].is_namelike() {
        words.push(postfixes.remove(0));
    }

    if words.len() < 2 {
        // Failed parse
        return (words, 0);
    }

    if surname_index <= 0 || surname_index >= words.len() {
        // We didn't get the surname from the formatting (e.g. "Smith, John"),
        // so we have to guess it
        surname_index = surname::find_surname_index(&words[1..]) + 1;
    }

    (words, surname_index)
}

impl Name {
    pub fn parse(name: &str) -> Option<Name> {
        if !name.chars().any(char::is_alphabetic) {
            return None
        }

        let mixed_case = is_mixed_case(name);
        let name = nickname::strip_nickname(name);
        let (words, surname_index) = name_words_and_surname_index(&name, mixed_case);

        if words.len() < 2 {
            // We need at least a first and last name, or we can't tell which we have
            return None;
        }
        else if words[surname_index..].iter().all( |w| !w.is_namelike() ) {
            // Looks like a bad parse, since the surname doesn't make sense
            return None;
        }

        // Take the remaining words, and strip out the initials (if present;
        // only allow one block of initials) and the first name (if present),
        // and whatever's left are the middle names
        let mut given_name: Option<String> = None;
        let mut middle_names: Vec<&str> = Vec::new();
        let mut middle_initials = String::new();

        for (i, word) in words[0..surname_index].iter().enumerate() {
            if word.is_initials() {
                let start = if i == 0 { 1 } else { 0 };
                if word.chars > start {
                    middle_initials.extend(
                        word.word
                            .chars()
                            .filter( |c| c.is_alphabetic() )
                            .skip(start)
                            .filter_map( |w| w.to_uppercase().next() ));
                }
            } else if given_name.is_none() {
                given_name = Some(word.namecased.to_string());
            } else {
                middle_names.push(&*word.namecased);
                middle_initials.push(word.initial());
            }
        }

        let middle_names =
            if middle_names.is_empty() {
                None
            } else {
                Some(middle_names.join(" "))
            };

        let middle_initials =
            if middle_initials.is_empty() {
                None
            } else {
                Some(middle_initials)
            };

        let surname = words[surname_index..]
            .iter()
            .map( |w| &*w.namecased )
            .join(" ");

        Some(Name {
            first_initial: words[0].initial(),
            given_name: given_name,
            surname: surname,
            middle_names: middle_names,
            middle_initials: middle_initials,
        })
    }

    pub fn display(&self) -> String {
        match self.given_name {
            Some(ref name) => {
                format!("{} {}", name, self.surname)
            }
            None => {
                format!("{}. {}", self.first_initial, self.surname)
            }
        }
    }
}
<commit_msg>DRY-up prefix title stripping<commit_after>#![feature(drain)]
#![feature(plugin)]
#![plugin(phf_macros)]

extern crate phf;
extern crate itertools;
extern crate unicode_segmentation;
extern crate unicode_normalization;
extern crate rustc_serialize;

mod utils;
mod suffix;
mod nickname;
mod title;
mod surname;
mod namecase;
mod namepart;

use itertools::Itertools;
use utils::*;
use namepart::{NamePart, Location};

#[derive(RustcDecodable, RustcEncodable)]
pub struct Name {
  pub given_name: Option<String>,
  pub surname: String,
  pub middle_names: Option<String>,
  pub first_initial: char,
  pub middle_initials: Option<String>,
}

fn strip_prefix_title(words: &mut Vec<NamePart>, try_to_keep_two_words: bool) -> bool {
    let mut prefix_len = words.len() - 1;
    while prefix_len > 0 {
        let found_prefix = {
            let next_word = &words[prefix_len];
            if try_to_keep_two_words && words.len() - prefix_len <= 1 && words[prefix_len-1].is_initials() {
                // If there is only one word after the prefix, e.g. "DR SMITH",
                // given prefix of "DR", we treat ambiguous strings like "DR"
                // as more likely to be initials than a title (there are no
                // similarly ambiguous given names among our title word list)
                false
            }
            else {
                (next_word.is_namelike() || next_word.is_initials()) &&
                    title::is_prefix_title(&words[0..prefix_len])
            }
        };

        if found_prefix {
            words.drain(0..prefix_len);
            return true;
        }

        prefix_len -= 1;
    }

    false
}

// Strip suffixes and titles, and find the start of the surname.
// These tasks are intrinsically connected because commas may indicate
// either a sort-ordered surname ("Smith, John") or a suffix ("John Smith, esq")
//
// This is where the meat of the parsing takes place
fn name_words_and_surname_index(name: &str, mixed_case: bool) -> (Vec<NamePart>, usize) {
    let mut words: Vec<NamePart> = Vec::new();
    let mut postfixes: Vec<NamePart> = Vec::new();
    let mut surname_index = 0;
    let mut found_first_name_or_initial = false;

    // Separate comma-separated titles and suffixes, then flip remaining words
    // around remaining comma, if any
    for (i, part) in name.split(",").enumerate() {
        if i == 0 || words.is_empty() {
            // We're in the surname part (if the format is "Smith, John"),
            // or the only actual name part (if the format is "John Smith,
            // esq." or just "John Smith")
            words.extend(NamePart::all_from_text(part, mixed_case, Location::End));
            if words.is_empty() { continue }

            // Check for title as prefix (e.g. "Dr. John Smith" or "Right Hon.
            // John Smith"); finding a prefix title means the next word is a
            // first name or initial (we don't support "Dr. Smith, John")
            if words.len() > 1 {
                found_first_name_or_initial = strip_prefix_title(&mut words, true);
            }

            // Strip non-comma-separated titles & suffixes (e.g. "John Smith Jr.")
            let postfix_position = words.iter().skip(1).position( |word|
                suffix::is_suffix(&word) || title::is_postfix_title(&word)
            );
            if postfix_position.is_some() {
                let range = (postfix_position.unwrap() + 1)..words.len(); // Off-by-one since we skipped the first word
                postfixes.extend(words.drain(range));
            }

            if !found_first_name_or_initial {
                found_first_name_or_initial = surname::find_surname_index(&*words) > 0;
            }
        }
        else if found_first_name_or_initial {
            // We already found the full name, so this is a comma-separated
            // postfix title or suffix
            postfixes.extend(NamePart::all_from_text(part, mixed_case, Location::End));
        }
        else {
            // We already processed one comma-separated part, which may
            // have been the surname (if this is the given name), or the full
            // name (if this is a suffix or title)
            let mut given_middle_or_postfix_words: Vec<NamePart> =
                NamePart::all_from_text(part, mixed_case, Location::Start).collect();
            if given_middle_or_postfix_words.is_empty() { continue }

            // Check for (unusual) formats like "Smith, Dr. John M."
            if !found_first_name_or_initial && given_middle_or_postfix_words.len() > 1 {
                found_first_name_or_initial = strip_prefix_title(&mut given_middle_or_postfix_words, false);
            }

            // Check for (more common) formats like "Smith, John" or "Smith, J. M."
            if !found_first_name_or_initial {
                let word = given_middle_or_postfix_words.first().unwrap();
                if word.is_namelike() {
                    found_first_name_or_initial = true;
                } else if word.is_initials() {
                    // Handle a special case like "Ben Smith, II" or "John E Smith,
                    // III", where we might have mistakenly classified the whole
                    // first comma-separated part as a surname (due to the "ben"
                    // prefix and "e" conjunction rules respectively)
                    found_first_name_or_initial = words.len() == 1 ||
                        given_middle_or_postfix_words.iter().any( |word|
                            !suffix::is_suffix(word) && !title::is_postfix_title(word)
                        );
                }
            }

            // Now we've decided: either this is the given name or first initial,
            // in which case we put it in front, or it's a suffix or title
            if found_first_name_or_initial {
                // Check for (unusual) formats like "Smith, Dr. John Jr." (but
                // only look for suffixes or abbreviations, anything title-like
                // that might be a name or initials is more likely the latter)
                let postfix_position = given_middle_or_postfix_words.iter().position( |word|
                    word.is_abbreviation() || suffix::is_suffix(&word)
                );

                if postfix_position.is_some() {
                    let range = postfix_position.unwrap()..given_middle_or_postfix_words.len();
                    postfixes.extend(given_middle_or_postfix_words.drain(range));
                }

                let surname_words = words;
                words = given_middle_or_postfix_words;
                surname_index = words.len();
                words.extend(surname_words);
            }
            else {
                postfixes.extend(given_middle_or_postfix_words);
            }
        }
    }

    // If there are two or fewer words, e.g. "JOHN MA", we treat
    // ambiguous strings like "MA" as surnames rather than titles
    // (not initials, which should only be at the end of the input
    // if they are comma-separated, and we already handled that case)
    if words.len() < 2 && !postfixes.is_empty() && postfixes[0].is_namelike() {
        words.push(postfixes.remove(0));
    }

    if words.len() < 2 {
        // Failed parse
        return (words, 0);
    }

    if surname_index <= 0 || surname_index >= words.len() {
        // We didn't get the surname from the formatting (e.g. "Smith, John"),
        // so we have to guess it
        surname_index = surname::find_surname_index(&words[1..]) + 1;
    }

    (words, surname_index)
}

impl Name {
    pub fn parse(name: &str) -> Option<Name> {
        if !name.chars().any(char::is_alphabetic) {
            return None
        }

        let mixed_case = is_mixed_case(name);
        let name = nickname::strip_nickname(name);
        let (words, surname_index) = name_words_and_surname_index(&name, mixed_case);

        if words.len() < 2 {
            // We need at least a first and last name, or we can't tell which we have
            return None;
        }
        else if words[surname_index..].iter().all( |w| !w.is_namelike() ) {
            // Looks like a bad parse, since the surname doesn't make sense
            return None;
        }

        // Take the remaining words, and strip out the initials (if present;
        // only allow one block of initials) and the first name (if present),
        // and whatever's left are the middle names
        let mut given_name: Option<String> = None;
        let mut middle_names: Vec<&str> = Vec::new();
        let mut middle_initials = String::new();

        for (i, word) in words[0..surname_index].iter().enumerate() {
            if word.is_initials() {
                let start = if i == 0 { 1 } else { 0 };
                if word.chars > start {
                    middle_initials.extend(
                        word.word
                            .chars()
                            .filter( |c| c.is_alphabetic() )
                            .skip(start)
                            .filter_map( |w| w.to_uppercase().next() ));
                }
            } else if given_name.is_none() {
                given_name = Some(word.namecased.to_string());
            } else {
                middle_names.push(&*word.namecased);
                middle_initials.push(word.initial());
            }
        }

        let middle_names =
            if middle_names.is_empty() {
                None
            } else {
                Some(middle_names.join(" "))
            };

        let middle_initials =
            if middle_initials.is_empty() {
                None
            } else {
                Some(middle_initials)
            };

        let surname = words[surname_index..]
            .iter()
            .map( |w| &*w.namecased )
            .join(" ");

        Some(Name {
            first_initial: words[0].initial(),
            given_name: given_name,
            surname: surname,
            middle_names: middle_names,
            middle_initials: middle_initials,
        })
    }

    pub fn display(&self) -> String {
        match self.given_name {
            Some(ref name) => {
                format!("{} {}", name, self.surname)
            }
            None => {
                format!("{}. {}", self.first_initial, self.surname)
            }
        }
    }
}
<|endoftext|>


<commit_before>//! Postgres support for the `r2d2` connection pool.
#![doc(html_root_url="https://sfackler.github.io/r2d2-postgres/doc")]
#![feature(core)]
#![warn(missing_docs)]
extern crate r2d2;
extern crate postgres;

use std::error;
use std::error::Error as _StdError;
use std::fmt;
use postgres::{IntoConnectParams, SslMode};

/// A unified enum of errors returned by postgres::Connection
#[derive(Clone, Debug)]
pub enum Error {
    /// A postgres::ConnectError
    Connect(postgres::ConnectError),
    /// An postgres::Error
    Other(postgres::Error),
}

impl fmt::Display for Error {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        write!(fmt, "{}: {}", self.description(), self.cause().unwrap())
    }
}

impl error::Error for Error {
    fn description(&self) -> &str {
        match *self {
            Error::Connect(_) => "Error opening a connection",
            Error::Other(_) => "Error communicating with server",
        }
    }

    fn cause(&self) -> Option<&error::Error> {
        match *self {
            Error::Connect(ref err) => Some(err as &error::Error),
            Error::Other(ref err) => Some(err as &error::Error),
        }
    }
}

/// An `r2d2::ConnectionManager` for `postgres::Connection`s.
///
/// ## Example
///
/// ```rust,no_run
/// #![allow(unstable)]
/// extern crate r2d2;
/// extern crate r2d2_postgres;
/// extern crate postgres;
///
/// use std::sync::Arc;
/// use std::default::Default;
/// use std::thread::Thread;
/// use postgres::SslMode;
/// use r2d2_postgres::PostgresConnectionManager;
///
/// fn main() {
///     let config = Default::default();
///     let manager = PostgresConnectionManager::new("postgres://postgres@localhost",
///                                                  SslMode::None);
///     let error_handler = Box::new(r2d2::LoggingErrorHandler);
///     let pool = Arc::new(r2d2::Pool::new(config, manager, error_handler).unwrap());
///
///     for i in 0..10i32 {
///         let pool = pool.clone();
///         Thread::spawn(move || {
///             let conn = pool.get().unwrap();
///             conn.execute("INSERT INTO foo (bar) VALUES ($1)", &[&i]).unwrap();
///         });
///     }
/// }
/// ```
pub struct PostgresConnectionManager {
    params: Result<postgres::ConnectParams, postgres::ConnectError>,
    ssl_mode: SslMode,
}

impl fmt::Debug for PostgresConnectionManager {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        write!(fmt, "PostgresConnectionManager {{ parameters: {:?}, ssl_mode: {:?} }}",
               self.params, self.ssl_mode)
    }
}

impl PostgresConnectionManager {
    /// Creates a new `PostgresConnectionManager`.
    ///
    /// See `postgres::Connection::connect` for a description of the parameter
    /// types.
    pub fn new<T: IntoConnectParams>(params: T, ssl_mode: SslMode) -> PostgresConnectionManager {
        PostgresConnectionManager {
            params: params.into_connect_params(),
            ssl_mode: ssl_mode,
        }
    }
}

impl r2d2::ConnectionManager for PostgresConnectionManager {
    type Connection = postgres::Connection;
    type Error = Error;

    fn connect(&self) -> Result<postgres::Connection, Error> {
        match self.params {
            Ok(ref p) => {
                postgres::Connection::connect(p.clone(), &self.ssl_mode).map_err(Error::Connect)
            }
            Err(ref e) => Err(Error::Connect(e.clone()))
        }
    }

    fn is_valid(&self, conn: &mut postgres::Connection) -> Result<(), Error> {
        conn.batch_execute("").map_err(Error::Other)
    }

    fn has_broken(&self, conn: &mut postgres::Connection) -> bool {
        conn.is_desynchronized()
    }
}
<commit_msg>Fix warnings<commit_after>//! Postgres support for the `r2d2` connection pool.
#![doc(html_root_url="https://sfackler.github.io/r2d2-postgres/doc")]
#![warn(missing_docs)]
extern crate r2d2;
extern crate postgres;

use std::error;
use std::error::Error as _StdError;
use std::fmt;
use postgres::{IntoConnectParams, SslMode};

/// A unified enum of errors returned by postgres::Connection
#[derive(Clone, Debug)]
pub enum Error {
    /// A postgres::ConnectError
    Connect(postgres::ConnectError),
    /// An postgres::Error
    Other(postgres::Error),
}

impl fmt::Display for Error {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        write!(fmt, "{}: {}", self.description(), self.cause().unwrap())
    }
}

impl error::Error for Error {
    fn description(&self) -> &str {
        match *self {
            Error::Connect(_) => "Error opening a connection",
            Error::Other(_) => "Error communicating with server",
        }
    }

    fn cause(&self) -> Option<&error::Error> {
        match *self {
            Error::Connect(ref err) => Some(err as &error::Error),
            Error::Other(ref err) => Some(err as &error::Error),
        }
    }
}

/// An `r2d2::ConnectionManager` for `postgres::Connection`s.
///
/// ## Example
///
/// ```rust,no_run
/// #![allow(unstable)]
/// extern crate r2d2;
/// extern crate r2d2_postgres;
/// extern crate postgres;
///
/// use std::sync::Arc;
/// use std::default::Default;
/// use std::thread;
/// use postgres::SslMode;
/// use r2d2_postgres::PostgresConnectionManager;
///
/// fn main() {
///     let config = Default::default();
///     let manager = PostgresConnectionManager::new("postgres://postgres@localhost",
///                                                  SslMode::None);
///     let error_handler = Box::new(r2d2::LoggingErrorHandler);
///     let pool = Arc::new(r2d2::Pool::new(config, manager, error_handler).unwrap());
///
///     for i in 0..10i32 {
///         let pool = pool.clone();
///         thread::spawn(move || {
///             let conn = pool.get().unwrap();
///             conn.execute("INSERT INTO foo (bar) VALUES ($1)", &[&i]).unwrap();
///         });
///     }
/// }
/// ```
pub struct PostgresConnectionManager {
    params: Result<postgres::ConnectParams, postgres::ConnectError>,
    ssl_mode: SslMode,
}

impl fmt::Debug for PostgresConnectionManager {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        write!(fmt, "PostgresConnectionManager {{ parameters: {:?}, ssl_mode: {:?} }}",
               self.params, self.ssl_mode)
    }
}

impl PostgresConnectionManager {
    /// Creates a new `PostgresConnectionManager`.
    ///
    /// See `postgres::Connection::connect` for a description of the parameter
    /// types.
    pub fn new<T: IntoConnectParams>(params: T, ssl_mode: SslMode) -> PostgresConnectionManager {
        PostgresConnectionManager {
            params: params.into_connect_params(),
            ssl_mode: ssl_mode,
        }
    }
}

impl r2d2::ConnectionManager for PostgresConnectionManager {
    type Connection = postgres::Connection;
    type Error = Error;

    fn connect(&self) -> Result<postgres::Connection, Error> {
        match self.params {
            Ok(ref p) => {
                postgres::Connection::connect(p.clone(), &self.ssl_mode).map_err(Error::Connect)
            }
            Err(ref e) => Err(Error::Connect(e.clone()))
        }
    }

    fn is_valid(&self, conn: &mut postgres::Connection) -> Result<(), Error> {
        conn.batch_execute("").map_err(Error::Other)
    }

    fn has_broken(&self, conn: &mut postgres::Connection) -> bool {
        conn.is_desynchronized()
    }
}
<|endoftext|>


<commit_before>extern crate libc;
// export it for now

use libc::{c_int, c_char, c_void};
use std::ffi::CString;
use std::ptr;

pub mod ffi;
pub use ffi::{IPaddress, _TCPsocket, _SDLNet_SocketSet, _SDLNet_GenericSocket};

pub struct TCPsocket {
    opaquePtr: *mut _TCPsocket,
}
pub struct SocketSet {
    opaquePtr: *mut _SDLNet_SocketSet,
}

pub fn init() -> () { unsafe { ffi::SDLNet_Init(); } }
pub fn quit() -> () { unsafe { ffi::SDLNet_Quit(); } }
pub fn get_error() -> String {
    unsafe {
        let raw = &ffi::SDLNet_GetError();
        std::str::from_utf8(std::ffi::c_str_to_bytes(raw)).unwrap().to_string()
    }
}

pub fn become_host(port: u16) -> Option<ffi::IPaddress> {
    let mut address = ffi::IPaddress { host: 0, port: 0};
    let mut result = 0;
    unsafe {
        result = ffi::SDLNet_ResolveHost(&mut address, ptr::null() , port)
    }
    if (result == 0){
        Some(address)
    } else {
        None
    }
}

pub fn resolve_host(host: &str, port: u16) -> Option<ffi::IPaddress> {
    let mut address = ffi::IPaddress { host: 0, port: 0 };
    let mut result = 0;
    unsafe {
        result = ffi::SDLNet_ResolveHost(&mut address, CString::from_slice(host.as_bytes()).as_ptr(), port)
    }
    if (result == 0) {
        Some(address)
    } else {
        None
    }
}

pub fn resolve_ip(mut address: IPaddress) -> String {
    unsafe {
        let raw = &ffi::SDLNet_ResolveIP(&mut address);
        std::str::from_utf8(std::ffi::c_str_to_bytes(raw)).unwrap().to_string()
    }
}

pub fn tcp_open() -> Option<TCPsocket> {
    let mut address = ffi::IPaddress { host: 0, port: 0};
    unsafe {
        let socket = ffi::SDLNet_TCP_Open(&mut address);
        if socket as *const _TCPsocket != ptr::null() {
            Some(TCPsocket { opaquePtr: socket })
        } else {
            None
        }
    }
}

pub fn tcp_close(sock: &TCPsocket) -> () {
    unsafe {
        ffi::SDLNet_TCP_Close(sock.opaquePtr)
    }
}

pub fn tcp_accept<'a>(server: &'a TCPsocket) -> TCPsocket {
    unsafe {
        TCPsocket { opaquePtr: ffi::SDLNet_TCP_Accept(server.opaquePtr) }
    }
}

pub fn tcp_get_peer_address<'a>(sock: &'a TCPsocket) -> Box<*mut IPaddress> {
    unsafe {
        Box::new(ffi::SDLNet_TCP_GetPeerAddress(sock.opaquePtr))
    }
}

pub fn tcp_send<'a>(sock: &'a TCPsocket, data: &[u8]) -> () {
    unsafe {
        ffi::SDLNet_TCP_Send(sock.opaquePtr, data.as_ptr() as *const c_void, data.len() as i32);
    }
}

pub fn tcp_recv<'a>(sock: &'a TCPsocket, maxlen: i32) -> Vec<u8> {
    let mut data: Vec<u8> = Vec::with_capacity(maxlen as usize);
    unsafe {
        let read_ammnt = ffi::SDLNet_TCP_Recv(sock.opaquePtr, data.as_mut_ptr() as *mut c_void, data.len() as i32);
        data.set_len(read_ammnt as usize);
    }
    data
}

pub fn alloc_socket_set(maxsockets: i32) -> SocketSet {
    unsafe {
        SocketSet { opaquePtr: ffi::SDLNet_AllocSocketSet(maxsockets) }
    }
}

pub fn free_socket_set(set: &SocketSet) -> () {
    unsafe {
        ffi::SDLNet_FreeSocketSet(set.opaquePtr);
    }
}

pub fn add_socket(set: &SocketSet, sock: &TCPsocket) -> i32 {
    unsafe {
        ffi::SDLNet_AddSocket(set.opaquePtr, sock.opaquePtr)
    }
}

// Maybe should take in the box here as it may get deleted.... not sure
pub fn del_socket(set: &SocketSet, sock: &TCPsocket) -> i32 {
    unsafe {
        ffi::SDLNet_DelSocket(set.opaquePtr, sock.opaquePtr)
    }
}

pub fn check_sockets(set: &SocketSet, timeout: u32) -> i32 {
    unsafe {
        ffi::SDLNet_CheckSockets(set.opaquePtr, timeout)
    }
}

pub fn socket_ready(sock: &TCPsocket) -> i32 {
    unsafe {
        ffi::SDLNet_SocketReady(sock.opaquePtr as *mut c_void)
    }
}
<commit_msg>Removed the other lifetimes. Were not necessary, just needed pointers (borrowed)<commit_after>extern crate libc;
// export it for now

use libc::{c_int, c_char, c_void};
use std::ffi::CString;
use std::ptr;

pub mod ffi;
pub use ffi::{IPaddress, _TCPsocket, _SDLNet_SocketSet, _SDLNet_GenericSocket};

pub struct TCPsocket {
    opaquePtr: *mut _TCPsocket,
}
pub struct SocketSet {
    opaquePtr: *mut _SDLNet_SocketSet,
}

pub fn init() -> () { unsafe { ffi::SDLNet_Init(); } }
pub fn quit() -> () { unsafe { ffi::SDLNet_Quit(); } }
pub fn get_error() -> String {
    unsafe {
        let raw = &ffi::SDLNet_GetError();
        std::str::from_utf8(std::ffi::c_str_to_bytes(raw)).unwrap().to_string()
    }
}

pub fn become_host(port: u16) -> Option<ffi::IPaddress> {
    let mut address = ffi::IPaddress { host: 0, port: 0};
    let mut result = 0;
    unsafe {
        result = ffi::SDLNet_ResolveHost(&mut address, ptr::null() , port)
    }
    if (result == 0){
        Some(address)
    } else {
        None
    }
}

pub fn resolve_host(host: &str, port: u16) -> Option<ffi::IPaddress> {
    let mut address = ffi::IPaddress { host: 0, port: 0 };
    let mut result = 0;
    unsafe {
        result = ffi::SDLNet_ResolveHost(&mut address, CString::from_slice(host.as_bytes()).as_ptr(), port)
    }
    if (result == 0) {
        Some(address)
    } else {
        None
    }
}

pub fn resolve_ip(mut address: IPaddress) -> String {
    unsafe {
        let raw = &ffi::SDLNet_ResolveIP(&mut address);
        std::str::from_utf8(std::ffi::c_str_to_bytes(raw)).unwrap().to_string()
    }
}

pub fn tcp_open() -> Option<TCPsocket> {
    let mut address = ffi::IPaddress { host: 0, port: 0};
    unsafe {
        let socket = ffi::SDLNet_TCP_Open(&mut address);
        if socket as *const _TCPsocket != ptr::null() {
            Some(TCPsocket { opaquePtr: socket })
        } else {
            None
        }
    }
}

pub fn tcp_close(sock: &TCPsocket) -> () {
    unsafe {
        ffi::SDLNet_TCP_Close(sock.opaquePtr)
    }
}

pub fn tcp_accept(server: &TCPsocket) -> TCPsocket {
    unsafe {
        TCPsocket { opaquePtr: ffi::SDLNet_TCP_Accept(server.opaquePtr) }
    }
}

pub fn tcp_get_peer_address(sock: &TCPsocket) -> Box<*mut IPaddress> {
    unsafe {
        Box::new(ffi::SDLNet_TCP_GetPeerAddress(sock.opaquePtr))
    }
}

pub fn tcp_send(sock: &TCPsocket, data: &[u8]) -> () {
    unsafe {
        ffi::SDLNet_TCP_Send(sock.opaquePtr, data.as_ptr() as *const c_void, data.len() as i32);
    }
}

pub fn tcp_recv(sock: &TCPsocket, maxlen: i32) -> Vec<u8> {
    let mut data: Vec<u8> = Vec::with_capacity(maxlen as usize);
    unsafe {
        let read_ammnt = ffi::SDLNet_TCP_Recv(sock.opaquePtr, data.as_mut_ptr() as *mut c_void, data.len() as i32);
        data.set_len(read_ammnt as usize);
    }
    data
}

pub fn alloc_socket_set(maxsockets: i32) -> SocketSet {
    unsafe {
        SocketSet { opaquePtr: ffi::SDLNet_AllocSocketSet(maxsockets) }
    }
}

pub fn free_socket_set(set: &SocketSet) -> () {
    unsafe {
        ffi::SDLNet_FreeSocketSet(set.opaquePtr);
    }
}

pub fn add_socket(set: &SocketSet, sock: &TCPsocket) -> i32 {
    unsafe {
        ffi::SDLNet_AddSocket(set.opaquePtr, sock.opaquePtr)
    }
}

// Maybe should take in the box here as it may get deleted.... not sure
pub fn del_socket(set: &SocketSet, sock: &TCPsocket) -> i32 {
    unsafe {
        ffi::SDLNet_DelSocket(set.opaquePtr, sock.opaquePtr)
    }
}

pub fn check_sockets(set: &SocketSet, timeout: u32) -> i32 {
    unsafe {
        ffi::SDLNet_CheckSockets(set.opaquePtr, timeout)
    }
}

pub fn socket_ready(sock: &TCPsocket) -> i32 {
    unsafe {
        ffi::SDLNet_SocketReady(sock.opaquePtr as *mut c_void)
    }
}
<|endoftext|>


<commit_before>#![feature(io, std_misc, path, core)]
#![cfg_attr(test, feature(fs))]

extern crate libc;

use std::cmp;
use std::ffi::AsOsStr;
use std::io;
use std::iter::IntoIterator;
use std::mem;
use std::num::Int;
use std::os::unix::{Fd, OsStrExt, AsRawFd};
use std::path::AsPath;

struct Inner(Fd);

impl Drop for Inner {
    fn drop(&mut self) {
        unsafe {
            libc::close(self.0);
        }
    }
}

impl Inner {
    unsafe fn new() -> io::Result<Inner> {
        let fd = libc::socket(libc::AF_UNIX, libc::SOCK_STREAM, 0);
        if fd < 0 {
            Err(io::Error::last_os_error())
        } else {
            Ok(Inner(fd))
        }
    }

}

unsafe fn sockaddr_un<P: AsPath + ?Sized>(path: &P) -> io::Result<libc::sockaddr_un> {
    let mut addr: libc::sockaddr_un = mem::zeroed();
    addr.sun_family = libc::AF_UNIX as libc::sa_family_t;

    let bytes = path.as_path().as_os_str().as_bytes();
    if bytes.len() > addr.sun_path.len() - 1 {
        return Err(io::Error::new(io::ErrorKind::InvalidInput,
                                  "path must be smaller than SUN_LEN",
                                  None));
    }
    for (dst, src) in addr.sun_path.iter_mut().zip(bytes.iter()) {
        *dst = *src as libc::c_char;
    }
    // null byte's already there because we zeroed the struct

    Ok(addr)
}

pub struct UnixStream {
    inner: Inner,
}

impl UnixStream {
    pub fn connect<P: AsPath + ?Sized>(path: &P) -> io::Result<UnixStream> {
        unsafe {
            let inner = try!(Inner::new());
            let addr = try!(sockaddr_un(path));

            let ret = libc::connect(inner.0,
                                    &addr as *const _ as *const _,
                                    mem::size_of::<libc::sockaddr_un>() as libc::socklen_t);
            if ret < 0 {
                Err(io::Error::last_os_error())
            } else {
                Ok(UnixStream {
                    inner: inner,
                })
            }
        }
    }
}

fn calc_len(buf: &[u8]) -> libc::size_t {
    cmp::min(<libc::size_t as Int>::max_value() as usize, buf.len()) as libc::size_t
}

impl io::Read for UnixStream {
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        let ret = unsafe {
            libc::recv(self.inner.0, buf.as_mut_ptr() as *mut _, calc_len(buf), 0)
        };

        if ret < 0 {
            Err(io::Error::last_os_error())
        } else {
            Ok(ret as usize)
        }
    }
}

impl io::Write for UnixStream {
    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
        let ret = unsafe {
            libc::send(self.inner.0, buf.as_ptr() as *const _, calc_len(buf), 0)
        };

        if ret < 0 {
            Err(io::Error::last_os_error())
        } else {
            Ok(ret as usize)
        }
    }

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

impl AsRawFd for UnixStream {
    fn as_raw_fd(&self) -> Fd {
        self.inner.0
    }
}

pub struct UnixListener {
    inner: Inner,
}

impl UnixListener {
    pub fn bind<P: AsPath + ?Sized>(path: &P) -> io::Result<UnixListener> {
        unsafe {
            let inner = try!(Inner::new());
            let addr = try!(sockaddr_un(path));

            let ret = libc::bind(inner.0,
                                 &addr as *const _ as *const _,
                                 mem::size_of::<libc::sockaddr_un>() as libc::socklen_t);
            if ret < 0 {
                return Err(io::Error::last_os_error());
            }

            let ret = libc::listen(inner.0, 128);
            if ret < 0 {
                Err(io::Error::last_os_error())
            } else {
                Ok(UnixListener {
                    inner: inner,
                })
            }
        }
    }

    pub fn accept(&self) -> io::Result<UnixStream> {
        unsafe {
            let ret = libc::accept(self.inner.0, 0 as *mut _, 0 as *mut _);
            if ret < 0 {
                Err(io::Error::last_os_error())
            } else {
                Ok(UnixStream {
                    inner: Inner(ret)
                })
            }
        }
    }

    pub fn iter<'a>(&'a self) -> Incoming<'a> {
        Incoming {
            listener: self
        }
    }
}

impl AsRawFd for UnixListener {
    fn as_raw_fd(&self) -> Fd {
        self.inner.0
    }
}

impl<'a> IntoIterator for &'a UnixListener {
    type Item = io::Result<UnixStream>;
    type IntoIter = Incoming<'a>;

    fn into_iter(self) -> Incoming<'a> {
        self.iter()
    }
}

pub struct Incoming<'a> {
    listener: &'a UnixListener,
}

impl<'a> Iterator for Incoming<'a> {
    type Item = io::Result<UnixStream>;

    fn next(&mut self) -> Option<io::Result<UnixStream>> {
        Some(self.listener.accept())
    }

    fn size_hint(&self) -> (usize, Option<usize>) {
        (Int::max_value(), None)
    }
}

#[cfg(test)]
mod test {
    use std::fs;
    use std::thread;
    use std::path::Path;
    use std::io;
    use std::io::prelude::*;

    use {UnixListener, UnixStream};

    macro_rules! or_panic {
        ($e:expr) => {
            match $e {
                Ok(e) => e,
                Err(e) => panic!("{}", e),
            }
        }
    }

    #[test]
    fn basic() {
        let socket_path = "unix_socket_test_basic";
        let msg1 = b"hello";
        let msg2 = b"world!";
        if Path::new(socket_path).exists() {
            or_panic!(fs::remove_file(socket_path));
        }

        let listener = or_panic!(UnixListener::bind(socket_path));
        let thread = thread::scoped(|| {
            let mut stream = or_panic!(listener.accept());
            let mut buf = [0; 5];
            or_panic!(stream.read(&mut buf));
            assert_eq!(msg1, buf);
            or_panic!(stream.write_all(msg2));
        });

        let mut stream = or_panic!(UnixStream::connect(socket_path));
        or_panic!(stream.write_all(msg1));
        let mut buf = vec![];
        or_panic!(stream.read_to_end(&mut buf));
        assert_eq!(msg2, buf);
        drop(stream);

        thread.join();

        or_panic!(fs::remove_file(socket_path));
    }

    #[test]
    fn iter() {
        let socket_path = "unix_socket_test_iter";
        if Path::new(socket_path).exists() {
            or_panic!(fs::remove_file(socket_path));
        }

        let listener = or_panic!(UnixListener::bind(socket_path));
        let thread = thread::scoped(|| {
            for stream in listener.iter().take(2) {
                let mut stream = or_panic!(stream);
                let mut buf = [0];
                or_panic!(stream.read(&mut buf));
            }
        });

        for _ in 0..2 {
            let mut stream = or_panic!(UnixStream::connect(socket_path));
            or_panic!(stream.write_all(&[0]));
        }

        thread.join();

        or_panic!(fs::remove_file(socket_path));
    }

    #[test]
    fn long_path() {
        let socket_path = "asdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasd\
                           asdfasdfasdfadfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasd";
        match UnixStream::connect(socket_path) {
            Err(ref e) if e.kind() == io::ErrorKind::InvalidInput => {}
            Err(e) => panic!("unexpected error {}", e),
            Ok(_) => panic!("unexpected success"),
        }

        match UnixListener::bind(socket_path) {
            Err(ref e) if e.kind() == io::ErrorKind::InvalidInput => {}
            Err(e) => panic!("unexpected error {}", e),
            Ok(_) => panic!("unexpected success"),
        }
    }
}
<commit_msg>Rename iter to incoming<commit_after>#![feature(io, std_misc, path, core)]
#![cfg_attr(test, feature(fs))]

extern crate libc;

use std::cmp;
use std::ffi::AsOsStr;
use std::io;
use std::iter::IntoIterator;
use std::mem;
use std::num::Int;
use std::os::unix::{Fd, OsStrExt, AsRawFd};
use std::path::AsPath;

struct Inner(Fd);

impl Drop for Inner {
    fn drop(&mut self) {
        unsafe {
            libc::close(self.0);
        }
    }
}

impl Inner {
    unsafe fn new() -> io::Result<Inner> {
        let fd = libc::socket(libc::AF_UNIX, libc::SOCK_STREAM, 0);
        if fd < 0 {
            Err(io::Error::last_os_error())
        } else {
            Ok(Inner(fd))
        }
    }

}

unsafe fn sockaddr_un<P: AsPath + ?Sized>(path: &P) -> io::Result<libc::sockaddr_un> {
    let mut addr: libc::sockaddr_un = mem::zeroed();
    addr.sun_family = libc::AF_UNIX as libc::sa_family_t;

    let bytes = path.as_path().as_os_str().as_bytes();
    if bytes.len() > addr.sun_path.len() - 1 {
        return Err(io::Error::new(io::ErrorKind::InvalidInput,
                                  "path must be smaller than SUN_LEN",
                                  None));
    }
    for (dst, src) in addr.sun_path.iter_mut().zip(bytes.iter()) {
        *dst = *src as libc::c_char;
    }
    // null byte's already there because we zeroed the struct

    Ok(addr)
}

pub struct UnixStream {
    inner: Inner,
}

impl UnixStream {
    pub fn connect<P: AsPath + ?Sized>(path: &P) -> io::Result<UnixStream> {
        unsafe {
            let inner = try!(Inner::new());
            let addr = try!(sockaddr_un(path));

            let ret = libc::connect(inner.0,
                                    &addr as *const _ as *const _,
                                    mem::size_of::<libc::sockaddr_un>() as libc::socklen_t);
            if ret < 0 {
                Err(io::Error::last_os_error())
            } else {
                Ok(UnixStream {
                    inner: inner,
                })
            }
        }
    }
}

fn calc_len(buf: &[u8]) -> libc::size_t {
    cmp::min(<libc::size_t as Int>::max_value() as usize, buf.len()) as libc::size_t
}

impl io::Read for UnixStream {
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        let ret = unsafe {
            libc::recv(self.inner.0, buf.as_mut_ptr() as *mut _, calc_len(buf), 0)
        };

        if ret < 0 {
            Err(io::Error::last_os_error())
        } else {
            Ok(ret as usize)
        }
    }
}

impl io::Write for UnixStream {
    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
        let ret = unsafe {
            libc::send(self.inner.0, buf.as_ptr() as *const _, calc_len(buf), 0)
        };

        if ret < 0 {
            Err(io::Error::last_os_error())
        } else {
            Ok(ret as usize)
        }
    }

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

impl AsRawFd for UnixStream {
    fn as_raw_fd(&self) -> Fd {
        self.inner.0
    }
}

pub struct UnixListener {
    inner: Inner,
}

impl UnixListener {
    pub fn bind<P: AsPath + ?Sized>(path: &P) -> io::Result<UnixListener> {
        unsafe {
            let inner = try!(Inner::new());
            let addr = try!(sockaddr_un(path));

            let ret = libc::bind(inner.0,
                                 &addr as *const _ as *const _,
                                 mem::size_of::<libc::sockaddr_un>() as libc::socklen_t);
            if ret < 0 {
                return Err(io::Error::last_os_error());
            }

            let ret = libc::listen(inner.0, 128);
            if ret < 0 {
                Err(io::Error::last_os_error())
            } else {
                Ok(UnixListener {
                    inner: inner,
                })
            }
        }
    }

    pub fn accept(&self) -> io::Result<UnixStream> {
        unsafe {
            let ret = libc::accept(self.inner.0, 0 as *mut _, 0 as *mut _);
            if ret < 0 {
                Err(io::Error::last_os_error())
            } else {
                Ok(UnixStream {
                    inner: Inner(ret)
                })
            }
        }
    }

    pub fn incoming<'a>(&'a self) -> Incoming<'a> {
        Incoming {
            listener: self
        }
    }
}

impl AsRawFd for UnixListener {
    fn as_raw_fd(&self) -> Fd {
        self.inner.0
    }
}

impl<'a> IntoIterator for &'a UnixListener {
    type Item = io::Result<UnixStream>;
    type IntoIter = Incoming<'a>;

    fn into_iter(self) -> Incoming<'a> {
        self.incoming()
    }
}

pub struct Incoming<'a> {
    listener: &'a UnixListener,
}

impl<'a> Iterator for Incoming<'a> {
    type Item = io::Result<UnixStream>;

    fn next(&mut self) -> Option<io::Result<UnixStream>> {
        Some(self.listener.accept())
    }

    fn size_hint(&self) -> (usize, Option<usize>) {
        (Int::max_value(), None)
    }
}

#[cfg(test)]
mod test {
    use std::fs;
    use std::thread;
    use std::path::Path;
    use std::io;
    use std::io::prelude::*;

    use {UnixListener, UnixStream};

    macro_rules! or_panic {
        ($e:expr) => {
            match $e {
                Ok(e) => e,
                Err(e) => panic!("{}", e),
            }
        }
    }

    #[test]
    fn basic() {
        let socket_path = "unix_socket_test_basic";
        let msg1 = b"hello";
        let msg2 = b"world!";
        if Path::new(socket_path).exists() {
            or_panic!(fs::remove_file(socket_path));
        }

        let listener = or_panic!(UnixListener::bind(socket_path));
        let thread = thread::scoped(|| {
            let mut stream = or_panic!(listener.accept());
            let mut buf = [0; 5];
            or_panic!(stream.read(&mut buf));
            assert_eq!(msg1, buf);
            or_panic!(stream.write_all(msg2));
        });

        let mut stream = or_panic!(UnixStream::connect(socket_path));
        or_panic!(stream.write_all(msg1));
        let mut buf = vec![];
        or_panic!(stream.read_to_end(&mut buf));
        assert_eq!(msg2, buf);
        drop(stream);

        thread.join();

        or_panic!(fs::remove_file(socket_path));
    }

    #[test]
    fn iter() {
        let socket_path = "unix_socket_test_iter";
        if Path::new(socket_path).exists() {
            or_panic!(fs::remove_file(socket_path));
        }

        let listener = or_panic!(UnixListener::bind(socket_path));
        let thread = thread::scoped(|| {
            for stream in listener.incoming().take(2) {
                let mut stream = or_panic!(stream);
                let mut buf = [0];
                or_panic!(stream.read(&mut buf));
            }
        });

        for _ in 0..2 {
            let mut stream = or_panic!(UnixStream::connect(socket_path));
            or_panic!(stream.write_all(&[0]));
        }

        thread.join();

        or_panic!(fs::remove_file(socket_path));
    }

    #[test]
    fn long_path() {
        let socket_path = "asdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasd\
                           asdfasdfasdfadfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasd";
        match UnixStream::connect(socket_path) {
            Err(ref e) if e.kind() == io::ErrorKind::InvalidInput => {}
            Err(e) => panic!("unexpected error {}", e),
            Ok(_) => panic!("unexpected success"),
        }

        match UnixListener::bind(socket_path) {
            Err(ref e) if e.kind() == io::ErrorKind::InvalidInput => {}
            Err(e) => panic!("unexpected error {}", e),
            Ok(_) => panic!("unexpected success"),
        }
    }
}
<|endoftext|>


<commit_before>//! A helper trait to initialize a data structure with custom code.
//!
//! This crate is meant to aid in initializing fixed arrays using something other than a `Default`
//! implementation. For example, if you wanted to create an array of Vecs, you could create one
//! with `Default` that made all the Vecs empty:
//!
//! ```rust
//! let my_array = <[Vec<u32>; 3]>::default();
//! assert_eq!(my_array, [[], [], []]);
//! ```
//!
//! But if you wanted to start the arrays with some state, you either need to start with the empty
//! arrays and fill from there, or drop into unsafe code to write in a partially-initialized array.
//!
//! ```rust
//! let mut my_array = <[Vec<usize>; 3]>::default();
//!
//! for (idx, arr) in my_array.iter_mut().enumerate() {
//!     for i in 0..(idx+1) {
//!         arr.push(i);
//!     }
//! }
//!
//! assert_eq!(my_array, [vec![0], vec![0, 1], vec![0, 1, 2]]);
//! ```
//!
//! With `InitWith`, the same array could be initialized like this:
//!
//! ```rust
//! use init_with::InitWith;
//!
//! let my_array = {
//!     let mut seed = Vec::new();
//!     let mut next_val = 0;
//!
//!     <[Vec<u32>; 3]>::init_with(|| {
//!         seed.push(next_val);
//!         next_val += 1;
//!         seed.clone()
//!     })
//! };
//!
//! assert_eq!(my_array, [vec![0], vec![0, 1], vec![0, 1, 2]]);
//! ```
//!
//! **Warning**: If the function given to `init_with` panics, any elements that have already been
//! created will not run their destructor. This means that any elements with heap allocations -
//! `Vec`, `Box`, etc - will leak their contents.

extern crate nodrop;

use std::{mem, ptr};

use nodrop::NoDrop;

/// A trait that allows you to create an instance of a type with a given function.
pub trait InitWith<T> {
    /// Create a new instance of this type using the given function to fill elements.
    fn init_with<F>(init: F) -> Self
        where F: FnMut() -> T,
              Self: Sized;
}

impl<T> InitWith<T> for [T; 3] {
    fn init_with<F>(mut init: F) -> Self
        where F: FnMut() -> T
    {
        let mut ret: NoDrop<[T; 3]> = unsafe { NoDrop::new(mem::uninitialized()) };

        for i in 0..3 {
            unsafe {
                ptr::write(&mut ret[i], init());
            }
        }

        ret.into_inner()
    }
}

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

    #[test]
    fn expected() {
        let val = <[i32; 3]>::init_with(|| 4);
        assert_eq!(val, [4, 4, 4]);
    }
}
<commit_msg>expand array impl to lengths 0-32<commit_after>//! A helper trait to initialize a data structure with custom code.
//!
//! This crate is meant to aid in initializing fixed arrays using something other than a `Default`
//! implementation. For example, if you wanted to create an array of Vecs, you could create one
//! with `Default` that made all the Vecs empty:
//!
//! ```rust
//! let my_array = <[Vec<u32>; 3]>::default();
//! assert_eq!(my_array, [[], [], []]);
//! ```
//!
//! But if you wanted to start the arrays with some state, you either need to start with the empty
//! arrays and fill from there, or drop into unsafe code to write in a partially-initialized array.
//!
//! ```rust
//! let mut my_array = <[Vec<usize>; 3]>::default();
//!
//! for (idx, arr) in my_array.iter_mut().enumerate() {
//!     for i in 0..(idx+1) {
//!         arr.push(i);
//!     }
//! }
//!
//! assert_eq!(my_array, [vec![0], vec![0, 1], vec![0, 1, 2]]);
//! ```
//!
//! With `InitWith`, the same array could be initialized like this:
//!
//! ```rust
//! use init_with::InitWith;
//!
//! let my_array = {
//!     let mut seed = Vec::new();
//!     let mut next_val = 0;
//!
//!     <[Vec<u32>; 3]>::init_with(|| {
//!         seed.push(next_val);
//!         next_val += 1;
//!         seed.clone()
//!     })
//! };
//!
//! assert_eq!(my_array, [vec![0], vec![0, 1], vec![0, 1, 2]]);
//! ```
//!
//! **Warning**: If the function given to `init_with` panics, any elements that have already been
//! created will not run their destructor. This means that any elements with heap allocations -
//! `Vec`, `Box`, etc - will leak their contents.

extern crate nodrop;

use std::{mem, ptr};

use nodrop::NoDrop;

/// A trait that allows you to create an instance of a type with a given function.
pub trait InitWith<T> {
    /// Create a new instance of this type using the given function to fill elements.
    fn init_with<F>(init: F) -> Self
        where F: FnMut() -> T,
              Self: Sized;
}

macro_rules! array_init {
    ($($N:expr),+) => {
        $(
            impl<T> InitWith<T> for [T; $N] {
                fn init_with<F>(mut init: F) -> Self
                    where F: FnMut() -> T
                {
                    let mut ret: NoDrop<[T; $N]> = unsafe { NoDrop::new(mem::uninitialized()) };

                    for i in 0..$N {
                        unsafe {
                            ptr::write(&mut ret[i], init());
                        }
                    }

                    ret.into_inner()
                }
            }
        )+
    };
}

array_init!(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10,
            11, 12, 13, 14, 15, 16, 17, 18, 19, 20,
            21, 22, 23, 24, 25, 26, 27, 28, 29, 30,
            31, 32);

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

    #[test]
    fn expected() {
        let val = <[i32; 3]>::init_with(|| 4);
        assert_eq!(val, [4, 4, 4]);
    }
}
<|endoftext|>