<commit_before>#![deny(missing_docs)]

//! A Gfx texture representation that works nicely with Piston libraries.

extern crate gfx;
extern crate texture;
extern crate image;

pub use texture::*;

use std::path::Path;
use image::{
    DynamicImage,
    RgbaImage,
};
use gfx::CombinedError;
use gfx::format::{Srgba8, R8_G8_B8_A8};

/// Flip settings.
#[derive(Clone, Copy, PartialEq, Eq)]
pub enum Flip {
    /// Does not flip.
    None,
    /// Flips image vertically.
    Vertical,
}

/// Represents a texture.
pub struct Texture<R> where R: gfx::Resources {
    /// Pixel storage for texture.
    pub surface: gfx::handle::Texture<R, R8_G8_B8_A8>,
    /// View used by shader.
    pub view: gfx::handle::ShaderResourceView<R, [f32; 4]>
}

impl<R: gfx::Resources> Texture<R> {
    /// Returns empty texture.
    pub fn empty<F>(factory: &mut F) -> Result<Self, CombinedError>
        where F: gfx::Factory<R>
    {
        CreateTexture::create(factory, Format::Rgba8, &[0u8; 4], [1, 1],
                              &TextureSettings::new())
    }

    /// Creates a texture from path.
    pub fn from_path<F, P>(
        factory: &mut F,
        path: P,
        flip: Flip,
        settings: &TextureSettings,
    ) -> Result<Self, String>
        where F: gfx::Factory<R>,
              P: AsRef<Path>
    {
        let img = try!(image::open(path).map_err(|e| e.to_string()));

        let img = match img {
            DynamicImage::ImageRgba8(img) => img,
            img => img.to_rgba()
        };

        let img = if flip == Flip::Vertical {
            image::imageops::flip_vertical(&img)
        } else {
            img
        };

        Texture::from_image(factory, &img, settings).map_err(
            |e| format!("{:?}", e))
    }

    /// Creates a texture from image.
    pub fn from_image<F>(
        factory: &mut F,
        img: &RgbaImage,
        settings: &TextureSettings
    ) -> Result<Self, CombinedError>
        where F: gfx::Factory<R>
    {
        let (width, height) = img.dimensions();
        CreateTexture::create(factory, Format::Rgba8,
                              img, [width, height], settings)
    }

    /// Creates texture from memory alpha.
    pub fn from_memory_alpha<F>(
        factory: &mut F,
        buffer: &[u8],
        width: u32,
        height: u32,
        settings: &TextureSettings
    ) -> Result<Self, CombinedError>
        where F: gfx::Factory<R>
    {
        if width == 0 || height == 0 {
            return Texture::empty(factory);
        }

        let size = [width, height];
        let buffer = texture::ops::alpha_to_rgba8(buffer, size);
        CreateTexture::create(factory, Format::Rgba8, &buffer, size, settings)
    }

    /// Updates the texture with an image.
    pub fn update<C>(
        &mut self,
        encoder: &mut gfx::Encoder<R, C>,
        img: &RgbaImage
    ) -> Result<(), gfx::UpdateError<[u16; 3]>>
        where C: gfx::CommandBuffer<R>
    {
        let (width, height) = img.dimensions();
        let offset = [0, 0];
        let size = [width, height];
        UpdateTexture::update(self, encoder, Format::Rgba8, img, offset, size)
    }
}

impl<F, R> CreateTexture<F> for Texture<R>
    where F: gfx::Factory<R>,
          R: gfx::Resources
{
    type Error = CombinedError;

    fn create<S: Into<[u32; 2]>>(
        factory: &mut F,
        _format: Format,
        memory: &[u8],
        size: S,
        _settings: &TextureSettings
    ) -> Result<Self, Self::Error> {
        let size = size.into();
        let (width, height) = (size[0] as u16, size[1] as u16);
        let tex_kind = gfx::tex::Kind::D2(width, height,
            gfx::tex::AaMode::Single);

        let (surface, view) = try!(factory.create_texture_const_u8::<Srgba8>(
            tex_kind, &[memory]));
        Ok(Texture { surface: surface, view: view })
    }
}

impl<R, C> UpdateTexture<gfx::Encoder<R, C>> for Texture<R>
    where R: gfx::Resources,
          C: gfx::CommandBuffer<R>
{
    type Error = gfx::UpdateError<[u16; 3]>;

    fn update<O, S>(
        &mut self,
        encoder: &mut gfx::Encoder<R, C>,
        format: Format,
        memory: &[u8],
        offset: O,
        size: S,
    ) -> Result<(), Self::Error>
        where O: Into<[u32; 2]>,
              S: Into<[u32; 2]>,
    {
        let offset = offset.into();
        let size = size.into();
        let tex = &self.surface;
        let face = None;
        let img_info = gfx::tex::ImageInfoCommon {
            xoffset: offset[0] as u16,
            yoffset: offset[1] as u16,
            zoffset: 0,
            width: size[0] as u16,
            height: size[1] as u16,
            depth: 0,
            format: (),
            mipmap: 0,
        };
        let data = gfx::cast_slice(memory);

        match format {
            Format::Rgba8 => {
                use gfx::format::Rgba8;
                encoder.update_texture::<_, Rgba8>(tex, face, img_info, data).map_err(Into::into)
            },
        }
    }
}

impl<R> ImageSize for Texture<R> where R: gfx::Resources {
    #[inline(always)]
    fn get_size(&self) -> (u32, u32) {
        let (w, h, _, _) = self.surface.get_info().kind.get_dimensions();
        (w as u32, h as u32)
    }
}
<commit_msg>Create a sampler for each texture<commit_after>#![deny(missing_docs)]

//! A Gfx texture representation that works nicely with Piston libraries.

extern crate gfx;
extern crate texture;
extern crate image;

pub use texture::*;

use std::path::Path;
use image::{
    DynamicImage,
    RgbaImage,
};
use gfx::CombinedError;
use gfx::format::{Srgba8, R8_G8_B8_A8};

/// Flip settings.
#[derive(Clone, Copy, PartialEq, Eq)]
pub enum Flip {
    /// Does not flip.
    None,
    /// Flips image vertically.
    Vertical,
}

/// Represents a texture.
pub struct Texture<R> where R: gfx::Resources {
    /// Pixel storage for texture.
    pub surface: gfx::handle::Texture<R, R8_G8_B8_A8>,
    /// Sampler for texture.
    pub sampler: gfx::handle::Sampler<R>,
    /// View used by shader.
    pub view: gfx::handle::ShaderResourceView<R, [f32; 4]>
}

impl<R: gfx::Resources> Texture<R> {
    /// Returns empty texture.
    pub fn empty<F>(factory: &mut F) -> Result<Self, CombinedError>
        where F: gfx::Factory<R>
    {
        CreateTexture::create(factory, Format::Rgba8, &[0u8; 4], [1, 1],
                              &TextureSettings::new())
    }

    /// Creates a texture from path.
    pub fn from_path<F, P>(
        factory: &mut F,
        path: P,
        flip: Flip,
        settings: &TextureSettings,
    ) -> Result<Self, String>
        where F: gfx::Factory<R>,
              P: AsRef<Path>
    {
        let img = try!(image::open(path).map_err(|e| e.to_string()));

        let img = match img {
            DynamicImage::ImageRgba8(img) => img,
            img => img.to_rgba()
        };

        let img = if flip == Flip::Vertical {
            image::imageops::flip_vertical(&img)
        } else {
            img
        };

        Texture::from_image(factory, &img, settings).map_err(
            |e| format!("{:?}", e))
    }

    /// Creates a texture from image.
    pub fn from_image<F>(
        factory: &mut F,
        img: &RgbaImage,
        settings: &TextureSettings
    ) -> Result<Self, CombinedError>
        where F: gfx::Factory<R>
    {
        let (width, height) = img.dimensions();
        CreateTexture::create(factory, Format::Rgba8,
                              img, [width, height], settings)
    }

    /// Creates texture from memory alpha.
    pub fn from_memory_alpha<F>(
        factory: &mut F,
        buffer: &[u8],
        width: u32,
        height: u32,
        settings: &TextureSettings
    ) -> Result<Self, CombinedError>
        where F: gfx::Factory<R>
    {
        if width == 0 || height == 0 {
            return Texture::empty(factory);
        }

        let size = [width, height];
        let buffer = texture::ops::alpha_to_rgba8(buffer, size);
        CreateTexture::create(factory, Format::Rgba8, &buffer, size, settings)
    }

    /// Updates the texture with an image.
    pub fn update<C>(
        &mut self,
        encoder: &mut gfx::Encoder<R, C>,
        img: &RgbaImage
    ) -> Result<(), gfx::UpdateError<[u16; 3]>>
        where C: gfx::CommandBuffer<R>
    {
        let (width, height) = img.dimensions();
        let offset = [0, 0];
        let size = [width, height];
        UpdateTexture::update(self, encoder, Format::Rgba8, img, offset, size)
    }
}

impl<F, R> CreateTexture<F> for Texture<R>
    where F: gfx::Factory<R>,
          R: gfx::Resources
{
    type Error = CombinedError;

    fn create<S: Into<[u32; 2]>>(
        factory: &mut F,
        _format: Format,
        memory: &[u8],
        size: S,
        settings: &TextureSettings
    ) -> Result<Self, Self::Error> {
        let size = size.into();
        let (width, height) = (size[0] as u16, size[1] as u16);
        let tex_kind = gfx::tex::Kind::D2(width, height,
            gfx::tex::AaMode::Single);

        // FIXME Use get_min too. gfx has only one filter setting for both.
        let filter_method = match settings.get_mag() {
            texture::Filter::Nearest => gfx::tex::FilterMethod::Scale,
            texture::Filter::Linear => gfx::tex::FilterMethod::Bilinear,
        };
        let sampler_info = gfx::tex::SamplerInfo::new(
            filter_method,
            gfx::tex::WrapMode::Clamp
        );

        let (surface, view) = try!(factory.create_texture_const_u8::<Srgba8>(
            tex_kind, &[memory]));
        let sampler = factory.create_sampler(sampler_info);
        Ok(Texture { surface: surface, sampler: sampler, view: view })
    }
}

impl<R, C> UpdateTexture<gfx::Encoder<R, C>> for Texture<R>
    where R: gfx::Resources,
          C: gfx::CommandBuffer<R>
{
    type Error = gfx::UpdateError<[u16; 3]>;

    fn update<O, S>(
        &mut self,
        encoder: &mut gfx::Encoder<R, C>,
        format: Format,
        memory: &[u8],
        offset: O,
        size: S,
    ) -> Result<(), Self::Error>
        where O: Into<[u32; 2]>,
              S: Into<[u32; 2]>,
    {
        let offset = offset.into();
        let size = size.into();
        let tex = &self.surface;
        let face = None;
        let img_info = gfx::tex::ImageInfoCommon {
            xoffset: offset[0] as u16,
            yoffset: offset[1] as u16,
            zoffset: 0,
            width: size[0] as u16,
            height: size[1] as u16,
            depth: 0,
            format: (),
            mipmap: 0,
        };
        let data = gfx::cast_slice(memory);

        match format {
            Format::Rgba8 => {
                use gfx::format::Rgba8;
                encoder.update_texture::<_, Rgba8>(tex, face, img_info, data).map_err(Into::into)
            },
        }
    }
}

impl<R> ImageSize for Texture<R> where R: gfx::Resources {
    #[inline(always)]
    fn get_size(&self) -> (u32, u32) {
        let (w, h, _, _) = self.surface.get_info().kind.get_dimensions();
        (w as u32, h as u32)
    }
}
<|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 struct IPAddress {
    opaquePtr: *mut IPaddress,
}
#[repr(C)]
pub struct CustTCPSocket {
    ready: i32,
}

pub fn init() -> bool { unsafe { ffi::SDLNet_Init() == 0 } }
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()
    }
}

// Returns an IPaddress struct if successful in becoming a host on the given port
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
    }
}

// Resolves the host from the given IP and porn
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
    }
}

// Resolves the given IP from the given IPaddress struct
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()
    }
}

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

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

// Accepts a TCP connection on the given socket, returning the new socket of the connection
pub fn tcp_accept(server: &TCPsocket) -> Option<TCPsocket> {
    unsafe {
        let socket =  ffi::SDLNet_TCP_Accept(server.opaquePtr);
        if socket as *const _TCPsocket != ptr::null() {
            Some(TCPsocket { opaquePtr: socket})
        } else {
            None
        }
    }
}

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

// Writes the data out
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);
    }
}

// Receives incoming data
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
}

// Allocates a socket set to hold the given number of sockets
pub fn alloc_socket_set(maxsockets: i32) -> SocketSet {
    unsafe {
        SocketSet { opaquePtr: ffi::SDLNet_AllocSocketSet(maxsockets) }
    }
}

// Frees the given socket set
pub fn free_socket_set(set: &SocketSet) -> () {
    unsafe {
        ffi::SDLNet_FreeSocketSet(set.opaquePtr);
    }
}

// Adds a given socket to the given socket set
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)
    }
}

// Returns the incoming data amount  on the given socketset
pub fn check_sockets(set: &SocketSet, timeout: u32) -> i32 {
    unsafe {
        ffi::SDLNet_CheckSockets(set.opaquePtr, timeout)
    }
}

pub fn socket_ready(sock: &TCPsocket) -> i32 {
    unsafe {
        (std::mem::transmute::<*mut ffi::_TCPsocket,&CustTCPSocket>(sock.opaquePtr)).ready
    }
}
<commit_msg>Changed socket_ready to return bool instead of a number.<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 struct IPAddress {
    opaquePtr: *mut IPaddress,
}
#[repr(C)]
pub struct CustTCPSocket {
    ready: i32,
}

pub fn init() -> bool { unsafe { ffi::SDLNet_Init() == 0 } }
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()
    }
}

// Returns an IPaddress struct if successful in becoming a host on the given port
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
    }
}

// Resolves the host from the given IP and porn
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
    }
}

// Resolves the given IP from the given IPaddress struct
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()
    }
}

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

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

// Accepts a TCP connection on the given socket, returning the new socket of the connection
pub fn tcp_accept(server: &TCPsocket) -> Option<TCPsocket> {
    unsafe {
        let socket =  ffi::SDLNet_TCP_Accept(server.opaquePtr);
        if socket as *const _TCPsocket != ptr::null() {
            Some(TCPsocket { opaquePtr: socket})
        } else {
            None
        }
    }
}

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

// Writes the data out
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);
    }
}

// Receives incoming data
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
}

// Allocates a socket set to hold the given number of sockets
pub fn alloc_socket_set(maxsockets: i32) -> SocketSet {
    unsafe {
        SocketSet { opaquePtr: ffi::SDLNet_AllocSocketSet(maxsockets) }
    }
}

// Frees the given socket set
pub fn free_socket_set(set: &SocketSet) -> () {
    unsafe {
        ffi::SDLNet_FreeSocketSet(set.opaquePtr);
    }
}

// Adds a given socket to the given socket set
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)
    }
}

// Returns the incoming data amount  on the given socketset
pub fn check_sockets(set: &SocketSet, timeout: u32) -> i32 {
    unsafe {
        ffi::SDLNet_CheckSockets(set.opaquePtr, timeout)
    }
}

pub fn socket_ready(sock: &TCPsocket) -> bool {
    unsafe {
        (std::mem::transmute::<*mut ffi::_TCPsocket,&CustTCPSocket>(sock.opaquePtr)).ready != 0
    }
}
<|endoftext|>


<commit_before>use std::cell::{Cell, RefCell};
use std::ffi::{CStr, CString};
use std::os::raw::c_char;
use std::ptr;

/// Trait for types that implement `as_ptr`.
///
/// This is implemented by types which can be converted
/// to a pointer from a borrowed reference.
pub trait AsPtr {
    /// The type pointed to
    ///
    /// `as_ptr` will return a pointer to this type
    type Raw;

    /// Returns a raw pointer to the contained content
    ///
    /// The caller must ensure `self` outlives the pointer
    /// that is returned, or else it will end up pointing
    /// to garbage.
    ///
    /// Mutating `self` may also invalidate this pointer,
    /// depending on the implementation.
    fn as_ptr(&self) -> *const Self::Raw;
}

impl<T> AsPtr for [T] {
    type Raw = T;
    fn as_ptr(&self) -> *const T {
        <[T]>::as_ptr(self)
    }
}

impl AsPtr for CStr {
    type Raw = c_char;
    fn as_ptr(&self) -> *const c_char {
        CStr::as_ptr(self)
    }
}

impl<'a, T> AsPtr for &'a T where T: Sized {
    type Raw = T;
    fn as_ptr(&self) -> *const T {
        *self as *const T
    }
}

impl<T> AsPtr for *const T {
    type Raw = T;
    fn as_ptr(&self) -> *const T {
        *self
    }
}

impl<T> AsPtr for Cell<T> where T: Copy {
    type Raw = T;
    fn as_ptr(&self) -> *const T {
        Cell::as_ptr(self)
    }
}

impl<T> AsPtr for RefCell<T> {
    type Raw = T;
    fn as_ptr(&self) -> *const T {
        RefCell::as_ptr(self)
    }
}

impl<T> AsPtr for Option<T> where T: AsPtr {
    type Raw = T::Raw;
    fn as_ptr(&self) -> *const T::Raw {
        match self {
            &Some(ref v) => v.as_ptr(),
            &None => ptr::null()
        }
    }
}

/// Trait for types that implement `into_raw`
///
/// This is implemented by types that can be converted
/// into a pointer by consuming ownership of the object
pub trait IntoRaw {
    /// The type pointed to
    ///
    /// `into_raw` returns a mutable pointer to this type
    type Raw;

    /// Consumes `self` returning the wrapped raw pointer.
    ///
    /// After calling this method, the caller is responsable
    /// for making sure any resources attached to this pointer
    /// (such as memory) are cleaned up. The proper way to do this
    /// is to convert the pointer back to `Self`.
    ///
    /// See `FromRaw`
    fn into_raw(self) -> *mut Self::Raw;
}

impl<T> IntoRaw for Box<T> {
    type Raw = T;
    fn into_raw(self) -> *mut T {
        Box::into_raw(self)
    }
}

impl IntoRaw for CString {
    type Raw = c_char;
    fn into_raw(self) -> *mut c_char {
        CString::into_raw(self)
    }
}

impl<T> IntoRaw for *mut T {
    type Raw = T;
    fn into_raw(self) -> *mut T {
        self
    }
}

impl<T> IntoRaw for Option<T> where T: IntoRaw {
    type Raw = T::Raw;
    fn into_raw(self) -> *mut T::Raw {
        match self {
            Some(v) => v.into_raw(),
            None => ptr::null_mut()
        }
    }
}

/// Trait for types that can be created from a raw pointer
pub trait FromRaw<T> {
    /// Create `Self` from a raw pointer
    ///
    /// After calling this method the raw pointer
    /// is owned by the resulting object. This
    /// means that the resulting object should
    /// clean up any resources associated with
    /// the pointer (such as memory).
    unsafe fn from_raw(raw: *mut T) -> Self;
}

impl<T> FromRaw<T> for Box<T> {
    unsafe fn from_raw(raw: *mut T) -> Self {
        Box::from_raw(raw)
    }
}

impl FromRaw<c_char> for CString {
    unsafe fn from_raw(raw: *mut c_char) -> CString {
        CString::from_raw(raw)
    }
}

impl<T> FromRaw<T> for *mut T {
    unsafe fn from_raw(raw: *mut T) -> *mut T {
        raw
    }
}

impl<T, U> FromRaw<U> for Option<T> where T: FromRaw<U> {
    unsafe fn from_raw(raw: *mut U) -> Option<T> {
        if raw.is_null() {
            None
        } else {
            Some(T::from_raw(raw))
        }
    }
}

<commit_msg>Add examples to documentation<commit_after>use std::cell::{Cell, RefCell};
use std::ffi::{CStr, CString};
use std::os::raw::c_char;
use std::ptr;

/// Trait for types that implement `as_ptr`.
///
/// This is implemented by types which can be converted
/// to a pointer from a borrowed reference.
///
/// # Example
/// ```
/// use ptrplus::AsPtr;
///
/// let x: &u32 = &5;
/// let y: *const u32 = x.as_ptr();
/// unsafe {
///     assert_eq!(*y, 5);
/// }
/// ```
///
/// ```
/// use ptrplus::AsPtr;
///
/// let x = 5;
/// let o1: Option<&u32> = None;
/// let o2: Option<&u32> = Some(&x);
///
/// assert!(o1.as_ptr().is_null());
/// assert!(!o2.as_ptr().is_null());
/// unsafe {
///     assert_eq!(*o2.as_ptr(), 5);
/// }
/// ```
pub trait AsPtr {
    /// The type pointed to
    ///
    /// `as_ptr` will return a pointer to this type
    type Raw;

    /// Returns a raw pointer to the contained content
    ///
    /// The caller must ensure `self` outlives the pointer
    /// that is returned, or else it will end up pointing
    /// to garbage.
    ///
    /// Mutating `self` may also invalidate this pointer,
    /// depending on the implementation.
    fn as_ptr(&self) -> *const Self::Raw;
}

impl<T> AsPtr for [T] {
    type Raw = T;
    fn as_ptr(&self) -> *const T {
        <[T]>::as_ptr(self)
    }
}

impl AsPtr for CStr {
    type Raw = c_char;
    fn as_ptr(&self) -> *const c_char {
        CStr::as_ptr(self)
    }
}

impl<'a, T> AsPtr for &'a T where T: Sized {
    type Raw = T;
    fn as_ptr(&self) -> *const T {
        *self as *const T
    }
}

impl<T> AsPtr for *const T {
    type Raw = T;
    fn as_ptr(&self) -> *const T {
        *self
    }
}

impl<T> AsPtr for Cell<T> where T: Copy {
    type Raw = T;
    fn as_ptr(&self) -> *const T {
        Cell::as_ptr(self)
    }
}

impl<T> AsPtr for RefCell<T> {
    type Raw = T;
    fn as_ptr(&self) -> *const T {
        RefCell::as_ptr(self)
    }
}

impl<T> AsPtr for Option<T> where T: AsPtr {
    type Raw = T::Raw;
    fn as_ptr(&self) -> *const T::Raw {
        match self {
            &Some(ref v) => v.as_ptr(),
            &None => ptr::null()
        }
    }
}

/// Trait for types that implement `into_raw`
///
/// This is implemented by types that can be converted
/// into a pointer by consuming ownership of the object
///
/// # Example
/// ```
/// use ptrplus::IntoRaw;
///
/// let x: Box<u32> = Box::new(5);
/// let y: *mut u32 = IntoRaw::into_raw(x);
/// unsafe {
///   assert_eq!(*y, 5);
///   *y = 6;
///   Box::from_raw(y);
/// }
///
/// ```
///
/// ```
/// use ptrplus::{FromRaw, IntoRaw};
///
/// let o1: Option<Box<u32>> = None;
/// let o2: Option<Box<u32>> = Some(Box::new(5));
///
/// let p1: *mut u32 = o1.into_raw();
/// let p2: *mut u32 = o2.into_raw();
///
/// assert!(p1.is_null());
/// assert!(!p2.is_null());
/// unsafe {
///     assert_eq!(*p2, 5);
///     let o1: Option<Box<u32>> = Option::from_raw(p1);
///     let o2: Option<Box<u32>> = Option::from_raw(p2);
///     assert!(o1.is_none());
///     assert!(!o2.is_none());
/// }
/// ```
pub trait IntoRaw {
    /// The type pointed to
    ///
    /// `into_raw` returns a mutable pointer to this type
    type Raw;

    /// Consumes `self` returning the wrapped raw pointer.
    ///
    /// After calling this method, the caller is responsable
    /// for making sure any resources attached to this pointer
    /// (such as memory) are cleaned up. The proper way to do this
    /// is to convert the pointer back to `Self`.
    ///
    /// See `FromRaw`
    fn into_raw(self) -> *mut Self::Raw;
}

impl<T> IntoRaw for Box<T> {
    type Raw = T;
    fn into_raw(self) -> *mut T {
        Box::into_raw(self)
    }
}

impl IntoRaw for CString {
    type Raw = c_char;
    fn into_raw(self) -> *mut c_char {
        CString::into_raw(self)
    }
}

impl<T> IntoRaw for *mut T {
    type Raw = T;
    fn into_raw(self) -> *mut T {
        self
    }
}

impl<T> IntoRaw for Option<T> where T: IntoRaw {
    type Raw = T::Raw;
    fn into_raw(self) -> *mut T::Raw {
        match self {
            Some(v) => v.into_raw(),
            None => ptr::null_mut()
        }
    }
}

/// Trait for types that can be created from a raw pointer
///
/// # Examples
/// ```
/// use ptrplus::{FromRaw, IntoRaw};
///
/// let x: Box<u32> = Box::new(5);
/// let y = x.into_raw();
/// let z: Box<u32> = unsafe { FromRaw::from_raw(y) };
/// assert_eq!(*z, 5);
///
/// ```
///
pub trait FromRaw<T> {
    /// Create `Self` from a raw pointer
    ///
    /// After calling this method the raw pointer
    /// is owned by the resulting object. This
    /// means that the resulting object should
    /// clean up any resources associated with
    /// the pointer (such as memory).
    unsafe fn from_raw(raw: *mut T) -> Self;
}

impl<T> FromRaw<T> for Box<T> {
    unsafe fn from_raw(raw: *mut T) -> Self {
        Box::from_raw(raw)
    }
}

impl FromRaw<c_char> for CString {
    unsafe fn from_raw(raw: *mut c_char) -> CString {
        CString::from_raw(raw)
    }
}

impl<T> FromRaw<T> for *mut T {
    unsafe fn from_raw(raw: *mut T) -> *mut T {
        raw
    }
}

impl<T, U> FromRaw<U> for Option<T> where T: FromRaw<U> {
    unsafe fn from_raw(raw: *mut U) -> Option<T> {
        if raw.is_null() {
            None
        } else {
            Some(T::from_raw(raw))
        }
    }
}

<|endoftext|>


<commit_before>//! This crate is a Rust library for using the [Serde] serialization framework
//! with data in [YAML] file format.
//!
//! This library does not reimplement a YAML parser; it uses [yaml-rust] which
//! is a pure Rust YAML 1.2 implementation.
//!
//! [Serde]: https://github.com/serde-rs/serde
//! [YAML]: http://yaml.org
//! [yaml-rust]: https://github.com/chyh1990/yaml-rust
//!
//! # Examples
//!
//! ```edition2018
//! use std::collections::BTreeMap;
//!
//! fn main() -> Result<(), serde_yaml::Error> {
//!     // You have some type.
//!     let mut map = BTreeMap::new();
//!     map.insert("x".to_string(), 1.0);
//!     map.insert("y".to_string(), 2.0);
//!
//!     // Serialize it to a YAML string.
//!     let s = serde_yaml::to_string(&map)?;
//!     assert_eq!(s, "---\nx: 1.0\ny: 2.0");
//!
//!     // Deserialize it back to a Rust type.
//!     let deserialized_map: BTreeMap<String, f64> = serde_yaml::from_str(&s)?;
//!     assert_eq!(map, deserialized_map);
//!     Ok(())
//! }
//! ```
//!
//! ## Using Serde derive
//!
//! It can also be used with Serde's serialization code generator `serde_derive` to
//! handle structs and enums defined in your own program.
//!
//! ```edition2018
//! # use serde_derive::{Serialize, Deserialize};
//! use serde::{Serialize, Deserialize};
//!
//! #[derive(Debug, PartialEq, Serialize, Deserialize)]
//! struct Point {
//!     x: f64,
//!     y: f64,
//! }
//!
//! fn main() -> Result<(), serde_yaml::Error> {
//!     let point = Point { x: 1.0, y: 2.0 };
//!
//!     let s = serde_yaml::to_string(&point)?;
//!     assert_eq!(s, "---\nx: 1.0\ny: 2.0");
//!
//!     let deserialized_point: Point = serde_yaml::from_str(&s)?;
//!     assert_eq!(point, deserialized_point);
//!     Ok(())
//! }
//! ```

#![doc(html_root_url = "https://docs.rs/serde_yaml/0.8.9")]
#![deny(missing_docs)]
#![cfg_attr(feature = "cargo-clippy", allow(renamed_and_removed_lints))]
#![cfg_attr(feature = "cargo-clippy", deny(clippy, clippy_pedantic))]
// Whitelisted clippy lints
#![cfg_attr(feature = "cargo-clippy", allow(redundant_field_names))]
// Whitelisted clippy_pedantic lints
#![cfg_attr(feature = "cargo-clippy", allow(
    // private Deserializer::next
    should_implement_trait,
    // things are often more readable this way
    cast_lossless,
    module_name_repetitions,
    single_match_else,
    use_self,
    // code is acceptable
    cast_possible_wrap,
    cast_precision_loss,
    cast_sign_loss,
    // not practical
    indexing_slicing,
    missing_docs_in_private_items,
    // not stable
    empty_enum,
    // meh, some things won't fail
    result_unwrap_used,
))]

extern crate dtoa;
extern crate linked_hash_map;
#[macro_use]
extern crate serde;
extern crate yaml_rust;

pub use self::de::{from_reader, from_slice, from_str};
pub use self::error::{Error, Location, Result};
pub use self::mapping::Mapping;
pub use self::ser::{to_string, to_vec, to_writer};
pub use self::value::{from_value, to_value, Index, Number, Sequence, Value};

mod de;
mod error;
mod mapping;
mod number;
mod path;
mod ser;
mod value;

#[allow(non_camel_case_types)]
enum private {}
<commit_msg>Ignore bare_trait_objects lint to support old compilers<commit_after>//! This crate is a Rust library for using the [Serde] serialization framework
//! with data in [YAML] file format.
//!
//! This library does not reimplement a YAML parser; it uses [yaml-rust] which
//! is a pure Rust YAML 1.2 implementation.
//!
//! [Serde]: https://github.com/serde-rs/serde
//! [YAML]: http://yaml.org
//! [yaml-rust]: https://github.com/chyh1990/yaml-rust
//!
//! # Examples
//!
//! ```edition2018
//! use std::collections::BTreeMap;
//!
//! fn main() -> Result<(), serde_yaml::Error> {
//!     // You have some type.
//!     let mut map = BTreeMap::new();
//!     map.insert("x".to_string(), 1.0);
//!     map.insert("y".to_string(), 2.0);
//!
//!     // Serialize it to a YAML string.
//!     let s = serde_yaml::to_string(&map)?;
//!     assert_eq!(s, "---\nx: 1.0\ny: 2.0");
//!
//!     // Deserialize it back to a Rust type.
//!     let deserialized_map: BTreeMap<String, f64> = serde_yaml::from_str(&s)?;
//!     assert_eq!(map, deserialized_map);
//!     Ok(())
//! }
//! ```
//!
//! ## Using Serde derive
//!
//! It can also be used with Serde's serialization code generator `serde_derive` to
//! handle structs and enums defined in your own program.
//!
//! ```edition2018
//! # use serde_derive::{Serialize, Deserialize};
//! use serde::{Serialize, Deserialize};
//!
//! #[derive(Debug, PartialEq, Serialize, Deserialize)]
//! struct Point {
//!     x: f64,
//!     y: f64,
//! }
//!
//! fn main() -> Result<(), serde_yaml::Error> {
//!     let point = Point { x: 1.0, y: 2.0 };
//!
//!     let s = serde_yaml::to_string(&point)?;
//!     assert_eq!(s, "---\nx: 1.0\ny: 2.0");
//!
//!     let deserialized_point: Point = serde_yaml::from_str(&s)?;
//!     assert_eq!(point, deserialized_point);
//!     Ok(())
//! }
//! ```

#![doc(html_root_url = "https://docs.rs/serde_yaml/0.8.9")]
#![deny(missing_docs)]
#![allow(unknown_lints, bare_trait_objects)]
#![cfg_attr(feature = "cargo-clippy", allow(renamed_and_removed_lints))]
#![cfg_attr(feature = "cargo-clippy", deny(clippy, clippy_pedantic))]
// Whitelisted clippy lints
#![cfg_attr(feature = "cargo-clippy", allow(redundant_field_names))]
// Whitelisted clippy_pedantic lints
#![cfg_attr(feature = "cargo-clippy", allow(
    // private Deserializer::next
    should_implement_trait,
    // things are often more readable this way
    cast_lossless,
    module_name_repetitions,
    single_match_else,
    use_self,
    // code is acceptable
    cast_possible_wrap,
    cast_precision_loss,
    cast_sign_loss,
    // not practical
    indexing_slicing,
    missing_docs_in_private_items,
    // not stable
    empty_enum,
    // meh, some things won't fail
    result_unwrap_used,
))]

extern crate dtoa;
extern crate linked_hash_map;
#[macro_use]
extern crate serde;
extern crate yaml_rust;

pub use self::de::{from_reader, from_slice, from_str};
pub use self::error::{Error, Location, Result};
pub use self::mapping::Mapping;
pub use self::ser::{to_string, to_vec, to_writer};
pub use self::value::{from_value, to_value, Index, Number, Sequence, Value};

mod de;
mod error;
mod mapping;
mod number;
mod path;
mod ser;
mod value;

#[allow(non_camel_case_types)]
enum private {}
<|endoftext|>


<commit_before>extern crate hyper;
extern crate rustc_serialize;

pub mod gists;
pub mod deployments;
pub mod issues;
pub mod rep;
pub mod repository;
pub mod pullrequests;

use gists::{Gists, UserGists};
use hyper::Client;
use hyper::header::{Authorization, UserAgent};
use repository::Repository;
use std::fmt;
use std::io::{Read, Result};

pub enum SortDirection {
  Asc,
  Desc
}

impl fmt::Display for SortDirection {
  fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
    write!(f, "{}", match *self {
      SortDirection::Asc => "asc",
      SortDirection::Desc => "desc"
    })
  }
}

pub struct Github<'a> {
  host: &'static str,
  agent: &'static str,
  client: &'a Client,
  token: Option<&'static str>
}

impl<'a> Github<'a> {
  /// create a new Github instance
  pub fn new(
    agent: &'static str, client: &'a Client, token: Option<&'static str>) -> Github<'a> {
    Github::host("https://api.github.com", agent, client, token)
  }

  /// create a new Github instance hosted and a custom location
  pub fn host(
    host: &'static str, agent: &'static str,
    client: &'a Client, token: Option<&'static str>) -> Github<'a> {
    Github {
      host: host,
      agent: agent,
      client: client,
      token: token
    }
  }

  /// return a reference to a github reposistory
  pub fn repo(&self, owner: &'static str, repo: &'static str) -> Repository {
    Repository::new(self, owner, repo)
  }

  /// return a reference to an interface that provides access to a user's gists
  pub fn user_gists(&self, owner: &'static str) -> UserGists {
    UserGists::new(self, owner)
  }

  /// return a reference to an interface that provides access to the
  /// the gists belonging to the owner of the token used to configure this client
  pub fn gists(&self) -> Gists {
    Gists::new(self)
  }

  fn get(&self, uri: &str) -> Result<String> {
    let url = format!("{}{}", self.host, uri);
    let builder = self.client.get(
      &url
    ).header(
      UserAgent(self.agent.to_owned())
    );
    let authenticated = match self.token {
      Some(token) =>
        builder.header(
          Authorization(format!("token {}", token))
        ),
      _ =>
        builder
    };
    let mut res = authenticated.send().unwrap();
    let mut body = String::new();
    res.read_to_string(&mut body).unwrap();
    Ok(body)
  }

  fn delete(&self, uri: &str) -> Result<()> {
    let url = format!("{}{}", self.host, uri);
    let builder = self.client.delete(
      &url
    ).header(
      UserAgent(self.agent.to_owned())
    );
    let authenticated = match self.token {
      Some(token) =>
        builder.header(
          Authorization(format!("token {}", token))
        ),
      _ =>
        builder
    };
    let mut res = authenticated.send().unwrap();
    Ok(())
  }

  fn post(&self, uri: &str, message: &[u8]) -> Result<String> {
    let url = format!("{}{}", self.host, uri);
    let builder = self.client.post(
      &url
    ).header(
      UserAgent(self.agent.to_owned())
    );
    let authenticated = match self.token {
      Some(token) =>
        builder.header(
          Authorization(format!("token {}", token))
        ),
      _ => builder
    };
    let mut res = authenticated.body(message).send().unwrap();
    let mut body = String::new();
    res.read_to_string(&mut body).unwrap();
    Ok(body)
  }

  fn put(&self, uri: &str, message: &[u8]) -> Result<String> {
    let url = format!("{}{}", self.host, uri);
    let builder = self.client.put(
      &url
    ).header(
      UserAgent(self.agent.to_owned())
    );
    let authenticated = match self.token {
      Some(token) =>
        builder.header(
          Authorization(format!("token {}", token))
        ),
      _ => builder
    };
    let mut res = authenticated.body(message).send().unwrap();
    let mut body = String::new();
    res.read_to_string(&mut body).unwrap();
    Ok(body)
  }
}
<commit_msg>reduce boiler plate<commit_after>extern crate hyper;
extern crate rustc_serialize;

pub mod gists;
pub mod deployments;
pub mod issues;
pub mod rep;
pub mod repository;
pub mod pullrequests;

use gists::{Gists, UserGists};
use hyper::Client;
use hyper::client::{IntoUrl, RequestBuilder};
use hyper::header::{Authorization, UserAgent};
use repository::Repository;
use std::fmt;
use std::io::{Read, Result};

pub enum SortDirection {
  Asc,
  Desc
}

impl fmt::Display for SortDirection {
  fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
    write!(f, "{}", match *self {
      SortDirection::Asc => "asc",
      SortDirection::Desc => "desc"
    })
  }
}

pub struct Github<'a> {
  host: &'static str,
  agent: &'static str,
  client: &'a Client,
  token: Option<&'static str>
}

impl<'a> Github<'a> {
  /// create a new Github instance
  pub fn new(
    agent: &'static str, client: &'a Client, token: Option<&'static str>) -> Github<'a> {
    Github::host("https://api.github.com", agent, client, token)
  }

  /// create a new Github instance hosted and a custom location
  pub fn host(
    host: &'static str, agent: &'static str,
    client: &'a Client, token: Option<&'static str>) -> Github<'a> {
    Github {
      host: host,
      agent: agent,
      client: client,
      token: token
    }
  }

  /// return a reference to a github reposistory
  pub fn repo(&self, owner: &'static str, repo: &'static str) -> Repository {
    Repository::new(self, owner, repo)
  }

  /// return a reference to an interface that provides access to a user's gists
  pub fn user_gists(&self, owner: &'static str) -> UserGists {
    UserGists::new(self, owner)
  }

  /// return a reference to an interface that provides access to the
  /// the gists belonging to the owner of the token used to configure this client
  pub fn gists(&self) -> Gists {
    Gists::new(self)
  }

  fn request<U: IntoUrl>(
    &self, request_builder: RequestBuilder<'a, U>, body: Option<&'a [u8]>) -> Result<String> {
    let builder = request_builder.header(
      UserAgent(self.agent.to_owned())
    );
    let authenticated = match self.token {
      Some(token) =>
        builder.header(
          Authorization(format!("token {}", token))
        ),
      _ =>
        builder
    };
    let mut res = match body {
      Some(ref bod) => authenticated.body(*bod).send().unwrap(),
       _ => authenticated.send().unwrap()
    };
    let mut body = String::new();
    res.read_to_string(&mut body).unwrap();
    Ok(body)
  }

  fn get(&self, uri: &str) -> Result<String> {
    let url = format!("{}{}", self.host, uri);
    self.request(
      self.client.get(
        &url
      ), None
    )
  }

  fn delete(&self, uri: &str) -> Result<()> {
    let url = format!("{}{}", self.host, uri);
    self.request(
      self.client.delete(
        &url
      ), None
    ).map(|_| ())
  }

  fn post(&self, uri: &str, message: &[u8]) -> Result<String> {
    let url = format!("{}{}", self.host, uri);
    self.request(
      self.client.post(
        &url
      ),
      Some(message)
    )
  }

  fn put(&self, uri: &str, message: &[u8]) -> Result<String> {
    let url = format!("{}{}", self.host, uri);
    self.request(
      self.client.put(
        &url
      ),
      Some(message)
    )
  }
}
<|endoftext|>


<commit_before>#![crate_name = "rusty-redis"]
#![desc = "A Rust client library for Redis based off hiredis"]
#![crate_type = "lib"]

use std::io::net::tcp::TcpStream;
use std::io::BufReader;
use std::i64::parse_bytes;

// TODO: need custom readline for bulk items

enum Global {
  RedisReaderMaxBuf = 1024 * 16
}

enum RedisReplyType {
  RedisReplyString,
  RedisReplyInteger,
  RedisReplyArray,
  RedisReplyNil,
  RedisReplyStatus,
  RedisReplyError
}

#[deriving(Clone)]
pub enum RedisObject {
  RedisString(String),
  RedisInteger(i64),
  RedisArray(Vec<RedisObject>),
  RedisNil,
  RedisStatus(String),
  RedisError(String)
}

enum RedisError {
  RedisNoError,
  RedisIoError,
  RedisProcessError
}

struct RedisReadTask {
  kind: RedisReplyType,
  elm: int,
  idx: int,
  obj: RedisObject
}

struct RedisReader {
  err: RedisError,
  errstr: String,
  buf: String, //this probably needs to be changed somehow
  reply: RedisObject,
  pos: uint, //might be needed in future, with dealing with multiple replies
  len: uint,
  rstack: [RedisReadTask, ..9],
  ridx: int
}

pub struct RedisContext {
  err: RedisError,
  errstr: String,
  tcpstream: TcpStream,
  flags: int, // async flag?
  obuf: String,
  reader: RedisReader
}

impl RedisReadTask {
  fn new() -> RedisReadTask {
    RedisReadTask {
      kind: RedisReplyNil,
      elm: -1,
      idx: -1,
      obj: RedisNil,
    }
  }
}

impl RedisReader {
  fn create_integer(&self, s: &str) -> Result<RedisObject, &'static str> {
    match parse_bytes(s.as_bytes(), 10) {
      Some(n) => Ok(RedisInteger(n)),
      None => Err("Invalid integer for create_integer")
    }
  }

  fn create_string(&self, mut buf: BufReader, len: uint) -> Result<RedisObject, &'static str> {
    match buf.read_to_string() {
      Ok(s) => {
        if len + 2 != s.len() { // include \r\n
          return Err("Invalid string for create_string: lengths do not matchup");
        }
        let ns = s.as_slice().trim();
        Ok(RedisString(ns.to_string()))
      },
      Err(_) => Err("Invalid string for create_string") // would be nice to not ignore this error
    }
  }

  fn process_line_item(&mut self) -> Result<(), &'static str> {
    let mut reader = BufReader::new(self.buf.as_bytes());

    reader.consume(1);
    match reader.read_line() {
      Ok(s) => {
        let ns = s.clone();
        let nns = ns.as_slice().trim();

        match self.rstack[self.ridx as uint].kind {
          RedisReplyStatus => self.reply = RedisStatus(nns.to_string()),
          RedisReplyError => self.reply = RedisError(nns.to_string()),
          RedisReplyInteger => match self.create_integer(nns) {
            Ok(n) => self.reply = n,
            Err(e) => return Err(e)
          },
          _ => return Err("Invalid type for process_line_item")
        };
        Ok(())
      },
      Err(e) => Err(e.desc)
    }
  }

  fn process_bulk_item(&mut self) -> Result<(), &'static str> {
    let mut reader = BufReader::new(self.buf.as_bytes());

    reader.consume(1);
    match reader.read_line() {
      Ok(s) => {
        let ns = s.clone();
        let nns = ns.as_slice().trim();
        let mut len: uint = 0;
        match parse_bytes(nns.as_bytes(), 10){
          Some(n) => {
            if n == -1{
              self.rstack[self.ridx as uint].kind = RedisReplyNil;
            }
            else{
              len = n as uint;
            }
          },
          None => { return Err("Invalid length in reply for process_bulk_item") }
        };

        match self.rstack[self.ridx as uint].kind {
          RedisReplyString => match self.create_string(reader, len) {
            Ok(s) => self.reply = s,
            Err(e) => return Err(e)
          },
          RedisReplyNil => self.reply = RedisNil,
          _ => return Err("Invalid type for process_bulk_item")
        }
        Ok(())
      }
      Err(e) => Err(e.desc)
    }
  }

  fn process_multi_bulk_item(&mut self) -> Result<(), &'static str> {
    unimplemented!();
  }

  fn process_item(&mut self) -> Result<(), &'static str> {
    match self.rstack[self.ridx as uint].kind {
      RedisReplyError => self.process_line_item(),
      RedisReplyStatus => self.process_line_item(),
      RedisReplyInteger => self.process_line_item(),
      RedisReplyString => self.process_bulk_item(),
      RedisReplyArray => self.process_multi_bulk_item(),
      _ => Err("This should never happen")
    }
  }

  fn check_reply_type(&mut self) -> Result<(), &'static str> {
    let mut kind: RedisReplyType;
    let slice = self.buf.as_slice();
    match slice.char_at(0) {
      '-' => kind = RedisReplyError,
      '+' => kind = RedisReplyStatus,
      ':' => kind = RedisReplyInteger,
      '$' => kind = RedisReplyString,
      '*' => kind = RedisReplyArray,
      _ =>  return Err("Failed reading control byte")
    }

    self.rstack[self.ridx as uint].kind = kind;
    Ok(())
  }

  fn process_reply(&mut self) -> Result<Option<RedisObject>, &'static str> {
    if self.len == 0 {
      return Ok(None)
    }

    if self.ridx == -1 {
      self.ridx = 0;
    }

    while self.ridx >= 0 {
      match self.check_reply_type(){
        Err(s) => { self.set_error(RedisProcessError, s); return Err(s) },
        _ => match self.process_item() {
               Err(s) => { self.set_error(RedisProcessError, s); return Err(s) },
               _ => self.ridx = self.ridx - 1
             }
      }
    }
    self.buf.truncate(0);
    self.len = 0;
    Ok(Some(self.reply.clone()))
  }

  fn feed(&mut self, buf: &mut [u8], len: uint){
    let mut i = 0;
    while i < len {
      let c = buf[i].to_ascii();
      self.buf.push_char(c.to_char());
      i = i + 1;
    }
    self.len = len;
  }

  fn set_error(&mut self, err: RedisError, errstr: &'static str){
    self.err = err;
    self.errstr = errstr.to_string();
  }

  fn new() -> RedisReader {
    RedisReader {
      err: RedisNoError,
      errstr: String::new(),
      buf: String::new(),
      reply: RedisNil,
      pos: 0,
      len: 0,
      rstack: [RedisReadTask::new(),
               RedisReadTask::new(),
               RedisReadTask::new(),
               RedisReadTask::new(),
               RedisReadTask::new(),
               RedisReadTask::new(),
               RedisReadTask::new(),
               RedisReadTask::new(),
               RedisReadTask::new()],
      ridx: -1
    }
  }
}

impl RedisContext {
  fn format_command(&self, cmd: &str, args: &[&str]) -> String {
    let mut argc: uint = 0;
    let mut c = String::new();
    let mut finalc = String::new();

    let mut len = cmd.len();
    c = c.append("$");
    c = c.append(len.to_string().as_slice());
    c = c.append("\r\n");
    c = c.append(cmd);
    c = c.append("\r\n");
    argc = argc + 1;

    for arg in args.iter(){
      len = arg.len();
      c = c.append("$");
      c = c.append(len.to_string().as_slice());
      c = c.append("\r\n");
      c = c.append(*arg);
      c = c.append("\r\n");
      argc = argc + 1;
    }
    finalc = finalc.append("*");
    finalc = finalc.append(argc.to_string().as_slice());
    finalc = finalc.append("\r\n");
    finalc = finalc.append(c.as_slice());
    finalc
  }

  fn set_error(&mut self, err: RedisError, errstr: &'static str){
    self.err = err;
    self.errstr = errstr.to_string();
  }

  fn check_error(&self) -> bool {
    match self.err {
      RedisNoError => false,
      _ => true
    }
  }

  fn get_reply_reader(&mut self) -> Result<Option<RedisObject>, &'static str> {
    self.reader.process_reply()
  }

  fn buffer_write(&mut self) {
    match self.tcpstream.write_str(self.obuf.as_slice()){
      Err(e) => { self.set_error(RedisIoError, e.desc ); }
      _ => ()
    }
  }

  fn buffer_read(&mut self) {
    let mut buf = [0, ..RedisReaderMaxBuf as uint];
    let res = self.tcpstream.read(buf);
    match res {
      Ok(s) => { self.reader.feed(buf, s); },
      Err(e) => { self.set_error(RedisIoError, e.desc); }
    }

  }

  fn block_for_reply(&mut self) -> Result<Option<RedisObject>, &'static str> {
    let o = try!(self.get_reply_reader());
    match o {
      Some(s) => Ok(Some(s)),
      None => {
        self.buffer_write();
        self.buffer_read();

        if self.check_error() {
          return Err("Error. Check error members.");
        }
        let o2 = try!(self.get_reply_reader());
        match o2{
          Some(s) => Ok(Some(s)),
          None => Err("No reply was found. Check error members.")
        }
      }
    }
  }

  pub fn connect(ip: &str, port: u16) -> RedisContext {
    RedisContext {
      err: RedisNoError,
      errstr: String::new(),
      tcpstream: match TcpStream::connect(ip, port) {
        Ok(s) => s,
        Err(e) => fail!(e.desc)
      },
      flags: 0,
      obuf: String::new(),
      reader: RedisReader::new()
    }
  }

  pub fn command(&mut self, cmd: &str, args: &[&str]) -> Result<Option<RedisObject>, &'static str> {
    self.obuf = self.format_command(cmd, args);
    self.block_for_reply()
  }
}

#[cfg(test)]
mod test {
  #[test]
  fn test_connect(){
    let _ = ::RedisContext::connect("127.0.0.1", 6379);
  }

  #[test]
  fn test_command(){
    let mut c = ::RedisContext::connect("127.0.0.1", 6379);
    let r = c.command("PING", []);

    match r {
      Ok(s) => match s {
        Some(s) => match s {
          ::RedisStatus(s) => assert!(s.eq(&"PONG".to_string())),
          _ => fail!("Didn't return correct reply type.")
        },
        None => fail!("Didn't return anything.")
      },
      Err(e) => fail!("{}", e)
    }
  }

  #[test]
  fn test_reply_types() {
    // Integer
    let mut c = ::RedisContext::connect("127.0.0.1", 6379);
    let r = c.command("APPEND", ["mykey", "test"]);

    match r {
      Ok(i) => match i {
        Some(i) => match i {
          ::RedisInteger(i) => assert!(i == 4),
          _ => fail!("INTEGER: Didn't return correct reply type.")
        },
        None => fail!("INTEGER: Didn't return anything.")
      },
      Err(e) => fail!("INTEGER: {}", e)
    }

    // String
    let r = c.command("GET", ["mykey"]);

    match r {
      Ok(s) => match s {
        Some(s) => match s {
          ::RedisString(s) => assert!(s.eq(&"test".to_string())),
          _ => fail!("STRING: Didn't return correct reply type.")
        },
        None => fail!("STRING: Didn't return anything.")
      },
      Err(e) => fail!("{}", e)
    }

    // cleanup
    let r = c.command("DEL", ["mykey"]);

    match r {
      Ok(i) => match i {
        Some(i) => match i {
          ::RedisInteger(i) => assert!(i == 1),
          _ => fail!("DELETE: cleanup failed")
        },
        None => fail!("DELETE: cleanup failed")
      },
      Err(_) => fail!("DELETE: cleanup failed")
    }
  }

  #[test]
  fn test_nil_reply() {
    let mut context = ::RedisContext::connect("127.0.0.1", 6379);
    let r = context.command("GET", ["nomykey"]);

    match r {
      Ok(s) => match s {
        Some(s) => match s {
          super::RedisNil => return,
          _ => fail!("NIL: Didn't return correct reply type.")
        },
        None => fail!("NIL: Didn't return anything."),
      },
      Err(e) => fail!("{}", e)
    }
  }
}

<commit_msg>some refactoring changes<commit_after>#![crate_name = "rusty-redis"]
#![desc = "A Rust client library for Redis based off hiredis"]
#![crate_type = "lib"]

use std::io::net::tcp::TcpStream;
use std::io::BufReader;

// TODO: need custom readline for bulk items

enum Global {
  RedisReaderMaxBuf = 1024 * 16
}

enum RedisReplyType {
  RedisReplyString,
  RedisReplyInteger,
  RedisReplyArray,
  RedisReplyNil,
  RedisReplyStatus,
  RedisReplyError
}

#[deriving(Clone)]
pub enum RedisObject {
  RedisString(String),
  RedisInteger(i64),
  RedisArray(Vec<RedisObject>),
  RedisNil,
  RedisStatus(String),
  RedisError(String)
}

enum RedisError {
  RedisNoError,
  RedisIoError,
  RedisProcessError
}

struct RedisReadTask {
  kind: RedisReplyType,
  elm: int,
  idx: int,
  obj: RedisObject
}

struct RedisReader {
  err: RedisError,
  errstr: String,
  buf: String, //this probably needs to be changed somehow
  reply: RedisObject,
  pos: uint, //might be needed in future, with dealing with multiple replies
  len: uint,
  rstack: [RedisReadTask, ..9],
  ridx: int
}

pub struct RedisContext {
  err: RedisError,
  errstr: String,
  tcpstream: TcpStream,
  flags: int, // async flag?
  obuf: String,
  reader: RedisReader
}

impl RedisReadTask {
  fn new() -> RedisReadTask {
    RedisReadTask {
      kind: RedisReplyNil,
      elm: -1,
      idx: -1,
      obj: RedisNil,
    }
  }
}

impl RedisReader {
  fn create_integer(&self, s: &str) -> Result<RedisObject, &'static str> {
    match from_str::<i64>(s) {
      Some(n) => Ok(RedisInteger(n)),
      None => Err("Invalid integer for create_integer")
    }
  }

  fn create_string(&self, mut buf: BufReader, len: uint) -> Result<RedisObject, &'static str> {
    match buf.read_to_string() {
      Ok(s) => {
        if len + 2 != s.len() { // include \r\n
          return Err("Invalid string for create_string: lengths do not matchup");
        }
        Ok(RedisString(s.as_slice()
                        .trim()
                        .to_string()))
      },
      Err(_) => Err("Invalid string for create_string") // would be nice to not ignore this error
    }
  }

  fn process_line_item(&mut self) -> Result<(), &'static str> {
    let mut reader = BufReader::new(self.buf.as_bytes());

    reader.consume(1);
    match reader.read_line() {
      Ok(s) => {
        let ns = s.clone();
        let nns = ns.as_slice().trim();

        self.reply = match self.rstack[self.ridx as uint].kind {
          RedisReplyStatus => RedisStatus(nns.to_string()),
          RedisReplyError => RedisError(nns.to_string()),
          RedisReplyInteger => match self.create_integer(nns) {
            Ok(n) => n,
            Err(e) => return Err(e)
          },
          _ => return Err("Invalid type for process_line_item")
        };
        Ok(())
      },
      Err(e) => Err(e.desc)
    }
  }

  fn process_bulk_item(&mut self) -> Result<(), &'static str> {
    let mut reader = BufReader::new(self.buf.as_bytes());

    reader.consume(1);
    match reader.read_line() {
      Ok(s) => {
        let ns = s.clone();
        let nns = ns.as_slice().trim();

        let mut len: uint = 0;
        match from_str::<i64>(nns){
          Some(n) => {
            if n == -1{
              self.rstack[self.ridx as uint].kind = RedisReplyNil;
            }
            else{
              len = n as uint;
            }
          },
          None => { return Err("Invalid length in reply for process_bulk_item") }
        };

        self.reply = match self.rstack[self.ridx as uint].kind {
          RedisReplyString => match self.create_string(reader, len) {
            Ok(s) => s,
            Err(e) => return Err(e)
          },
          RedisReplyNil => RedisNil,
          _ => return Err("Invalid type for process_bulk_item")
        };
        Ok(())
      }
      Err(e) => Err(e.desc)
    }
  }

  fn process_multi_bulk_item(&mut self) -> Result<(), &'static str> {
    unimplemented!();
  }

  fn process_item(&mut self) -> Result<(), &'static str> {
    match self.rstack[self.ridx as uint].kind {
      RedisReplyError => self.process_line_item(),
      RedisReplyStatus => self.process_line_item(),
      RedisReplyInteger => self.process_line_item(),
      RedisReplyString => self.process_bulk_item(),
      RedisReplyArray => self.process_multi_bulk_item(),
      _ => Err("This should never happen")
    }
  }

  fn check_reply_type(&mut self) -> Result<(), &'static str> {
    let mut kind: RedisReplyType;
    let slice = self.buf.as_slice();
    kind = match slice.char_at(0) {
      '-' => RedisReplyError,
      '+' => RedisReplyStatus,
      ':' => RedisReplyInteger,
      '$' => RedisReplyString,
      '*' => RedisReplyArray,
      _ =>  return Err("Failed reading control byte")
    };

    self.rstack[self.ridx as uint].kind = kind;
    Ok(())
  }

  fn process_reply(&mut self) -> Result<Option<RedisObject>, &'static str> {
    if self.len == 0 {
      return Ok(None)
    }

    if self.ridx == -1 {
      self.ridx = 0;
    }

    while self.ridx >= 0 {
      match self.check_reply_type(){
        Err(s) => { self.set_error(RedisProcessError, s); return Err(s) },
        _ => match self.process_item() {
               Err(s) => { self.set_error(RedisProcessError, s); return Err(s) },
               _ => self.ridx = self.ridx - 1
             }
      }
    }
    self.buf.truncate(0);
    self.len = 0;
    Ok(Some(self.reply.clone()))
  }

  fn feed(&mut self, buf: &[u8], len: uint){
    for i in range(0, len) {
      let c = buf[i].to_ascii();
      self.buf.push_char(c.to_char());
    }
    self.len = len;
  }

  fn set_error(&mut self, err: RedisError, errstr: &'static str){
    self.err = err;
    self.errstr = errstr.to_string();
  }

  fn new() -> RedisReader {
    RedisReader {
      err: RedisNoError,
      errstr: String::new(),
      buf: String::new(),
      reply: RedisNil,
      pos: 0,
      len: 0,
      rstack: [RedisReadTask::new(),
               RedisReadTask::new(),
               RedisReadTask::new(),
               RedisReadTask::new(),
               RedisReadTask::new(),
               RedisReadTask::new(),
               RedisReadTask::new(),
               RedisReadTask::new(),
               RedisReadTask::new()],
      ridx: -1
    }
  }
}

impl RedisContext {
  fn format_command(&self, cmd: &str, args: &[&str]) -> String {
    let mut argc: uint = 0;
    let mut c = String::new();
    let mut finalc = String::new();

    let mut len = cmd.len();
    c = c.append("$");
    c = c.append(len.to_string().as_slice());
    c = c.append("\r\n");
    c = c.append(cmd);
    c = c.append("\r\n");
    argc += 1;

    for arg in args.iter(){
      len = arg.len();
      c = c.append("$");
      c = c.append(len.to_string().as_slice());
      c = c.append("\r\n");
      c = c.append(*arg);
      c = c.append("\r\n");
      argc += 1;
    }
    finalc = finalc.append("*");
    finalc = finalc.append(argc.to_string().as_slice());
    finalc = finalc.append("\r\n");
    finalc = finalc.append(c.as_slice());
    finalc
  }

  fn set_error(&mut self, err: RedisError, errstr: &'static str){
    self.err = err;
    self.errstr = errstr.to_string();
  }

  fn check_error(&self) -> bool {
    match self.err {
      RedisNoError => false,
      _ => true
    }
  }

  fn get_reply_reader(&mut self) -> Result<Option<RedisObject>, &'static str> {
    self.reader.process_reply()
  }

  fn buffer_write(&mut self) {
    match self.tcpstream.write_str(self.obuf.as_slice()){
      Err(e) => { self.set_error(RedisIoError, e.desc ); }
      _ => ()
    }
  }

  fn buffer_read(&mut self) {
    let mut buf = [0, ..RedisReaderMaxBuf as uint];
    let res = self.tcpstream.read(buf);
    match res {
      Ok(s) => { self.reader.feed(buf, s); },
      Err(e) => { self.set_error(RedisIoError, e.desc); }
    }

  }

  fn block_for_reply(&mut self) -> Result<Option<RedisObject>, &'static str> {
    let o = try!(self.get_reply_reader());
    match o {
      Some(s) => Ok(Some(s)),
      None => {
        self.buffer_write();
        self.buffer_read();

        if self.check_error() {
          return Err("Error. Check error members.");
        }
        let o2 = try!(self.get_reply_reader());
        match o2{
          Some(s) => Ok(Some(s)),
          None => Err("No reply was found. Check error members.")
        }
      }
    }
  }

  pub fn connect(ip: &str, port: u16) -> RedisContext {
    RedisContext {
      err: RedisNoError,
      errstr: String::new(),
      tcpstream: match TcpStream::connect(ip, port) {
        Ok(s) => s,
        Err(e) => fail!(e.desc)
      },
      flags: 0,
      obuf: String::new(),
      reader: RedisReader::new()
    }
  }

  pub fn command(&mut self, cmd: &str, args: &[&str]) -> Result<Option<RedisObject>, &'static str> {
    self.obuf = self.format_command(cmd, args);
    self.block_for_reply()
  }
}

#[cfg(test)]
mod test {
  #[test]
  fn test_connect(){
    let _ = ::RedisContext::connect("127.0.0.1", 6379);
  }

  #[test]
  fn test_command(){
    let mut c = ::RedisContext::connect("127.0.0.1", 6379);
    let r = c.command("PING", []);

    match r {
      Ok(s) => match s {
        Some(s) => match s {
          ::RedisStatus(s) => assert!(s.eq(&"PONG".to_string())),
          _ => fail!("Didn't return correct reply type.")
        },
        None => fail!("Didn't return anything.")
      },
      Err(e) => fail!("{}", e)
    }
  }

  #[test]
  fn test_reply_types() {
    // Integer
    let mut c = ::RedisContext::connect("127.0.0.1", 6379);
    let r = c.command("APPEND", ["mykey", "test"]);

    match r {
      Ok(i) => match i {
        Some(i) => match i {
          ::RedisInteger(i) => assert!(i == 4),
          _ => fail!("INTEGER: Didn't return correct reply type.")
        },
        None => fail!("INTEGER: Didn't return anything.")
      },
      Err(e) => fail!("INTEGER: {}", e)
    }

    // String
    let r = c.command("GET", ["mykey"]);

    match r {
      Ok(s) => match s {
        Some(s) => match s {
          ::RedisString(s) => assert!(s.eq(&"test".to_string())),
          _ => fail!("STRING: Didn't return correct reply type.")
        },
        None => fail!("STRING: Didn't return anything.")
      },
      Err(e) => fail!("{}", e)
    }

    // cleanup
    let r = c.command("DEL", ["mykey"]);

    match r {
      Ok(i) => match i {
        Some(i) => match i {
          ::RedisInteger(i) => assert!(i == 1),
          _ => fail!("DELETE: cleanup failed")
        },
        None => fail!("DELETE: cleanup failed")
      },
      Err(_) => fail!("DELETE: cleanup failed")
    }
  }

  #[test]
  fn test_nil_reply() {
    let mut context = ::RedisContext::connect("127.0.0.1", 6379);
    let r = context.command("GET", ["notmykey"]);

    match r {
      Ok(s) => match s {
        Some(s) => match s {
          super::RedisNil => return,
          _ => fail!("NIL: Didn't return correct reply type.")
        },
        None => fail!("NIL: Didn't return anything."),
      },
      Err(e) => fail!("{}", e)
    }
  }
}

<|endoftext|>


<commit_before>#![feature(proc_macro)]

extern crate proc_macro;
extern crate syn;
#[macro_use]
extern crate quote;

use proc_macro::TokenStream;
use syn::{parse_expr, parse_item, Abi, BareFnArg, BareFnTy, Block, Constness, Expr, ExprKind,
          FnArg, FnDecl, Generics, Ident, Item, ItemKind, Pat, Path, PathSegment, UnOp, Unsafety,
          Visibility};
use quote::{Tokens, ToTokens};
use std::option::Option;

#[proc_macro_attribute]
pub fn runtime_target_feature(features: TokenStream, function: TokenStream) -> TokenStream {
    let features_string = features.to_string();

    let features_str = strip_quotes(strip_parens(features_string.as_str()));

    let features = features_str
        .split(",")
        .map(str::trim)
        .map(Feature::new)
        .collect::<Vec<_>>();

    let have_features = features
        .iter()
        .map(|ref x| x.checker_expr())
        .collect::<Vec<_>>();

    let function_string = function.to_string();

    let function_item = syn::parse_item(&function_string).unwrap();
    let function_type = function_item_to_type(&function_item.node);

    let (function_decl, function_unsafety, function_constness, function_abi, function_generics) =
        match function_item.node {
            ItemKind::Fn(ref a, b, c, ref d, ref e, _) => (a.as_ref(), b, c, d, e),
            _ => panic!("item must be a function"),
        };

    let args = function_decl
        .inputs
        .iter()
        .map(fn_arg_to_expr)
        .collect::<Vec<_>>();

    let setup_ident = Ident::new("setup");
    let default_ident = Ident::new("default");
    let features_ident: Ident = features.iter()
        .map(|x| x.to_ident_string())
        .fold("".to_string(), |acc, x| acc + &x) // TODO: separator
        .into();

    let function_item_default = Item {
        ident: default_ident.clone(),
        vis: Visibility::Inherited,
        attrs: function_item.attrs.clone(),
        node: function_item.node.clone(),
    };

    let function_item_with_features = Item {
        ident: features_ident.clone(),
        vis: Visibility::Inherited,
        attrs: function_item.attrs.clone(),
        node: function_item.node.clone(),
    };

    let setup_args = args.clone();

    let setup_block_tokens = quote! {
        {
            let chosen_function = if #(#have_features)&&* {
                #features_ident
            } else {
                #default_ident
            };

            PTR.store(chosen_function, rt::atomic::Ordering::Relaxed);

            chosen_function(#(#setup_args),*)
        }
    };

    let setup_block = parse_block(setup_block_tokens.as_str());
    let setup_node = ItemKind::Fn(Box::new(function_decl.clone()),
                                  function_unsafety,
                                  function_constness,
                                  function_abi.clone(),
                                  function_generics.clone(),
                                  setup_block);

    let function_item_setup = Item {
        ident: setup_ident.clone(),
        vis: Visibility::Inherited,
        attrs: function_item.attrs.clone(),
        node: setup_node,
    };

    let dispatch_function_block_tokens = quote! {
        {
            pub extern crate runtime_target_feature_rt as rt;

            static PTR: rt::atomic::Atomic<#function_type> = rt::atomic::Atomic::new(#setup_ident);

            #function_item_setup

            #function_item_default

            #[target_feature = #features_str]
            #function_item_with_features

            PTR.load(rt::atomic::Ordering::Relaxed)(#(#args),*)
        }
    };

    let dispatch_function_block = parse_block(dispatch_function_block_tokens.as_str());

    let dispatch_function_node = ItemKind::Fn(Box::new(function_decl.clone()),
                                              function_unsafety,
                                              function_constness,
                                              function_abi.clone(),
                                              function_generics.clone(),
                                              dispatch_function_block);

    let dispatch_function = Item {
        ident: function_item.ident.clone(),
        vis: function_item.vis,
        attrs: function_item.attrs.clone(),
        node: dispatch_function_node,
    };

    let mut tokens = Tokens::new();
    dispatch_function.to_tokens(&mut tokens);
    println!("{}", tokens);
    tokens.parse().unwrap()
}

fn parse_block(input: &str) -> Box<Block> {
    Box::new(match parse_expr(input).unwrap().node {
                 ExprKind::Block(_, block) => block,
                 _ => unreachable!(),
             })
}

fn strip_parens(str_with_parens: &str) -> &str {
    if !(str_with_parens.starts_with("(") || str_with_parens.ends_with(")")) {
        panic!("attribute arguments must begin with '(' and end with ')'");
    }

    &str_with_parens[1..str_with_parens.len() - 1].trim()
}

fn strip_quotes(str_with_quotes: &str) -> &str {
    if !(str_with_quotes.starts_with("\"") || str_with_quotes.ends_with("\"")) {
        panic!("attribute arguments must be a string literal");
    }

    &str_with_quotes[1..str_with_quotes.len() - 1].trim()
}

fn function_item_to_type(item_kind: &ItemKind) -> BareFnTy {
    let (decl, unsafety, abi, generics): (&FnDecl, Unsafety, &Option<Abi>, &Generics) =
        match *item_kind {
            ItemKind::Fn(ref a, b, _, ref d, ref e, _) => (&*a, b, d, e),
            _ => panic!("item must be a function"),
        };

    let inputs = decl.inputs
        .iter()
        .map(|x| match *x {
                 FnArg::Captured(_, ref ty) => ty,
                 FnArg::Ignored(ref ty) => ty,
                 _ => panic!("self not supported"),
             })
        .map(|ty| {
                 BareFnArg {
                     name: Option::None,
                     ty: ty.clone(),
                 }
             })
        .collect::<Vec<_>>();

    let lifetimes = Vec::new(); // TODO

    BareFnTy {
        unsafety: unsafety,
        abi: abi.clone(),
        lifetimes: lifetimes,
        inputs: inputs,
        output: decl.output.clone(),
        variadic: decl.variadic,
    }
}

fn fn_arg_to_expr(arg: &FnArg) -> Expr {
    match *arg {
        FnArg::Captured(ref pat, _) => {
            match *pat {
                Pat::Ident(_, ref ident, _) => {
                    Expr {
                        node: ExprKind::Path(Option::None, Path::from(ident.clone())),
                        attrs: Vec::new(),
                    }
                }
                _ => panic!("pattern must be identifier"),
            }
        }
        _ => panic!("argument must be captured"),
    }
}

enum Feature<'a> {
    Enable(&'a str),
    Disable(&'a str),
}

impl<'a> Feature<'a> {
    fn new(feature_str: &'a str) -> Self {
        if feature_str.starts_with("+") {
            Feature::Enable(&feature_str[1..])
        } else if feature_str.starts_with("-") {
            Feature::Disable(&feature_str[1..])
        } else {
            panic!("feature must begin with '+' or '-'");
        }
    }

    fn name(&self) -> String {
        match *self {
                Feature::Enable(x) => x,
                Feature::Disable(x) => x,
            }
            .replace(|c| c == '.' || c == '-', "_")
    }

    fn to_ident_string(&self) -> String {
        match *self {
                Feature::Enable(_) => "enable_",
                Feature::Disable(_) => "disable_",
            }
            .to_string() + &self.name()
    }

    fn checker_expr(&self) -> Expr {
        let segments = ["rt", &("have_".to_string() + &self.name())]
            .iter()
            .map(|x| PathSegment::from(*x))
            .collect();
        let path = Path {
            global: false,
            segments: segments,
        };
        let function = Expr {
            node: ExprKind::Path(Option::None, path),
            attrs: Vec::new(),
        };
        let call = Expr {
            node: ExprKind::Call(Box::new(function), Vec::new()),
            attrs: Vec::new(),
        };
        match *self {
            Feature::Enable(_) => call,
            Feature::Disable(_) => {
                Expr {
                    node: ExprKind::Unary(UnOp::Not, Box::new(call)),
                    attrs: Vec::new(),
                }
            }
        }
    }

}
<commit_msg>give function with features nicer ident<commit_after>#![feature(proc_macro)]

extern crate proc_macro;
extern crate syn;
#[macro_use]
extern crate quote;

use proc_macro::TokenStream;
use syn::{parse_expr, parse_item, Abi, BareFnArg, BareFnTy, Block, Constness, Expr, ExprKind,
          FnArg, FnDecl, Generics, Ident, Item, ItemKind, Pat, Path, PathSegment, UnOp, Unsafety,
          Visibility};
use quote::{Tokens, ToTokens};
use std::option::Option;

#[proc_macro_attribute]
pub fn runtime_target_feature(features: TokenStream, function: TokenStream) -> TokenStream {
    let features_string = features.to_string();

    let features_str = strip_quotes(strip_parens(features_string.as_str()));

    let features = features_str
        .split(",")
        .map(str::trim)
        .map(Feature::new)
        .collect::<Vec<_>>();

    let have_features = features
        .iter()
        .map(|ref x| x.checker_expr())
        .collect::<Vec<_>>();

    let function_string = function.to_string();

    let function_item = syn::parse_item(&function_string).unwrap();
    let function_type = function_item_to_type(&function_item.node);

    let (function_decl, function_unsafety, function_constness, function_abi, function_generics) =
        match function_item.node {
            ItemKind::Fn(ref a, b, c, ref d, ref e, _) => (a.as_ref(), b, c, d, e),
            _ => panic!("item must be a function"),
        };

    let args = function_decl
        .inputs
        .iter()
        .map(fn_arg_to_expr)
        .collect::<Vec<_>>();

    let setup_ident = Ident::new("setup");
    let default_ident = Ident::new("default");
    let features_ident: Ident = features.iter()
        .map(|x| x.to_ident_string())
        .fold("with".to_string(), |acc, x| acc + "_" + &x)
        .into();

    let function_item_default = Item {
        ident: default_ident.clone(),
        vis: Visibility::Inherited,
        attrs: function_item.attrs.clone(),
        node: function_item.node.clone(),
    };

    let function_item_with_features = Item {
        ident: features_ident.clone(),
        vis: Visibility::Inherited,
        attrs: function_item.attrs.clone(),
        node: function_item.node.clone(),
    };

    let setup_args = args.clone();

    let setup_block_tokens = quote! {
        {
            let chosen_function = if #(#have_features)&&* {
                #features_ident
            } else {
                #default_ident
            };

            PTR.store(chosen_function, rt::atomic::Ordering::Relaxed);

            chosen_function(#(#setup_args),*)
        }
    };

    let setup_block = parse_block(setup_block_tokens.as_str());
    let setup_node = ItemKind::Fn(Box::new(function_decl.clone()),
                                  function_unsafety,
                                  function_constness,
                                  function_abi.clone(),
                                  function_generics.clone(),
                                  setup_block);

    let function_item_setup = Item {
        ident: setup_ident.clone(),
        vis: Visibility::Inherited,
        attrs: function_item.attrs.clone(),
        node: setup_node,
    };

    let dispatch_function_block_tokens = quote! {
        {
            pub extern crate runtime_target_feature_rt as rt;

            static PTR: rt::atomic::Atomic<#function_type> = rt::atomic::Atomic::new(#setup_ident);

            #function_item_setup

            #function_item_default

            #[target_feature = #features_str]
            #function_item_with_features

            PTR.load(rt::atomic::Ordering::Relaxed)(#(#args),*)
        }
    };

    let dispatch_function_block = parse_block(dispatch_function_block_tokens.as_str());

    let dispatch_function_node = ItemKind::Fn(Box::new(function_decl.clone()),
                                              function_unsafety,
                                              function_constness,
                                              function_abi.clone(),
                                              function_generics.clone(),
                                              dispatch_function_block);

    let dispatch_function = Item {
        ident: function_item.ident.clone(),
        vis: function_item.vis,
        attrs: function_item.attrs.clone(),
        node: dispatch_function_node,
    };

    let mut tokens = Tokens::new();
    dispatch_function.to_tokens(&mut tokens);
    println!("{}", tokens);
    tokens.parse().unwrap()
}

fn parse_block(input: &str) -> Box<Block> {
    Box::new(match parse_expr(input).unwrap().node {
                 ExprKind::Block(_, block) => block,
                 _ => unreachable!(),
             })
}

fn strip_parens(str_with_parens: &str) -> &str {
    if !(str_with_parens.starts_with("(") || str_with_parens.ends_with(")")) {
        panic!("attribute arguments must begin with '(' and end with ')'");
    }

    &str_with_parens[1..str_with_parens.len() - 1].trim()
}

fn strip_quotes(str_with_quotes: &str) -> &str {
    if !(str_with_quotes.starts_with("\"") || str_with_quotes.ends_with("\"")) {
        panic!("attribute arguments must be a string literal");
    }

    &str_with_quotes[1..str_with_quotes.len() - 1].trim()
}

fn function_item_to_type(item_kind: &ItemKind) -> BareFnTy {
    let (decl, unsafety, abi, generics): (&FnDecl, Unsafety, &Option<Abi>, &Generics) =
        match *item_kind {
            ItemKind::Fn(ref a, b, _, ref d, ref e, _) => (&*a, b, d, e),
            _ => panic!("item must be a function"),
        };

    let inputs = decl.inputs
        .iter()
        .map(|x| match *x {
                 FnArg::Captured(_, ref ty) => ty,
                 FnArg::Ignored(ref ty) => ty,
                 _ => panic!("self not supported"),
             })
        .map(|ty| {
                 BareFnArg {
                     name: Option::None,
                     ty: ty.clone(),
                 }
             })
        .collect::<Vec<_>>();

    let lifetimes = Vec::new(); // TODO

    BareFnTy {
        unsafety: unsafety,
        abi: abi.clone(),
        lifetimes: lifetimes,
        inputs: inputs,
        output: decl.output.clone(),
        variadic: decl.variadic,
    }
}

fn fn_arg_to_expr(arg: &FnArg) -> Expr {
    match *arg {
        FnArg::Captured(ref pat, _) => {
            match *pat {
                Pat::Ident(_, ref ident, _) => {
                    Expr {
                        node: ExprKind::Path(Option::None, Path::from(ident.clone())),
                        attrs: Vec::new(),
                    }
                }
                _ => panic!("pattern must be identifier"),
            }
        }
        _ => panic!("argument must be captured"),
    }
}

enum Feature<'a> {
    Enable(&'a str),
    Disable(&'a str),
}

impl<'a> Feature<'a> {
    fn new(feature_str: &'a str) -> Self {
        if feature_str.starts_with("+") {
            Feature::Enable(&feature_str[1..])
        } else if feature_str.starts_with("-") {
            Feature::Disable(&feature_str[1..])
        } else {
            panic!("feature must begin with '+' or '-'");
        }
    }

    fn name(&self) -> String {
        match *self {
                Feature::Enable(x) => x,
                Feature::Disable(x) => x,
            }
            .replace(|c| c == '.' || c == '-', "_")
    }

    fn to_ident_string(&self) -> String {
        match *self {
                Feature::Enable(_) => "enable_",
                Feature::Disable(_) => "disable_",
            }
            .to_string() + &self.name()
    }

    fn checker_expr(&self) -> Expr {
        let segments = ["rt", &("have_".to_string() + &self.name())]
            .iter()
            .map(|x| PathSegment::from(*x))
            .collect();
        let path = Path {
            global: false,
            segments: segments,
        };
        let function = Expr {
            node: ExprKind::Path(Option::None, path),
            attrs: Vec::new(),
        };
        let call = Expr {
            node: ExprKind::Call(Box::new(function), Vec::new()),
            attrs: Vec::new(),
        };
        match *self {
            Feature::Enable(_) => call,
            Feature::Disable(_) => {
                Expr {
                    node: ExprKind::Unary(UnOp::Not, Box::new(call)),
                    attrs: Vec::new(),
                }
            }
        }
    }

}
<|endoftext|>


<commit_before>extern crate curl;
extern crate rustc_serialize;

use std::thread;
use std::time::Duration;
use std::env;
use std::str::FromStr;
use rustc_serialize::json;
use curl::http;

mod error;
pub use error::Error;

const USER_AGENT:         &'static str = concat!("travis-after-all/", env!("CARGO_PKG_VERSION"));
const TRAVIS_JOB_NUMBER : &'static str = "TRAVIS_JOB_NUMBER";
const TRAVIS_BUILD_ID:    &'static str = "TRAVIS_BUILD_ID";
const TRAVIS_API_URL:     &'static str = "https://api.travis-ci.org";
const POLLING_INTERVAL:   &'static str = "LEADER_POLLING_INTERVAL";

pub struct Build {
    travis_api_url: String,
    build_id: String,
    job_number: String,
    polling_interval: u64,
}

#[derive(Debug, RustcDecodable, RustcEncodable)]
pub struct MatrixElement {
    finished_at: Option<String>,
    result: Option<u32>,
    number: String,
    id: Option<u32>,
}

impl MatrixElement {
    pub fn id(&self) -> u32 {
        self.id.unwrap()
    }

    pub fn is_leader(&self) -> bool {
        is_leader(&self.number)
    }

    pub fn is_succeeded(&self) -> bool {
        if !self.is_finished() {
           return false;
        }

        match self.result {
            None => false,
            Some(0) => true,
            Some(_) => false,
        }
    }

    pub fn is_finished(&self) -> bool {
        self.finished_at.is_some()
    }
}

#[derive(Debug, RustcDecodable, RustcEncodable)]
pub struct Matrix {
    id: u32,
    matrix: Vec<MatrixElement>,
}

impl Matrix {
    pub fn builds(&self) -> &[MatrixElement] {
        &self.matrix
    }

    pub fn others_finished(&self) -> bool {
        self.matrix.iter()
            .filter(|build| !build.is_leader())
            .all(|build| build.is_finished())
    }

    pub fn others_succeeded(&self) -> bool {
        self.matrix.iter()
            .filter(|build| !build.is_leader())
            .all(|build| build.is_succeeded())
    }
}

pub fn is_leader(job: &str) -> bool {
    job.ends_with('1')
}

impl Build {
    pub fn from_env() -> Result<Build, Error> {
        let build_id = try!(env::var(TRAVIS_BUILD_ID));
        let job_number = try!(env::var(TRAVIS_JOB_NUMBER));

        let polling_interval = match env::var(POLLING_INTERVAL) {
            Err(_) => 5,
            Ok(val) => try!(FromStr::from_str(&val))
        };

        Ok(Build {
            travis_api_url: TRAVIS_API_URL.into(),
            build_id: build_id,
            job_number: job_number,
            polling_interval: polling_interval,
        })

    }

    pub fn is_leader(&self) -> bool {
        is_leader(&self.job_number)
    }

    pub fn build_matrix(&self) -> Result<Matrix, Error> {
        let url = format!("{}/builds/{}", self.travis_api_url, self.build_id);
        let res = http::handle()
            .get(url)
            .follow_redirects(true)
            .header("User-Agent", USER_AGENT)
            .exec()
            .unwrap();

        if res.get_code() == 404 {
            return Err(Error::BuildNotFound);
        }

        let body = String::from_utf8(res.move_body()).unwrap();
        Ok(try!(json::decode(&body)))
    }

    pub fn wait_for_others(&self) -> Result<(), Error> {
        if !self.is_leader() {
            return Err(Error::NotLeader)
        }

        let dur = Duration::new(self.polling_interval, 0);
        loop {
            let matrix = try!(self.build_matrix());

            if matrix.others_finished() {
                break;
            }
            thread::sleep(dur);
        }

        let matrix = try!(self.build_matrix());
        match matrix.others_succeeded() {
            true => Ok(()),
            false => Err(Error::FailedBuilds)
        }
    }
}

<commit_msg>fix: Include variable name in error<commit_after>extern crate curl;
extern crate rustc_serialize;

use std::thread;
use std::time::Duration;
use std::env;
use std::str::FromStr;
use rustc_serialize::json;
use curl::http;

mod error;
pub use error::Error;

const USER_AGENT:         &'static str = concat!("travis-after-all/", env!("CARGO_PKG_VERSION"));
const TRAVIS_JOB_NUMBER : &'static str = "TRAVIS_JOB_NUMBER";
const TRAVIS_BUILD_ID:    &'static str = "TRAVIS_BUILD_ID";
const TRAVIS_API_URL:     &'static str = "https://api.travis-ci.org";
const POLLING_INTERVAL:   &'static str = "LEADER_POLLING_INTERVAL";

pub struct Build {
    travis_api_url: String,
    build_id: String,
    job_number: String,
    polling_interval: u64,
}

#[derive(Debug, RustcDecodable, RustcEncodable)]
pub struct MatrixElement {
    finished_at: Option<String>,
    result: Option<u32>,
    number: String,
    id: Option<u32>,
}

impl MatrixElement {
    pub fn id(&self) -> u32 {
        self.id.unwrap()
    }

    pub fn is_leader(&self) -> bool {
        is_leader(&self.number)
    }

    pub fn is_succeeded(&self) -> bool {
        if !self.is_finished() {
           return false;
        }

        match self.result {
            None => false,
            Some(0) => true,
            Some(_) => false,
        }
    }

    pub fn is_finished(&self) -> bool {
        self.finished_at.is_some()
    }
}

#[derive(Debug, RustcDecodable, RustcEncodable)]
pub struct Matrix {
    id: u32,
    matrix: Vec<MatrixElement>,
}

impl Matrix {
    pub fn builds(&self) -> &[MatrixElement] {
        &self.matrix
    }

    pub fn others_finished(&self) -> bool {
        self.matrix.iter()
            .filter(|build| !build.is_leader())
            .all(|build| build.is_finished())
    }

    pub fn others_succeeded(&self) -> bool {
        self.matrix.iter()
            .filter(|build| !build.is_leader())
            .all(|build| build.is_succeeded())
    }
}

pub fn is_leader(job: &str) -> bool {
    job.ends_with('1')
}

fn env_var(varname: &str) -> Result<String, Error> {
    env::var(varname)
        .map_err(|_| Error::from_string(format!("Missing environment variable: {}", varname)))
}

impl Build {
    pub fn from_env() -> Result<Build, Error> {
        let build_id = try!(env_var(TRAVIS_BUILD_ID));
        let job_number = try!(env_var(TRAVIS_JOB_NUMBER));

        let polling_interval = match env_var(POLLING_INTERVAL) {
            Err(_) => 5,
            Ok(val) => try!(FromStr::from_str(&val))
        };

        Ok(Build {
            travis_api_url: TRAVIS_API_URL.into(),
            build_id: build_id,
            job_number: job_number,
            polling_interval: polling_interval,
        })

    }

    pub fn is_leader(&self) -> bool {
        is_leader(&self.job_number)
    }

    pub fn build_matrix(&self) -> Result<Matrix, Error> {
        let url = format!("{}/builds/{}", self.travis_api_url, self.build_id);
        let res = http::handle()
            .get(url)
            .follow_redirects(true)
            .header("User-Agent", USER_AGENT)
            .exec()
            .unwrap();

        if res.get_code() == 404 {
            return Err(Error::BuildNotFound);
        }

        let body = String::from_utf8(res.move_body()).unwrap();
        Ok(try!(json::decode(&body)))
    }

    pub fn wait_for_others(&self) -> Result<(), Error> {
        if !self.is_leader() {
            return Err(Error::NotLeader)
        }

        let dur = Duration::new(self.polling_interval, 0);
        loop {
            let matrix = try!(self.build_matrix());

            if matrix.others_finished() {
                break;
            }
            thread::sleep(dur);
        }

        let matrix = try!(self.build_matrix());
        match matrix.others_succeeded() {
            true => Ok(()),
            false => Err(Error::FailedBuilds)
        }
    }
}

<|endoftext|>