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

//! Body Parser Plugin for Iron
//!
//! This plugin parses JSON out of an incoming Request.

extern crate iron;
extern crate rustc_serialize;
extern crate plugin;
extern crate persistent;

use rustc_serialize::{json, Decodable};

use iron::mime;
use iron::prelude::*;
use iron::headers;
use iron::typemap::{Key};
use std::io::Read;
use std::any::Any;
use std::marker;

pub use self::errors::{BodyError, BodyErrorCause};
pub use self::limit_reader::{LimitReader};

mod errors;
mod limit_reader;

fn read_body_as_utf8(req: &mut Request, limit: usize) -> Result<String, errors::BodyError> {
    let mut bytes = Vec::new();
    match LimitReader::new(req.body.by_ref(), limit).read_to_end(&mut bytes) {
        Ok(_) => {
             match String::from_utf8(bytes) {
                Ok(e) => Ok(e),
                Err(err) => Err(errors::BodyError {
                    detail: "Invalid UTF-8 sequence".to_string(),
                    cause: errors::BodyErrorCause::Utf8Error(err.utf8_error())
                })
            }
        },
        Err(err) => Err(errors::BodyError {
            detail: "Can't read request body".to_string(),
            cause: errors::BodyErrorCause::IoError(err)
        })
    }
}

/// Use this key to modify the default body limit.
pub struct MaxBodyLength;
impl Key for MaxBodyLength {
    type Value = usize;
}

/// Raw is a plugin to read a request body into UTF-8 String.
/// Doesn't read `multipart/form-data`.
pub struct Raw;

impl Key for Raw {
    type Value = Option<String>;
}

const DEFAULT_BODY_LIMIT: usize = 1024 * 1024 * 100;

impl<'a, 'b> plugin::Plugin<Request<'a, 'b>> for Raw {
    type Error = BodyError;

    fn eval(req: &mut Request) -> Result<Option<String>, BodyError> {
        let need_read = req.headers.get::<headers::ContentType>().map(|header| {
            match **header {
                mime::Mime(mime::TopLevel::Multipart, mime::SubLevel::FormData, _) => false,
                _ => true
            }
        }).unwrap_or(false);

        if need_read {
            let max_length = req.get::<persistent::Read<MaxBodyLength>>()
                .ok().unwrap_or(std::sync::Arc::new(DEFAULT_BODY_LIMIT));
            let body = try!(read_body_as_utf8(req, *max_length));
            Ok(Some(body))
        } else {
            Ok(None)
        }
    }
}

/// Json is a plugin to parse a request body into JSON.
/// Uses Raw plugin to parse the body with limit.
#[derive(Clone)]
pub struct Json;
impl Key for Json {
    type Value = Option<json::Json>;
}

impl<'a, 'b> plugin::Plugin<Request<'a, 'b>> for Json {
    type Error = BodyError;

    fn eval(req: &mut Request) -> Result<Option<json::Json>, BodyError> {
        req.get::<Raw>()
            .and_then(|maybe_body| {
                reverse_option(maybe_body.map(|body| body.parse()))
                    .map_err(|err| {
                        BodyError {
                            detail: "Can't parse body to JSON".to_string(),
                            cause: BodyErrorCause::ParserError(err)
                        }
                    })
            })
    }
}

/// Struct is a plugin to parse a request body into a struct.
/// Uses Raw plugin to parse the body with limit.
pub struct Struct<T: Decodable> {
    marker: marker::PhantomData<T>
}
impl<T> Key for Struct<T> where T: Decodable + Any {
    type Value = Option<T>;
}

impl<'a, 'b, T> plugin::Plugin<Request<'a, 'b>> for Struct<T>
where T: Decodable + Any {
    type Error = BodyError;

    fn eval(req: &mut Request) -> Result<Option<T>, BodyError> {
        req.get::<Json>()
            .and_then(|maybe_body| {
                reverse_option(maybe_body.map(|body| Decodable::decode(&mut json::Decoder::new(body))))
                    .map_err(|err| BodyError {
                        detail: "Can't parse body to the struct".to_string(),
                        cause: BodyErrorCause::DecoderError(err)
                    })
            })
    }
}

fn reverse_option<T,E>(value: Option<Result<T, E>>) -> Result<Option<T>, E> {
    match value {
        Some(Ok(val)) => Ok(Some(val)),
        Some(Err(err)) => Err(err),
        None => Ok(None),
    }
}<commit_msg>using map instead of clone for performance<commit_after>#![crate_name = "bodyparser"]

//! Body Parser Plugin for Iron
//!
//! This plugin parses JSON out of an incoming Request.

extern crate iron;
extern crate rustc_serialize;
extern crate plugin;
extern crate persistent;

use rustc_serialize::{json, Decodable};

use iron::mime;
use iron::prelude::*;
use iron::headers;
use iron::typemap::{Key};
use std::io::Read;
use std::any::Any;
use std::marker;

pub use self::errors::{BodyError, BodyErrorCause};
pub use self::limit_reader::{LimitReader};

mod errors;
mod limit_reader;

fn read_body_as_utf8(req: &mut Request, limit: usize) -> Result<String, errors::BodyError> {
    let mut bytes = Vec::new();
    match LimitReader::new(req.body.by_ref(), limit).read_to_end(&mut bytes) {
        Ok(_) => {
             match String::from_utf8(bytes) {
                Ok(e) => Ok(e),
                Err(err) => Err(errors::BodyError {
                    detail: "Invalid UTF-8 sequence".to_string(),
                    cause: errors::BodyErrorCause::Utf8Error(err.utf8_error())
                })
            }
        },
        Err(err) => Err(errors::BodyError {
            detail: "Can't read request body".to_string(),
            cause: errors::BodyErrorCause::IoError(err)
        })
    }
}

/// Use this key to modify the default body limit.
pub struct MaxBodyLength;
impl Key for MaxBodyLength {
    type Value = usize;
}

/// Raw is a plugin to read a request body into UTF-8 String.
/// Doesn't read `multipart/form-data`.
pub struct Raw;

impl Key for Raw {
    type Value = Option<String>;
}

const DEFAULT_BODY_LIMIT: usize = 1024 * 1024 * 100;

impl<'a, 'b> plugin::Plugin<Request<'a, 'b>> for Raw {
    type Error = BodyError;

    fn eval(req: &mut Request) -> Result<Option<String>, BodyError> {
        let need_read = req.headers.get::<headers::ContentType>().map(|header| {
            match **header {
                mime::Mime(mime::TopLevel::Multipart, mime::SubLevel::FormData, _) => false,
                _ => true
            }
        }).unwrap_or(false);

        if need_read {
            let max_length = req
                .get::<persistent::Read<MaxBodyLength>>()
                .ok()
                .map(|x| *x)
                .unwrap_or(DEFAULT_BODY_LIMIT);

            let body = try!(read_body_as_utf8(req, max_length));
            Ok(Some(body))
        } else {
            Ok(None)
        }
    }
}

/// Json is a plugin to parse a request body into JSON.
/// Uses Raw plugin to parse the body with limit.
#[derive(Clone)]
pub struct Json;
impl Key for Json {
    type Value = Option<json::Json>;
}

impl<'a, 'b> plugin::Plugin<Request<'a, 'b>> for Json {
    type Error = BodyError;

    fn eval(req: &mut Request) -> Result<Option<json::Json>, BodyError> {
        req.get::<Raw>()
            .and_then(|maybe_body| {
                reverse_option(maybe_body.map(|body| body.parse()))
                    .map_err(|err| {
                        BodyError {
                            detail: "Can't parse body to JSON".to_string(),
                            cause: BodyErrorCause::ParserError(err)
                        }
                    })
            })
    }
}

/// Struct is a plugin to parse a request body into a struct.
/// Uses Raw plugin to parse the body with limit.
pub struct Struct<T: Decodable> {
    marker: marker::PhantomData<T>
}
impl<T> Key for Struct<T> where T: Decodable + Any {
    type Value = Option<T>;
}

impl<'a, 'b, T> plugin::Plugin<Request<'a, 'b>> for Struct<T>
where T: Decodable + Any {
    type Error = BodyError;

    fn eval(req: &mut Request) -> Result<Option<T>, BodyError> {
        req.get::<Json>()
            .and_then(|maybe_body| {
                reverse_option(maybe_body.map(|body| Decodable::decode(&mut json::Decoder::new(body))))
                    .map_err(|err| BodyError {
                        detail: "Can't parse body to the struct".to_string(),
                        cause: BodyErrorCause::DecoderError(err)
                    })
            })
    }
}

fn reverse_option<T,E>(value: Option<Result<T, E>>) -> Result<Option<T>, E> {
    match value {
        Some(Ok(val)) => Ok(Some(val)),
        Some(Err(err)) => Err(err),
        None => Ok(None),
    }
}<|endoftext|>


<commit_before>//! The export module for Tdo server.
#![deny(missing_docs, unsafe_code,
        missing_copy_implementations,
        trivial_casts, trivial_numeric_casts,
        unused_import_braces, unused_qualifications)]
#![warn(missing_debug_implementations)]
extern crate tdo_core;
extern crate libc;

use std::{slice, io, ptr};

/// Generates a well formated String of all undone Todos
pub fn gen_tasks_mail(tdo: &tdo_core::tdo::Tdo) -> Option<String> {
    let mut listed = String::new();
    for list in tdo.to_owned().lists.into_iter() {
        let undone = list.list_undone();
        if undone.len() > 0 {
            listed.push_str("\n------------------------------------------------------------\n\t");
            listed.push_str(&list.name);
            listed.push_str("\n------------------------------------------------------------\n");
            for entry in undone {
                if entry.done {
                    listed.push_str(&format!("- {:?}\n", entry.name));
                }
            }
            listed.push_str("\n\n");
        }
    }
    match listed.len() {
        0 => None,
        _ => Some(listed),
    }
}

/// Returns the full Name of the current user if present.
#[allow(unsafe_code)]
pub fn get_full_name() -> Result<String, io::Error>{
    unsafe {
        let uid = libc::geteuid();
        let user = ptr::read(libc::getpwuid(uid));
        let name = String::from_utf8_unchecked(slice::from_raw_parts(user.pw_gecos as *const u8,
                                                                     libc::strlen(user.pw_gecos))
            .to_vec());
        if name == "" {
            Err(io::Error::last_os_error())
        } else {
            Ok(name)
        }
    }
}
<commit_msg>add markdown export<commit_after>//! The export module for Tdo server.
#![deny(missing_docs, unsafe_code,
        missing_copy_implementations,
        trivial_casts, trivial_numeric_casts,
        unused_import_braces, unused_qualifications)]
#![warn(missing_debug_implementations)]
extern crate tdo_core;
extern crate libc;

use std::{slice, io, ptr};

/// Generates a well formated String of all undone Todos
pub fn gen_tasks_mail(tdo: &tdo_core::tdo::Tdo) -> Option<String> {
    let mut listed = String::new();
    for list in tdo.to_owned().lists.into_iter() {
        let undone = list.list_undone();
        if undone.len() > 0 {
            listed.push_str("\n------------------------------------------------------------\n\t");
            listed.push_str(&list.name);
            listed.push_str("\n------------------------------------------------------------\n");
            for entry in undone {
                if entry.done {
                    listed.push_str(&format!("- {:?}\n", entry.name));
                }
            }
            listed.push_str("\n\n");
        }
    }
    match listed.len() {
        0 => None,
        _ => Some(listed),
    }
}

/// Generates a markdown String to export the lists.
pub fn gen_tasks_md(tdo: &tdo_core::tdo::Tdo, list_done: bool) -> Option<String> {
    let mut markdown = String::from("# Your tasks\n\n");
    let name = get_full_name();
    if name.is_ok() {
        markdown.push_str(&format!("Here are the tasks for {}\n\n", &name.unwrap()));
    }
    let mut intern = String::new();
    for list in tdo.to_owned().lists.iter() {
        let tasks: Vec<tdo_core::todo::Todo>;
        if list_done {
            tasks = list.list.to_owned();
        } else {
            tasks = list.list_undone();
        }
        if tasks.len() > 0 {
            intern.push_str(&format!("\n# {}\n", &list.name));
            for entry in tasks {
                if entry.done {
                    intern.push_str(&format!("- [x] {}\n", &entry.name));
                } else {
                    intern.push_str(&format!("- [ ] {}\n", &entry.name));
                }
            }
        }
    }
    match intern.len() {
        0 => None,
        _ => {
            markdown.push_str(&intern);
            Some(markdown)
        },
    }
}

/// Returns the full Name of the current user if present.
#[allow(unsafe_code)]
pub fn get_full_name() -> Result<String, io::Error> {
    unsafe {
        let uid = libc::geteuid();
        let user = ptr::read(libc::getpwuid(uid));
        let name = String::from_utf8_unchecked(slice::from_raw_parts(user.pw_gecos as *const u8,
                                                                     libc::strlen(user.pw_gecos))
            .to_vec());
        if name == "" {
            Err(io::Error::last_os_error())
        } else {
            Ok(name)
        }
    }
}
<|endoftext|>


<commit_before>#[test]
fn it_works() {
}
<commit_msg>initial decoding with unit test<commit_after>pub mod lc4 {

  // ConditionCode
  pub type CC = u8;

  pub const N : CC = 4;
  pub const Z : CC = 2;
  pub const P : CC = 1;

  pub type RName = u8;

  pub const R0 : RName = 0;
  pub const R1 : RName = 1;
  pub const R2 : RName = 2;
  pub const R3 : RName = 3;
  pub const R4 : RName = 4;
  pub const R5 : RName = 5;
  pub const R6 : RName = 6;
  pub const R7 : RName = 7;

  #[derive(PartialEq, Eq)]
  pub struct IMM11 { pub val : i16 }
  #[derive(PartialEq, Eq)]
  pub struct IMM9 { pub val : i16 }
  #[derive(PartialEq, Eq)]
  pub struct IMM7 { pub val : i8 }
  #[derive(PartialEq, Eq)]
  pub struct IMM6 { pub val : i8 }
  #[derive(PartialEq, Eq)]
  pub struct IMM5 { pub val : i8 }

  #[derive(PartialEq, Eq)]
  pub struct UIMM8 { pub val : u8 }
  #[derive(PartialEq, Eq)]
  pub struct UIMM7 { pub val : u8 }
  #[derive(PartialEq, Eq)]
  pub struct UIMM4 { pub val : u8 }

  // Instructions

  #[derive(PartialEq, Eq)]
  pub enum Inst {
    NOP,
    BR(CC,IMM9),
    ADD(RName, RName, RName),
    MUL(RName, RName, RName),
    SUB(RName, RName, RName),
    DIV(RName, RName, RName),
    ADDi(RName, RName, IMM5),
    CMP(RName, RName),
    CMPu(RName, RName),
    CMPi(RName, IMM7),
    CMPiu(RName, UIMM7),
    JSR(IMM11),
    JSRr(RName),
    AND(RName, RName, RName),
    NOT(RName, RName),
    OR(RName, RName, RName),
    XOR(RName, RName, RName),
    ANDi(RName, RName, IMM5),
    LDR(RName, RName, IMM6),
    STR(RName, RName, IMM6),
    RTI,
    CONST(RName, IMM9),
    SLL(RName, RName, UIMM4),
    SRA(RName, RName, UIMM4),
    SRL(RName, RName, UIMM4),
    MOD(RName, RName, RName),
    JMPr(RName),
    JMP(IMM11),
    HICONST(RName, UIMM8),
    TRAP(UIMM8)
  }

  // PSEUDO-instructions

  pub const RET : Inst = Inst::JMPr(R7);
  // LEA(RName, LABEL)
  // LC(RName, LABEL)

  // Assembly Directives
  /*
  .DATA
  .CODE
  .ADDR UIMM16
  .FALIGN
  .FILL IMM16
  .BLKW UIMM16
  .CONST IMM16
  .UCONST UIMM16
  */

}

pub mod controller {

  use lc4::*;

  #[derive(PartialEq, Eq)]
  enum DecodeError { BadOpcode }

  trait Controller {
    fn decode(&self) -> Result<Inst, DecodeError>;
  }

  macro_rules! opcode {
    ( $inst:expr ) => { ($inst & 0xF000 ) >> 12 };
  }

  macro_rules! br_opcode {
    ( $inst:expr ) => { ($inst & 0x0E00 ) >> 9 };
  }

  macro_rules! decode_imm9 {
    ( $inst:expr ) => { IMM9{val : if $inst & 0x0100 == 0 { $inst & 0x01FF } else { ($inst & 0x01FF) | 0xFE00  } as i16} };
  }

  impl Controller for u16 {
    fn decode(&self) -> Result<Inst, DecodeError> {
      match opcode!(self) {
        0b0000 =>
          match br_opcode!(self) {
            0b000 => Ok(Inst::NOP),
            a => Ok(Inst::BR(a as CC, decode_imm9!(self)))
          },
        _ => Err(DecodeError::BadOpcode)
      }
    }
  }

  #[test]
  fn decode_unit_tests () {
    assert!((0x0000 as u16).decode() == Ok(Inst::NOP));
  }
}

pub mod cpu {

  pub struct CPU {
    pub registers: [u16; 8],
    pub psr: u16,
    pub pc: u16,
    pub nzp: u8,
    pub memory: [u16; 2^16]
  }

}<|endoftext|>


<commit_before>// Copyright (C) 2016  ParadoxSpiral
//
// This file is part of mpv-rs.
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA

use libc;

use super::*;
use super::utils::mpv_err;
use super::super::raw::*;

use std::ffi::CStr;
use std::mem;
use std::panic;
use std::panic::AssertUnwindSafe;
use std::ptr;

unsafe extern "C" fn get_proc_addr_wrapper<F>(cookie: *mut libc::c_void,
                                           name: *const libc::c_char)
                                           -> *mut libc::c_void
    where F: for<'a> Fn(&'a str) -> *const ()
{
    let fun = cookie as *mut F;

    let ret = panic::catch_unwind(AssertUnwindSafe( || {
        let name = CStr::from_ptr(name).to_str().unwrap();
        (*fun)(name) as *mut () as *mut libc::c_void
    }));
    if ret.is_ok() {
        ret.unwrap()
    } else {
        ptr::null_mut()
    }
}

/// Holds all state relevant to opengl callback functions.
pub struct OpenGlState  {
    api_ctx: *mut MpvOpenGlCbContext,
    is_empty: bool,
}

impl OpenGlState {
    pub(crate) fn empty() -> OpenGlState {
        OpenGlState{
            api_ctx: ptr::null_mut(),
            is_empty: true,
        }
    }

    pub(crate) fn new<F>(mpv_ctx: *mut MpvHandle, mut proc_addr: F) -> Result<OpenGlState, Error>
        where F: for<'a> Fn(&'a str) -> *const () + 'static
    {
        let api_ctx = unsafe {
            mpv_get_sub_api(mpv_ctx, MpvSubApi::OpenglCb) as *mut MpvOpenGlCbContext
        };
        debug_assert!(!api_ctx.is_null());

        let proc_addr_ptr = &mut proc_addr as *mut F;

        let ret = mpv_err(
            OpenGlState {
                api_ctx: api_ctx,
                is_empty: false,
            },
            unsafe {
                    mpv_opengl_cb_init_gl(api_ctx, ptr::null(),
                                          get_proc_addr_wrapper::<F>,
                                          proc_addr_ptr as *mut libc::c_void)
            }
        );
        if ret.is_ok() {
            mem::forget(proc_addr);
        }
        ret
    }
}

impl Drop for OpenGlState {
    #[inline]
    fn drop(&mut self) {
        if !self.is_empty {
            unsafe {
                mpv_opengl_cb_uninit_gl(self.api_ctx);
            }
        }
    }
}
<commit_msg>[opengl] Add set_draw_target<commit_after>// Copyright (C) 2016  ParadoxSpiral
//
// This file is part of mpv-rs.
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA

use libc;

use super::*;
use super::utils::mpv_err;
use super::super::raw::*;

use std::ffi::CStr;
use std::mem;
use std::panic;
use std::panic::AssertUnwindSafe;
use std::ptr;

unsafe extern "C" fn get_proc_addr_wrapper<F>(cookie: *mut libc::c_void,
                                           name: *const libc::c_char)
                                           -> *mut libc::c_void
    where F: for<'a> Fn(&'a str) -> *const ()
{
    let fun = cookie as *mut F;

    let ret = panic::catch_unwind(AssertUnwindSafe( || {
        let name = CStr::from_ptr(name).to_str().unwrap();
        (*fun)(name) as *mut () as *mut libc::c_void
    }));
    if ret.is_ok() {
        ret.unwrap()
    } else {
        ptr::null_mut()
    }
}

/// Holds all state relevant to opengl callback functions.
pub struct OpenGlState  {
    api_ctx: *mut MpvOpenGlCbContext,
    is_empty: bool,
}

impl OpenGlState {
    pub(crate) fn empty() -> OpenGlState {
        OpenGlState{
            api_ctx: ptr::null_mut(),
            is_empty: true,
        }
    }

    pub(crate) fn new<F>(mpv_ctx: *mut MpvHandle, mut proc_addr: F) -> Result<OpenGlState, Error>
        where F: for<'a> Fn(&'a str) -> *const () + 'static
    {
        let api_ctx = unsafe {
            mpv_get_sub_api(mpv_ctx, MpvSubApi::OpenglCb) as *mut MpvOpenGlCbContext
        };
        debug_assert!(!api_ctx.is_null());

        let proc_addr_ptr = &mut proc_addr as *mut F;

        let ret = mpv_err(
            OpenGlState {
                api_ctx: api_ctx,
                is_empty: false,
            },
            unsafe {
                    mpv_opengl_cb_init_gl(api_ctx, ptr::null(),
                                          get_proc_addr_wrapper::<F>,
                                          proc_addr_ptr as *mut libc::c_void)
            }
        );
        if ret.is_ok() {
            mem::forget(proc_addr);
        }
        ret
    }

    #[inline]
    /// Set the fbo that mpv will draw on.
    /// Passing `0` as `w` or `h` will choose the size of the fbo.
    /// Mpv relies on correct and initialized opengl state.
    pub unsafe fn set_draw_target(&self, fbo: libc::c_int, w: libc::c_int, h: libc::c_int)
        -> Result<(), Error>
    {
        mpv_err((), mpv_opengl_cb_draw(self.api_ctx, fbo, w, h))
    }
}

impl Drop for OpenGlState {
    #[inline]
    fn drop(&mut self) {
        if !self.is_empty {
            unsafe {
                mpv_opengl_cb_uninit_gl(self.api_ctx);
            }
        }
    }
}
<|endoftext|>


<commit_before>//! A simple utility for getting the size of a terminal.
//!
//! Supports both Linux and Windows, but help is needed to test other platforms
//!
//! Tested on Rust Stable (1.4), Beta (1.5), and Nightly (1.6)
//!
//! # Example
//!
//! ```
//! use terminal_size::{Width, Height, terminal_size};
//!
//! let size = terminal_size();
//! if let Some((Width(w), Height(h))) = size {
//!     println!("Your terminal is {} cols wide and {} lines tall", w, h);
//! } else {
//!     println!("Unable to get terminal size");
//! }
//! ```
//!

#[derive(Debug)]
pub struct Width(pub u16);
#[derive(Debug)]
pub struct Height(pub u16);

#[cfg(unix)]
mod unix;
#[cfg(unix)]
pub use crate::unix::{terminal_size, terminal_size_using_fd};

#[cfg(windows)]
mod windows;
#[cfg(windows)]
pub use windows::terminal_size;
<commit_msg>Export new terminal_size_using_handle function<commit_after>//! A simple utility for getting the size of a terminal.
//!
//! Supports both Linux and Windows, but help is needed to test other platforms
//!
//! Tested on Rust Stable (1.4), Beta (1.5), and Nightly (1.6)
//!
//! # Example
//!
//! ```
//! use terminal_size::{Width, Height, terminal_size};
//!
//! let size = terminal_size();
//! if let Some((Width(w), Height(h))) = size {
//!     println!("Your terminal is {} cols wide and {} lines tall", w, h);
//! } else {
//!     println!("Unable to get terminal size");
//! }
//! ```
//!

#[derive(Debug)]
pub struct Width(pub u16);
#[derive(Debug)]
pub struct Height(pub u16);

#[cfg(unix)]
mod unix;
#[cfg(unix)]
pub use crate::unix::{terminal_size, terminal_size_using_fd};

#[cfg(windows)]
mod windows;
#[cfg(windows)]
pub use windows::{terminal_size, terminal_size_using_handle};
<|endoftext|>


<commit_before>use ::std::collections::BTreeMap;
use ::std::collections::BTreeSet;

const DX: [i32; 8] = [-1, 0, 1, -1, 1, -1, 0, 1];
const DY: [i32; 8] = [-1, -1, -1, 0, 0, 1, 1, 1];

#[derive(Eq, Ord, PartialEq, PartialOrd)]
#[derive(Clone)]
pub struct Pos {
    pub x: i32,
    pub y: i32,
}

/// Return new position from `x` and `y`
#[inline]
pub fn pos(x: i32, y: i32) -> Pos {
    Pos {
        x: x,
        y: y,
    }
}

pub struct Neighbors{
    origin: Pos,
    i: usize,
}

pub fn neighbors(origin: &Pos) -> Neighbors {
    Neighbors {
        origin: origin.clone(),
        i: 0,
    }
}

impl Iterator for Neighbors {
    type Item = (Pos, usize);
    fn next(&mut self) -> Option<Self::Item> {
        if self.i >= 8 { None }
        else {
            self.i += 1;
            let j = self.i - 1;
            Some( (pos(self.origin.x+DX[j], self.origin.y+DY[j]), j) )
        }
    }
}

pub struct Map {
    pub neighbors_state: BTreeMap<Pos, u8>,
    alive_cells: BTreeSet<Pos>,
    state_eval_table: [u8; 256],
}

fn new_state_eval_table() -> [u8; 256] {
    let mut result = [0; 256];
    for i in 0..256 {
        let mut count = usize::count_ones(i);
        if count == 3 { result[i] = 2; }
        else if count == 2 { result[i] = 1; }
    }
    result
}

impl Map {
    pub fn print(&self) {
        let vec: Vec<_> = self.alive_cells.iter().map(|pos| (pos.x, pos.y)).collect();
        println!("{:?}", vec);
    }

    pub fn is_empty(&self) -> bool {
        self.alive_cells.is_empty()
    }

    pub fn count_alive_cells(&self) -> usize {
        self.alive_cells.len()
    }

    pub fn check(&self) {
        for (pos, state) in &self.neighbors_state {
            let mut new = 0;
            for (nei, i) in neighbors(&pos) {
                if self.cell_is_alive(&nei) {
                    new |= 1<<i;
                }
            }
            //assert!(new != 0);
            assert_eq!(new, *state);
        }

        for pos in &self.alive_cells {
            for (pos, _) in neighbors(&pos) {
                let state = self.neighbors_state[&pos];
                let mut new = 0;
                for (nei, i) in neighbors(&pos) {
                    if self.cell_is_alive(&nei) {
                        new |= 1<<i;
                    }
                }
                //assert!(new != 0);
                assert_eq!(new, state);
            }
        }
    }

    /// Return a new empty map
    pub fn new() -> Map {
        Map {
            neighbors_state: BTreeMap::new(),
            alive_cells: BTreeSet::new(),
            state_eval_table: new_state_eval_table(),
        }
    }

    /// Return a new map from list of alive cells
    pub fn new_from_alive_list(list: &[Pos]) -> Map {
        let mut result = Map::new();
        for pos in list {
            result.set_cell_alive(&pos);
        }
        result
    }

    /// Generate next generation
    pub fn next_generation(&mut self) {
        let new_alive = self.neighbors_state.iter().filter_map(|(pos, state)| {
            if self.eval_state(*state) == 2 {
                Some(pos.clone())
            } else { None }
        }).collect::<Vec<_>>();
        let new_dead = self.neighbors_state.iter().filter_map(|(pos, state)| {
            if self.eval_state(*state) == 0 {
                Some(pos.clone())
            } else { None }
        }).collect::<Vec<_>>();

        for pos in new_alive {
            self.set_cell_alive(&pos);
        }
        for pos in new_dead {
            self.set_cell_dead(&pos);
        }
        self.check();
    }

    /// Return list of alive cells within the rectangle from `top_left`
    /// to `bottom_right`
    pub fn get_alive_cells_in(&self, top_left: Pos, bottom_right: Pos) -> Vec<Pos> {
        self.alive_cells.iter().filter(|&pos| {
            top_left.x <= pos.x && pos.x <= bottom_right.x &&
            top_left.y <= pos.y && pos.y <= bottom_right.y
        }).cloned().collect()
    }

    /// Force a cell to be alive
    pub fn set_cell_alive(&mut self, pos: &Pos) {
        if self.alive_cells.insert(pos.clone()) {
            let mut new_state = 0;
            for (nei, i) in neighbors(pos) {
                if self.cell_is_alive(&nei) {
                    new_state |= 1<<i;
                }
                let state = self.neighbors_state.entry(nei).or_insert(0);
                *state |= 1<<(7^i);
            }
            let mut state = self.neighbors_state.entry(pos.clone()).or_insert(0);
            *state = new_state;
        }
    }

    /// Kill a cell
    pub fn set_cell_dead(&mut self, pos: &Pos) {
        if self.alive_cells.remove(pos) {
            for (nei, i) in neighbors(pos) {
                let mut rm = false;
                if let Some(mut state) = self.neighbors_state.get_mut(&nei) {
                    *state &= !(1<<(7^i));
                    if *state == 0 {
                        rm = true;
                    }
                }
                if rm && !self.cell_is_alive(&nei) {
                    self.neighbors_state.remove(&nei);
                }
            }
        }
    }

    /// Check if a cell is alive or not
    #[inline]
    pub fn cell_is_alive(&self, pos: &Pos) -> bool {
        self.alive_cells.contains(pos)
    }

    #[inline]
    fn eval_state(&self, state: u8) -> u8 {
        self.state_eval_table[state as usize]
    }
}
<commit_msg>Remove check<commit_after>use ::std::collections::BTreeMap;
use ::std::collections::BTreeSet;

const DX: [i32; 8] = [-1, 0, 1, -1, 1, -1, 0, 1];
const DY: [i32; 8] = [-1, -1, -1, 0, 0, 1, 1, 1];

#[derive(Eq, Ord, PartialEq, PartialOrd)]
#[derive(Clone)]
pub struct Pos {
    pub x: i32,
    pub y: i32,
}

/// Return new position from `x` and `y`
#[inline]
pub fn pos(x: i32, y: i32) -> Pos {
    Pos {
        x: x,
        y: y,
    }
}

pub struct Neighbors{
    origin: Pos,
    i: usize,
}

pub fn neighbors(origin: &Pos) -> Neighbors {
    Neighbors {
        origin: origin.clone(),
        i: 0,
    }
}

impl Iterator for Neighbors {
    type Item = (Pos, usize);
    fn next(&mut self) -> Option<Self::Item> {
        if self.i >= 8 { None }
        else {
            self.i += 1;
            let j = self.i - 1;
            Some( (pos(self.origin.x+DX[j], self.origin.y+DY[j]), j) )
        }
    }
}

pub struct Map {
    pub neighbors_state: BTreeMap<Pos, u8>,
    alive_cells: BTreeSet<Pos>,
    state_eval_table: [u8; 256],
}

fn new_state_eval_table() -> [u8; 256] {
    let mut result = [0; 256];
    for i in 0..256 {
        let mut count = usize::count_ones(i);
        if count == 3 { result[i] = 2; }
        else if count == 2 { result[i] = 1; }
    }
    result
}

impl Map {
    pub fn print(&self) {
        let vec: Vec<_> = self.alive_cells.iter().map(|pos| (pos.x, pos.y)).collect();
        println!("{:?}", vec);
    }

    pub fn is_empty(&self) -> bool {
        self.alive_cells.is_empty()
    }

    pub fn count_alive_cells(&self) -> usize {
        self.alive_cells.len()
    }

    pub fn check(&self) {
        for (pos, state) in &self.neighbors_state {
            let mut new = 0;
            for (nei, i) in neighbors(&pos) {
                if self.cell_is_alive(&nei) {
                    new |= 1<<i;
                }
            }
            //assert!(new != 0);
            assert_eq!(new, *state);
        }

        for pos in &self.alive_cells {
            for (pos, _) in neighbors(&pos) {
                let state = self.neighbors_state[&pos];
                let mut new = 0;
                for (nei, i) in neighbors(&pos) {
                    if self.cell_is_alive(&nei) {
                        new |= 1<<i;
                    }
                }
                //assert!(new != 0);
                assert_eq!(new, state);
            }
        }
    }

    /// Return a new empty map
    pub fn new() -> Map {
        Map {
            neighbors_state: BTreeMap::new(),
            alive_cells: BTreeSet::new(),
            state_eval_table: new_state_eval_table(),
        }
    }

    /// Return a new map from list of alive cells
    pub fn new_from_alive_list(list: &[Pos]) -> Map {
        let mut result = Map::new();
        for pos in list {
            result.set_cell_alive(&pos);
        }
        result
    }

    /// Generate next generation
    pub fn next_generation(&mut self) {
        let new_alive = self.neighbors_state.iter().filter_map(|(pos, state)| {
            if self.eval_state(*state) == 2 {
                Some(pos.clone())
            } else { None }
        }).collect::<Vec<_>>();
        let new_dead = self.neighbors_state.iter().filter_map(|(pos, state)| {
            if self.eval_state(*state) == 0 {
                Some(pos.clone())
            } else { None }
        }).collect::<Vec<_>>();

        for pos in new_alive {
            self.set_cell_alive(&pos);
        }
        for pos in new_dead {
            self.set_cell_dead(&pos);
        }
    }

    /// Return list of alive cells within the rectangle from `top_left`
    /// to `bottom_right`
    pub fn get_alive_cells_in(&self, top_left: Pos, bottom_right: Pos) -> Vec<Pos> {
        self.alive_cells.iter().filter(|&pos| {
            top_left.x <= pos.x && pos.x <= bottom_right.x &&
            top_left.y <= pos.y && pos.y <= bottom_right.y
        }).cloned().collect()
    }

    /// Force a cell to be alive
    pub fn set_cell_alive(&mut self, pos: &Pos) {
        if self.alive_cells.insert(pos.clone()) {
            let mut new_state = 0;
            for (nei, i) in neighbors(pos) {
                if self.cell_is_alive(&nei) {
                    new_state |= 1<<i;
                }
                let state = self.neighbors_state.entry(nei).or_insert(0);
                *state |= 1<<(7^i);
            }
            let mut state = self.neighbors_state.entry(pos.clone()).or_insert(0);
            *state = new_state;
        }
    }

    /// Kill a cell
    pub fn set_cell_dead(&mut self, pos: &Pos) {
        if self.alive_cells.remove(pos) {
            for (nei, i) in neighbors(pos) {
                let mut rm = false;
                if let Some(mut state) = self.neighbors_state.get_mut(&nei) {
                    *state &= !(1<<(7^i));
                    if *state == 0 {
                        rm = true;
                    }
                }
                if rm && !self.cell_is_alive(&nei) {
                    self.neighbors_state.remove(&nei);
                }
            }
        }
    }

    /// Check if a cell is alive or not
    #[inline]
    pub fn cell_is_alive(&self, pos: &Pos) -> bool {
        self.alive_cells.contains(pos)
    }

    #[inline]
    fn eval_state(&self, state: u8) -> u8 {
        self.state_eval_table[state as usize]
    }
}
<|endoftext|>


<commit_before>use libc::{c_void,c_char,c_int,c_long,size_t};
use std;
use std::c_str::CString;
use std::ptr::null;
use std::mem::transmute;
use native;

pub struct Config {
    pub port: uint,
    pub threads: uint
}

impl Config {
    pub fn default() -> Config {
        Config { port: 8888, threads: 50 }
    }
}

#[link(name="civetweb")]
extern {
    fn mg_start(callbacks: *MgCallbacks, user_data: *c_void, options: **c_char) -> *MgContext;
    fn mg_stop(context: *MgContext);
    fn mg_set_request_handler(context: *MgContext, uri: *c_char, handler: MgRequestHandler, data: *c_void);
    fn mg_read(connection: *mut MgConnection, buf: *c_void, len: size_t) -> c_int;
    fn mg_write(connection: *mut MgConnection, data: *c_void, len: size_t) -> c_int;
    fn mg_get_header(connection: *mut MgConnection, name: *c_char) -> *c_char;
    fn mg_get_request_info(connection: *mut MgConnection) -> *MgRequestInfo;
}

enum MgContext {}

pub struct Server(*MgContext);

pub struct ServerCallback<T> {
    callback: fn(&mut Connection, &T) -> Result<(), ()>,
    param: T
}

impl<T> ServerCallback<T> {
    pub fn new(callback: fn(&mut Connection, &T) -> Result<(), ()>, param: T) -> ServerCallback<T> {
        ServerCallback { callback: callback, param: param }
    }
}

impl Server {
    fn as_ref<'a>(&'a self) -> &'a MgContext {
        match *self { Server(context) => unsafe { &*context } }
    }

    pub fn start<T: 'static>(options: Config, callback: ServerCallback<T>) -> Server {
        let Config { port, threads } = options;
        let options = ["listening_ports".to_str(), port.to_str(), "num_threads".to_str(), threads.to_str()];

        let mut server = None;
        let mut cb = Some(box callback);

        options.with_c_strs(true, |options| {
            let context = start(options);
            server = Some(Server(context));

            unsafe { mg_set_request_handler(context, "**".to_c_str().unwrap(), raw_handler::<T>, transmute(cb.take_unwrap())) }
        });

        server.unwrap()
    }
}

impl Drop for Server {
    fn drop(&mut self) {
        unsafe { mg_stop(self.as_ref()) }
    }
}

fn raw_handler<T: 'static>(conn: *mut MgConnection, param: *c_void) -> int {
    let (tx, rx) = channel();
    let callback: &ServerCallback<T> = unsafe { transmute(param) };

    let mut task = native::task::new((0, std::uint::MAX));
    task.death.on_exit = Some(proc(r) tx.send(r));

    let mut result = None;

    task.run(|| {
        let mut connection = Connection(conn);
        result = Some((callback.callback)(&mut connection, &callback.param));
    });

    let _ = rx.recv();

    match result {
        None => 0,
        Some(Err(_)) => 0,
        Some(Ok(_)) => 1
    }
}

pub enum MgConnection {}

pub struct Connection(*mut MgConnection);

impl Connection {
    fn unwrap(&self) -> *mut MgConnection {
        match *self { Connection(conn) => conn }
    }
}

type MgRequestHandler = fn(*mut MgConnection, *c_void) -> int;

#[allow(dead_code)]
struct MgHeader {
    name: *c_char,
    value: *c_char
}

pub struct Header<'a>(*MgHeader);

impl<'a> Header<'a> {
    fn as_ref(&self) -> &'a MgHeader {
        match *self { Header(header) => unsafe { &*header } }
    }

    pub fn name(&self) -> Option<&'a str> {
        to_slice(self.as_ref(), |header| header.name)
    }

    pub fn value(&self) -> Option<&'a str> {
        to_slice(self.as_ref(), |header| header.value)
    }
}

struct MgRequestInfo {
    request_method: *c_char,
    uri: *c_char,
    http_version: *c_char,
    query_string: *c_char,
    remote_user: *c_char,
    remote_ip: c_long,
    remote_port: c_int,
    is_ssl: bool,

    #[allow(dead_code)]
    user_data: *c_void,
    #[allow(dead_code)]
    conn_data: *c_void,

    num_headers: c_int,
    headers: [MgHeader, ..64]
}

pub struct RequestInfo<'a>(*MgRequestInfo);

impl<'a> RequestInfo<'a> {
    pub fn as_ref<'a>(&'a self) -> &'a MgRequestInfo {
        match *self { RequestInfo(info) => unsafe { &*info } }
    }

    pub fn num_headers(&self) -> int {
        self.as_ref().num_headers as int
    }

    pub fn method<'a>(&'a self) -> Option<&'a str> {
        to_slice(self.as_ref(), |info| info.request_method)
    }

    pub fn url<'a>(&'a self) -> Option<&'a str> {
        to_slice(self.as_ref(), |info| info.uri)
    }

    pub fn http_version<'a>(&'a self) -> Option<&'a str> {
        to_slice(self.as_ref(), |info| info.http_version)
    }

    pub fn query_string<'a>(&'a self) -> Option<&'a str> {
        to_slice(self.as_ref(), |info| info.query_string)
    }

    pub fn remote_user<'a>(&'a self) -> Option<&'a str> {
        to_slice(self.as_ref(), |info| info.remote_user)
    }

    pub fn remote_ip(&self) -> int {
        self.as_ref().remote_ip as int
    }

    pub fn remote_port(&self) -> int {
        self.as_ref().remote_port as int
    }

    pub fn is_ssl(&self) -> bool {
        self.as_ref().is_ssl
    }
}

#[allow(dead_code)]
struct MgCallbacks {
    begin_request: *c_void,
    end_request: *c_void,
    log_message: *c_void,
    init_ssl: *c_void,
    websocket_connect: *c_void,
    websocket_ready: *c_void,
    websocket_data: *c_void,
    connection_close: *c_void,
    open_file: *c_void,
    init_lua: *c_void,
    upload: *c_void,
    http_error: *c_void
}

impl MgCallbacks {
    fn new() -> MgCallbacks {
        MgCallbacks {
            begin_request: null(),
            end_request: null(),
            log_message: null(),
            init_ssl: null(),
            websocket_connect: null(),
            websocket_ready: null(),
            websocket_data: null(),
            connection_close: null(),
            open_file: null(),
            init_lua: null(),
            upload: null(),
            http_error: null()
        }
    }
}

fn to_slice<'a, T>(obj: &'a T, callback: |&'a T|:'static -> *c_char) -> Option<&'a str> {
    let chars = callback(obj);

    if unsafe { chars.is_null() || *chars == 0 } {
        return None;
    }

    let c_string = unsafe { CString::new(chars, false) };
    let len = c_string.len();

    unsafe { Some(transmute(std::raw::Slice { data: chars, len: len })) }
}

pub fn start(options: **c_char) -> *MgContext {
    unsafe { mg_start(&MgCallbacks::new(), null(), options) }
}

pub fn read(conn: &Connection, buf: &mut [u8]) -> i32 {
    unsafe { mg_read(conn.unwrap(), buf.as_ptr() as *c_void, buf.len() as u64) }
}

pub fn write(conn: &Connection, bytes: &[u8]) -> i32 {
    let c_bytes = bytes.as_ptr() as *c_void;
    unsafe { mg_write(conn.unwrap(), c_bytes, bytes.len() as u64) }
}

pub fn get_header(conn: &Connection, string: &str) -> Option<String> {
    let cstr = unsafe { mg_get_header(conn.unwrap(), string.to_c_str().unwrap()).to_option() };

    cstr.map(|c| unsafe { CString::new(c, false) }.as_str().to_str())
}

pub fn get_request_info<'a>(conn: &'a Connection) -> Option<RequestInfo<'a>> {
    (unsafe { mg_get_request_info(conn.unwrap()).to_option() }).map(|info| RequestInfo(info))
}

pub fn get_headers<'a>(conn: &'a Connection) -> Vec<Header<'a>> {
    match get_request_info(conn) {
        Some(info) => info.as_ref().headers.iter().map(|h| Header(h)).collect(),
        None => vec!()
    }
}

trait WithCStrs {
    fn with_c_strs(&self, null_terminated: bool, f: |**c_char|) ;
}

impl<'a, T: ToCStr> WithCStrs for &'a [T] {
    fn with_c_strs(&self, null_terminate: bool, f: |**c_char|) {
        let c_strs: Vec<CString> = self.iter().map(|s: &T| s.to_c_str()).collect();
        let mut ptrs: Vec<*c_char> = c_strs.iter().map(|c: &CString| c.with_ref(|ptr| ptr)).collect();
        if null_terminate {
            ptrs.push(null());
        }
        f(ptrs.as_ptr())
    }
}
<commit_msg>Include civetweb as a static library<commit_after>use libc::{c_void,c_char,c_int,c_long,size_t};
use std;
use std::c_str::CString;
use std::ptr::null;
use std::mem::transmute;
use native;

pub struct Config {
    pub port: uint,
    pub threads: uint
}

impl Config {
    pub fn default() -> Config {
        Config { port: 8888, threads: 50 }
    }
}

#[link(name = "civetweb", kind = "static")]
extern {
    fn mg_start(callbacks: *MgCallbacks, user_data: *c_void, options: **c_char) -> *MgContext;
    fn mg_stop(context: *MgContext);
    fn mg_set_request_handler(context: *MgContext, uri: *c_char, handler: MgRequestHandler, data: *c_void);
    fn mg_read(connection: *mut MgConnection, buf: *c_void, len: size_t) -> c_int;
    fn mg_write(connection: *mut MgConnection, data: *c_void, len: size_t) -> c_int;
    fn mg_get_header(connection: *mut MgConnection, name: *c_char) -> *c_char;
    fn mg_get_request_info(connection: *mut MgConnection) -> *MgRequestInfo;
}

enum MgContext {}

pub struct Server(*MgContext);

pub struct ServerCallback<T> {
    callback: fn(&mut Connection, &T) -> Result<(), ()>,
    param: T
}

impl<T> ServerCallback<T> {
    pub fn new(callback: fn(&mut Connection, &T) -> Result<(), ()>, param: T) -> ServerCallback<T> {
        ServerCallback { callback: callback, param: param }
    }
}

impl Server {
    fn as_ref<'a>(&'a self) -> &'a MgContext {
        match *self { Server(context) => unsafe { &*context } }
    }

    pub fn start<T: 'static>(options: Config, callback: ServerCallback<T>) -> Server {
        let Config { port, threads } = options;
        let options = ["listening_ports".to_str(), port.to_str(), "num_threads".to_str(), threads.to_str()];

        let mut server = None;
        let mut cb = Some(box callback);

        options.with_c_strs(true, |options| {
            let context = start(options);
            server = Some(Server(context));

            unsafe { mg_set_request_handler(context, "**".to_c_str().unwrap(), raw_handler::<T>, transmute(cb.take_unwrap())) }
        });

        server.unwrap()
    }
}

impl Drop for Server {
    fn drop(&mut self) {
        unsafe { mg_stop(self.as_ref()) }
    }
}

fn raw_handler<T: 'static>(conn: *mut MgConnection, param: *c_void) -> int {
    let (tx, rx) = channel();
    let callback: &ServerCallback<T> = unsafe { transmute(param) };

    let mut task = native::task::new((0, std::uint::MAX));
    task.death.on_exit = Some(proc(r) tx.send(r));

    let mut result = None;

    task.run(|| {
        let mut connection = Connection(conn);
        result = Some((callback.callback)(&mut connection, &callback.param));
    });

    let _ = rx.recv();

    match result {
        None => 0,
        Some(Err(_)) => 0,
        Some(Ok(_)) => 1
    }
}

pub enum MgConnection {}

pub struct Connection(*mut MgConnection);

impl Connection {
    fn unwrap(&self) -> *mut MgConnection {
        match *self { Connection(conn) => conn }
    }
}

type MgRequestHandler = fn(*mut MgConnection, *c_void) -> int;

#[allow(dead_code)]
struct MgHeader {
    name: *c_char,
    value: *c_char
}

pub struct Header<'a>(*MgHeader);

impl<'a> Header<'a> {
    fn as_ref(&self) -> &'a MgHeader {
        match *self { Header(header) => unsafe { &*header } }
    }

    pub fn name(&self) -> Option<&'a str> {
        to_slice(self.as_ref(), |header| header.name)
    }

    pub fn value(&self) -> Option<&'a str> {
        to_slice(self.as_ref(), |header| header.value)
    }
}

struct MgRequestInfo {
    request_method: *c_char,
    uri: *c_char,
    http_version: *c_char,
    query_string: *c_char,
    remote_user: *c_char,
    remote_ip: c_long,
    remote_port: c_int,
    is_ssl: bool,

    #[allow(dead_code)]
    user_data: *c_void,
    #[allow(dead_code)]
    conn_data: *c_void,

    num_headers: c_int,
    headers: [MgHeader, ..64]
}

pub struct RequestInfo<'a>(*MgRequestInfo);

impl<'a> RequestInfo<'a> {
    pub fn as_ref<'a>(&'a self) -> &'a MgRequestInfo {
        match *self { RequestInfo(info) => unsafe { &*info } }
    }

    pub fn num_headers(&self) -> int {
        self.as_ref().num_headers as int
    }

    pub fn method<'a>(&'a self) -> Option<&'a str> {
        to_slice(self.as_ref(), |info| info.request_method)
    }

    pub fn url<'a>(&'a self) -> Option<&'a str> {
        to_slice(self.as_ref(), |info| info.uri)
    }

    pub fn http_version<'a>(&'a self) -> Option<&'a str> {
        to_slice(self.as_ref(), |info| info.http_version)
    }

    pub fn query_string<'a>(&'a self) -> Option<&'a str> {
        to_slice(self.as_ref(), |info| info.query_string)
    }

    pub fn remote_user<'a>(&'a self) -> Option<&'a str> {
        to_slice(self.as_ref(), |info| info.remote_user)
    }

    pub fn remote_ip(&self) -> int {
        self.as_ref().remote_ip as int
    }

    pub fn remote_port(&self) -> int {
        self.as_ref().remote_port as int
    }

    pub fn is_ssl(&self) -> bool {
        self.as_ref().is_ssl
    }
}

#[allow(dead_code)]
struct MgCallbacks {
    begin_request: *c_void,
    end_request: *c_void,
    log_message: *c_void,
    init_ssl: *c_void,
    websocket_connect: *c_void,
    websocket_ready: *c_void,
    websocket_data: *c_void,
    connection_close: *c_void,
    open_file: *c_void,
    init_lua: *c_void,
    upload: *c_void,
    http_error: *c_void
}

impl MgCallbacks {
    fn new() -> MgCallbacks {
        MgCallbacks {
            begin_request: null(),
            end_request: null(),
            log_message: null(),
            init_ssl: null(),
            websocket_connect: null(),
            websocket_ready: null(),
            websocket_data: null(),
            connection_close: null(),
            open_file: null(),
            init_lua: null(),
            upload: null(),
            http_error: null()
        }
    }
}

fn to_slice<'a, T>(obj: &'a T, callback: |&'a T|:'static -> *c_char) -> Option<&'a str> {
    let chars = callback(obj);

    if unsafe { chars.is_null() || *chars == 0 } {
        return None;
    }

    let c_string = unsafe { CString::new(chars, false) };
    let len = c_string.len();

    unsafe { Some(transmute(std::raw::Slice { data: chars, len: len })) }
}

pub fn start(options: **c_char) -> *MgContext {
    unsafe { mg_start(&MgCallbacks::new(), null(), options) }
}

pub fn read(conn: &Connection, buf: &mut [u8]) -> i32 {
    unsafe { mg_read(conn.unwrap(), buf.as_ptr() as *c_void, buf.len() as u64) }
}

pub fn write(conn: &Connection, bytes: &[u8]) -> i32 {
    let c_bytes = bytes.as_ptr() as *c_void;
    unsafe { mg_write(conn.unwrap(), c_bytes, bytes.len() as u64) }
}

pub fn get_header(conn: &Connection, string: &str) -> Option<String> {
    let cstr = unsafe { mg_get_header(conn.unwrap(), string.to_c_str().unwrap()).to_option() };

    cstr.map(|c| unsafe { CString::new(c, false) }.as_str().to_str())
}

pub fn get_request_info<'a>(conn: &'a Connection) -> Option<RequestInfo<'a>> {
    (unsafe { mg_get_request_info(conn.unwrap()).to_option() }).map(|info| RequestInfo(info))
}

pub fn get_headers<'a>(conn: &'a Connection) -> Vec<Header<'a>> {
    match get_request_info(conn) {
        Some(info) => info.as_ref().headers.iter().map(|h| Header(h)).collect(),
        None => vec!()
    }
}

trait WithCStrs {
    fn with_c_strs(&self, null_terminated: bool, f: |**c_char|) ;
}

impl<'a, T: ToCStr> WithCStrs for &'a [T] {
    fn with_c_strs(&self, null_terminate: bool, f: |**c_char|) {
        let c_strs: Vec<CString> = self.iter().map(|s: &T| s.to_c_str()).collect();
        let mut ptrs: Vec<*c_char> = c_strs.iter().map(|c: &CString| c.with_ref(|ptr| ptr)).collect();
        if null_terminate {
            ptrs.push(null());
        }
        f(ptrs.as_ptr())
    }
}
<|endoftext|>


<commit_before>use libc::{c_void,c_char,c_int,c_long,size_t};
use std;
use std::c_str::CString;
use std::ptr::null;
use std::mem::transmute;
use native;

pub struct Config {
    pub port: uint,
    pub threads: uint
}

impl Config {
    pub fn default() -> Config {
        Config { port: 8888, threads: 50 }
    }
}

#[link(name = "civetweb", kind = "static")]
extern {
    fn mg_start(callbacks: *MgCallbacks, user_data: *c_void, options: **c_char) -> *MgContext;
    fn mg_stop(context: *MgContext);
    fn mg_set_request_handler(context: *MgContext, uri: *c_char, handler: MgRequestHandler, data: *c_void);
    fn mg_read(connection: *mut MgConnection, buf: *c_void, len: size_t) -> c_int;
    fn mg_write(connection: *mut MgConnection, data: *c_void, len: size_t) -> c_int;
    fn mg_get_header(connection: *mut MgConnection, name: *c_char) -> *c_char;
    fn mg_get_request_info(connection: *mut MgConnection) -> *MgRequestInfo;
}

enum MgContext {}

pub struct Server(*MgContext);

pub struct ServerCallback<T> {
    callback: fn(&mut Connection, &T) -> Result<(), ()>,
    param: T
}

impl<T> ServerCallback<T> {
    pub fn new(callback: fn(&mut Connection, &T) -> Result<(), ()>, param: T) -> ServerCallback<T> {
        ServerCallback { callback: callback, param: param }
    }
}

impl Server {
    fn as_ref<'a>(&'a self) -> &'a MgContext {
        match *self { Server(context) => unsafe { &*context } }
    }

    pub fn start<T: 'static>(options: Config, callback: ServerCallback<T>) -> Server {
        let Config { port, threads } = options;
        let options = vec!(
            "listening_ports".to_c_str(), port.to_str().to_c_str(),
            "num_threads".to_c_str(), threads.to_str().to_c_str(),
        );
        let mut ptrs: Vec<_> = options.iter().map(|a| a.with_ref(|p| p)).collect();
        ptrs.push(0 as *_);

        let context = start(ptrs.as_ptr());
        let uri = "**".to_c_str();
        unsafe {
            mg_set_request_handler(context, uri.with_ref(|p| p),
                                   raw_handler::<T>,
                                   transmute(box callback));
        }
        Server(context)
    }
}

impl Drop for Server {
    fn drop(&mut self) {
        unsafe { mg_stop(self.as_ref()) }
    }
}

fn raw_handler<T: 'static>(conn: *mut MgConnection, param: *c_void) -> int {
    let (tx, rx) = channel();
    let callback: &ServerCallback<T> = unsafe { transmute(param) };

    let mut task = native::task::new((0, std::uint::MAX));
    task.death.on_exit = Some(proc(r) tx.send(r));

    let mut result = None;

    task.run(|| {
        let mut connection = Connection(conn);
        result = Some((callback.callback)(&mut connection, &callback.param));
    });

    let _ = rx.recv();

    match result {
        None => 0,
        Some(Err(_)) => 0,
        Some(Ok(_)) => 1
    }
}

pub enum MgConnection {}

pub struct Connection(*mut MgConnection);

impl Connection {
    fn unwrap(&self) -> *mut MgConnection {
        match *self { Connection(conn) => conn }
    }
}

type MgRequestHandler = fn(*mut MgConnection, *c_void) -> int;

#[allow(dead_code)]
struct MgHeader {
    name: *c_char,
    value: *c_char
}

pub struct Header<'a>(*MgHeader);

impl<'a> Header<'a> {
    fn as_ref(&self) -> &'a MgHeader {
        match *self { Header(header) => unsafe { &*header } }
    }

    pub fn name(&self) -> Option<&'a str> {
        to_slice(self.as_ref(), |header| header.name)
    }

    pub fn value(&self) -> Option<&'a str> {
        to_slice(self.as_ref(), |header| header.value)
    }
}

struct MgRequestInfo {
    request_method: *c_char,
    uri: *c_char,
    http_version: *c_char,
    query_string: *c_char,
    remote_user: *c_char,
    remote_ip: c_long,
    remote_port: c_int,
    is_ssl: bool,

    #[allow(dead_code)]
    user_data: *c_void,
    #[allow(dead_code)]
    conn_data: *c_void,

    num_headers: c_int,
    headers: [MgHeader, ..64]
}

pub struct RequestInfo<'a>(*MgRequestInfo);

impl<'a> RequestInfo<'a> {
    pub fn as_ref<'a>(&'a self) -> &'a MgRequestInfo {
        match *self { RequestInfo(info) => unsafe { &*info } }
    }

    pub fn num_headers(&self) -> int {
        self.as_ref().num_headers as int
    }

    pub fn method<'a>(&'a self) -> Option<&'a str> {
        to_slice(self.as_ref(), |info| info.request_method)
    }

    pub fn url<'a>(&'a self) -> Option<&'a str> {
        to_slice(self.as_ref(), |info| info.uri)
    }

    pub fn http_version<'a>(&'a self) -> Option<&'a str> {
        to_slice(self.as_ref(), |info| info.http_version)
    }

    pub fn query_string<'a>(&'a self) -> Option<&'a str> {
        to_slice(self.as_ref(), |info| info.query_string)
    }

    pub fn remote_user<'a>(&'a self) -> Option<&'a str> {
        to_slice(self.as_ref(), |info| info.remote_user)
    }

    pub fn remote_ip(&self) -> int {
        self.as_ref().remote_ip as int
    }

    pub fn remote_port(&self) -> int {
        self.as_ref().remote_port as int
    }

    pub fn is_ssl(&self) -> bool {
        self.as_ref().is_ssl
    }
}

#[allow(dead_code)]
struct MgCallbacks {
    begin_request: *c_void,
    end_request: *c_void,
    log_message: *c_void,
    init_ssl: *c_void,
    websocket_connect: *c_void,
    websocket_ready: *c_void,
    websocket_data: *c_void,
    connection_close: *c_void,
    open_file: *c_void,
    init_lua: *c_void,
    upload: *c_void,
    http_error: *c_void
}

impl MgCallbacks {
    fn new() -> MgCallbacks {
        MgCallbacks {
            begin_request: null(),
            end_request: null(),
            log_message: null(),
            init_ssl: null(),
            websocket_connect: null(),
            websocket_ready: null(),
            websocket_data: null(),
            connection_close: null(),
            open_file: null(),
            init_lua: null(),
            upload: null(),
            http_error: null()
        }
    }
}

fn to_slice<'a, T>(obj: &'a T, callback: |&'a T|:'static -> *c_char) -> Option<&'a str> {
    let chars = callback(obj);

    if unsafe { chars.is_null() || *chars == 0 } {
        return None;
    }

    let c_string = unsafe { CString::new(chars, false) };
    let len = c_string.len();

    unsafe { Some(transmute(std::raw::Slice { data: chars, len: len })) }
}

pub fn start(options: **c_char) -> *MgContext {
    unsafe { mg_start(&MgCallbacks::new(), null(), options) }
}

pub fn read(conn: &Connection, buf: &mut [u8]) -> i32 {
    unsafe { mg_read(conn.unwrap(), buf.as_ptr() as *c_void, buf.len() as size_t) }
}

pub fn write(conn: &Connection, bytes: &[u8]) -> i32 {
    let c_bytes = bytes.as_ptr() as *c_void;
    unsafe { mg_write(conn.unwrap(), c_bytes, bytes.len() as size_t) }
}

pub fn get_header(conn: &Connection, string: &str) -> Option<String> {
    let cstr = unsafe { mg_get_header(conn.unwrap(), string.to_c_str().unwrap()).to_option() };

    cstr.map(|c| unsafe { CString::new(c, false) }.as_str().to_str())
}

pub fn get_request_info<'a>(conn: &'a Connection) -> Option<RequestInfo<'a>> {
    (unsafe { mg_get_request_info(conn.unwrap()).to_option() }).map(|info| RequestInfo(info))
}

pub fn get_headers<'a>(conn: &'a Connection) -> Vec<Header<'a>> {
    match get_request_info(conn) {
        Some(info) => info.as_ref().headers.iter().map(|h| Header(h)).collect(),
        None => vec!()
    }
}
<commit_msg>Don't need the channel for tasks<commit_after>use libc::{c_void,c_char,c_int,c_long,size_t};
use std;
use std::c_str::CString;
use std::ptr::null;
use std::mem::transmute;
use native;

pub struct Config {
    pub port: uint,
    pub threads: uint
}

impl Config {
    pub fn default() -> Config {
        Config { port: 8888, threads: 50 }
    }
}

#[link(name = "civetweb", kind = "static")]
extern {
    fn mg_start(callbacks: *MgCallbacks, user_data: *c_void, options: **c_char) -> *MgContext;
    fn mg_stop(context: *MgContext);
    fn mg_set_request_handler(context: *MgContext, uri: *c_char, handler: MgRequestHandler, data: *c_void);
    fn mg_read(connection: *mut MgConnection, buf: *c_void, len: size_t) -> c_int;
    fn mg_write(connection: *mut MgConnection, data: *c_void, len: size_t) -> c_int;
    fn mg_get_header(connection: *mut MgConnection, name: *c_char) -> *c_char;
    fn mg_get_request_info(connection: *mut MgConnection) -> *MgRequestInfo;
}

enum MgContext {}

pub struct Server(*MgContext);

pub struct ServerCallback<T> {
    callback: fn(&mut Connection, &T) -> Result<(), ()>,
    param: T
}

impl<T> ServerCallback<T> {
    pub fn new(callback: fn(&mut Connection, &T) -> Result<(), ()>, param: T) -> ServerCallback<T> {
        ServerCallback { callback: callback, param: param }
    }
}

impl Server {
    fn as_ref<'a>(&'a self) -> &'a MgContext {
        match *self { Server(context) => unsafe { &*context } }
    }

    pub fn start<T: 'static>(options: Config, callback: ServerCallback<T>) -> Server {
        let Config { port, threads } = options;
        let options = vec!(
            "listening_ports".to_c_str(), port.to_str().to_c_str(),
            "num_threads".to_c_str(), threads.to_str().to_c_str(),
        );
        let mut ptrs: Vec<_> = options.iter().map(|a| a.with_ref(|p| p)).collect();
        ptrs.push(0 as *_);

        let context = start(ptrs.as_ptr());
        let uri = "**".to_c_str();
        unsafe {
            mg_set_request_handler(context, uri.with_ref(|p| p),
                                   raw_handler::<T>,
                                   transmute(box callback));
        }
        Server(context)
    }
}

impl Drop for Server {
    fn drop(&mut self) {
        unsafe { mg_stop(self.as_ref()) }
    }
}

fn raw_handler<T: 'static>(conn: *mut MgConnection, param: *c_void) -> int {
    let callback: &ServerCallback<T> = unsafe { transmute(param) };
    let task = native::task::new((0, std::uint::MAX));
    let mut result = None;

    task.run(|| {
        let mut connection = Connection(conn);
        result = Some((callback.callback)(&mut connection, &callback.param));
    });

    match result {
        None => 0,
        Some(Err(_)) => 0,
        Some(Ok(_)) => 1
    }
}

pub enum MgConnection {}

pub struct Connection(*mut MgConnection);

impl Connection {
    fn unwrap(&self) -> *mut MgConnection {
        match *self { Connection(conn) => conn }
    }
}

type MgRequestHandler = fn(*mut MgConnection, *c_void) -> int;

#[allow(dead_code)]
struct MgHeader {
    name: *c_char,
    value: *c_char
}

pub struct Header<'a>(*MgHeader);

impl<'a> Header<'a> {
    fn as_ref(&self) -> &'a MgHeader {
        match *self { Header(header) => unsafe { &*header } }
    }

    pub fn name(&self) -> Option<&'a str> {
        to_slice(self.as_ref(), |header| header.name)
    }

    pub fn value(&self) -> Option<&'a str> {
        to_slice(self.as_ref(), |header| header.value)
    }
}

struct MgRequestInfo {
    request_method: *c_char,
    uri: *c_char,
    http_version: *c_char,
    query_string: *c_char,
    remote_user: *c_char,
    remote_ip: c_long,
    remote_port: c_int,
    is_ssl: bool,

    #[allow(dead_code)]
    user_data: *c_void,
    #[allow(dead_code)]
    conn_data: *c_void,

    num_headers: c_int,
    headers: [MgHeader, ..64]
}

pub struct RequestInfo<'a>(*MgRequestInfo);

impl<'a> RequestInfo<'a> {
    pub fn as_ref<'a>(&'a self) -> &'a MgRequestInfo {
        match *self { RequestInfo(info) => unsafe { &*info } }
    }

    pub fn num_headers(&self) -> int {
        self.as_ref().num_headers as int
    }

    pub fn method<'a>(&'a self) -> Option<&'a str> {
        to_slice(self.as_ref(), |info| info.request_method)
    }

    pub fn url<'a>(&'a self) -> Option<&'a str> {
        to_slice(self.as_ref(), |info| info.uri)
    }

    pub fn http_version<'a>(&'a self) -> Option<&'a str> {
        to_slice(self.as_ref(), |info| info.http_version)
    }

    pub fn query_string<'a>(&'a self) -> Option<&'a str> {
        to_slice(self.as_ref(), |info| info.query_string)
    }

    pub fn remote_user<'a>(&'a self) -> Option<&'a str> {
        to_slice(self.as_ref(), |info| info.remote_user)
    }

    pub fn remote_ip(&self) -> int {
        self.as_ref().remote_ip as int
    }

    pub fn remote_port(&self) -> int {
        self.as_ref().remote_port as int
    }

    pub fn is_ssl(&self) -> bool {
        self.as_ref().is_ssl
    }
}

#[allow(dead_code)]
struct MgCallbacks {
    begin_request: *c_void,
    end_request: *c_void,
    log_message: *c_void,
    init_ssl: *c_void,
    websocket_connect: *c_void,
    websocket_ready: *c_void,
    websocket_data: *c_void,
    connection_close: *c_void,
    open_file: *c_void,
    init_lua: *c_void,
    upload: *c_void,
    http_error: *c_void
}

impl MgCallbacks {
    fn new() -> MgCallbacks {
        MgCallbacks {
            begin_request: null(),
            end_request: null(),
            log_message: null(),
            init_ssl: null(),
            websocket_connect: null(),
            websocket_ready: null(),
            websocket_data: null(),
            connection_close: null(),
            open_file: null(),
            init_lua: null(),
            upload: null(),
            http_error: null()
        }
    }
}

fn to_slice<'a, T>(obj: &'a T, callback: |&'a T|:'static -> *c_char) -> Option<&'a str> {
    let chars = callback(obj);

    if unsafe { chars.is_null() || *chars == 0 } {
        return None;
    }

    let c_string = unsafe { CString::new(chars, false) };
    let len = c_string.len();

    unsafe { Some(transmute(std::raw::Slice { data: chars, len: len })) }
}

pub fn start(options: **c_char) -> *MgContext {
    unsafe { mg_start(&MgCallbacks::new(), null(), options) }
}

pub fn read(conn: &Connection, buf: &mut [u8]) -> i32 {
    unsafe { mg_read(conn.unwrap(), buf.as_ptr() as *c_void, buf.len() as size_t) }
}

pub fn write(conn: &Connection, bytes: &[u8]) -> i32 {
    let c_bytes = bytes.as_ptr() as *c_void;
    unsafe { mg_write(conn.unwrap(), c_bytes, bytes.len() as size_t) }
}

pub fn get_header(conn: &Connection, string: &str) -> Option<String> {
    let cstr = unsafe { mg_get_header(conn.unwrap(), string.to_c_str().unwrap()).to_option() };

    cstr.map(|c| unsafe { CString::new(c, false) }.as_str().to_str())
}

pub fn get_request_info<'a>(conn: &'a Connection) -> Option<RequestInfo<'a>> {
    (unsafe { mg_get_request_info(conn.unwrap()).to_option() }).map(|info| RequestInfo(info))
}

pub fn get_headers<'a>(conn: &'a Connection) -> Vec<Header<'a>> {
    match get_request_info(conn) {
        Some(info) => info.as_ref().headers.iter().map(|h| Header(h)).collect(),
        None => vec!()
    }
}
<|endoftext|>


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

use std::fmt;
use std::str::FromStr;
use std::num;
use std::str;

#[derive(Clone, PartialEq, Eq)]
pub struct Url {
    pub scheme: String,
    pub user: Option<UserInfo>,
    pub host: String,
    pub port: Option<u16>,
    pub path: Path,
}

#[derive(Clone, PartialEq, Eq)]
pub struct Path {
    pub path: String,
    pub query: Query,
    pub fragment: Option<String>
}

#[derive(Clone, PartialEq, Eq)]
pub struct UserInfo {
    pub user: String,
    pub pass: Option<String>
}

pub type Query = Vec<(String, String)>;

impl Url {
    pub fn new(scheme: String,
               user: Option<UserInfo>,
               host: String,
               port: Option<u16>,
               path: String,
               query: Query,
               fragment: Option<String>)
               -> Url {
        Url {
            scheme: scheme,
            user: user,
            host: host,
            port: port,
            path: Path::new(path, query, fragment)
        }
    }

    pub fn parse(rawurl: &str) -> DecodeResult<Url> {
        // scheme
        let (scheme, rest) = try!(get_scheme(rawurl));

        // authority
        let (userinfo, host, port, rest) = try!(get_authority(rest));

        // path
        let has_authority = host.len() > 0;
        let (path, rest) = try!(get_path(rest, has_authority));

        // query and fragment
        let (query, fragment) = try!(get_query_fragment(rest));

        let url = Url::new(scheme.to_string(),
                            userinfo,
                            host.to_string(),
                            port,
                            path,
                            query,
                            fragment);
        Ok(url)
    }
}

impl Path {
    pub fn new(path: String,
               query: Query,
               fragment: Option<String>)
               -> Path {
        Path {
            path: path,
            query: query,
            fragment: fragment,
        }
    }

    pub fn parse(rawpath: &str) -> DecodeResult<Path> {
        let (path, rest) = try!(get_path(rawpath, false));

        // query and fragment
        let (query, fragment) = try!(get_query_fragment(rest.as_slice()));

        Ok(Path{ path: path, query: query, fragment: fragment })
    }
}

impl UserInfo {
    #[inline]
    pub fn new(user: String, pass: Option<String>) -> UserInfo {
        UserInfo { user: user, pass: pass }
    }
}

pub type DecodeResult<T> = Result<T, String>;

pub fn decode_component(container: &str) -> DecodeResult<String> {
    decode_inner(container, false)
}

fn decode_inner(c: &str, full_url: bool) -> DecodeResult<String> {
    let mut out = String::new();
    let mut iter = c.as_bytes().iter().map(|&b| b);

    loop {
        match iter.next() {
            Some(b) => match b as char {
                '%' => {
                    let bytes = match (iter.next(), iter.next()) {
                        (Some(one), Some(two)) => [one as u8, two as u8],
                        _ => return Err(format!("Malformed input: found '%' \
                                                without two trailing bytes")),
                    };

                    // Only decode some characters if full_url:
                    match num::from_str_radix::<usize>(str::from_utf8(&bytes).unwrap(), 16).unwrap() as u8 as char {
                        // gen-delims:
                        ':' | '/' | '?' | '#' | '[' | ']' | '@' |

                        // sub-delims:
                        '!' | '$' | '&' | '"' | '(' | ')' | '*' |
                        '+' | ',' | ';' | '='
                            if full_url => {
                            out.push('%');
                            out.push(bytes[0] as char);
                            out.push(bytes[1] as char);
                        }

                        ch => out.push(ch)
                    }
                }
                ch => out.push(ch)
            },
            None => return Ok(out),
        }
    }
}

fn split_char_first(s: &str, c: char) -> (&str, &str) {
    let mut iter = s.splitn(1, c);

    match (iter.next(), iter.next()) {
        (Some(a), Some(b)) => (a, b),
        (Some(a), None) => (a, ""),
        (None, _) => unreachable!(),
    }
}

impl fmt::Debug for UserInfo {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self.pass {
            Some(ref pass) => write!(f, "{}:{}@", self.user, *pass),
            None => write!(f, "{}@", self.user),
        }
    }
}

fn query_from_str(rawquery: &str) -> DecodeResult<Query> {
    let mut query: Query = vec!();
    if !rawquery.is_empty() {
        for p in rawquery.split('&') {
            let (k, v) = split_char_first(p, '=');
            query.push((try!(decode_component(k)),
                        try!(decode_component(v))));
        }
    }

    Ok(query)
}

pub fn get_scheme(rawurl: &str) -> DecodeResult<(&str, &str)> {
    for (i,c) in rawurl.chars().enumerate() {
        let result = match c {
            'A' ... 'Z'
            | 'a' ... 'z' => continue,
            '0' ... '9' | '+' | '-' | '.' => {
                if i != 0 { continue }

                Err("url: Scheme must begin with a letter.".to_string())
            }
            ':' => {
                if i == 0 {
                    Err("url: Scheme cannot be empty.".to_string())
                } else {
                    Ok((&rawurl[0..i], &rawurl[i+1..rawurl.len()]))
                }
            }
            _ => Err("url: Invalid character in scheme.".to_string()),
        };

        return result;
    }

    Err("url: Scheme must be terminated with a colon.".to_string())
}

// returns userinfo, host, port, and unparsed part, or an error
fn get_authority(rawurl: &str) ->
    DecodeResult<(Option<UserInfo>, &str, Option<u16>, &str)> {
    enum State {
        Start, // starting state
        PassHostPort, // could be in user or port
        Ip6Port, // either in ipv6 host or port
        Ip6Host, // are in an ipv6 host
        InHost, // are in a host - may be ipv6, but don't know yet
        InPort // are in port
    }

    #[derive(Clone, PartialEq)]
    enum Input {
        Digit, // all digits
        Hex, // digits and letters a-f
        Unreserved // all other legal characters
    }

    if !rawurl.starts_with("//") {
        // there is no authority.
        return Ok((None, "", None, rawurl));
    }

    let len = rawurl.len();
    let mut st = State::Start;
    let mut input = Input::Digit; // most restricted, start here.

    let mut userinfo = None;
    let mut host = "";
    let mut port = None;

    let mut colon_count = 0us;
    let mut pos = 0;
    let mut begin = 2;
    let mut end = len;

    for (i,c) in rawurl.chars().enumerate()
                               // ignore the leading '//' handled by early return
                               .skip(2) {
        // deal with input class first
        match c {
            '0' ... '9' => (),
            'A' ... 'F'
            | 'a' ... 'f' => {
                if input == Input::Digit {
                    input = Input::Hex;
                }
            }
            'G' ... 'Z'
            | 'g' ... 'z'
            | '-' | '.' | '_' | '~' | '%'
            | '&' |'\'' | '(' | ')' | '+'
            | '!' | '*' | ',' | ';' | '=' => input = Input::Unreserved,
            ':' | '@' | '?' | '#' | '/' => {
                // separators, don't change anything
            }
            _ => return Err("Illegal character in authority".to_string()),
        }

        // now process states
        match c {
          ':' => {
            colon_count += 1;
            match st {
              State::Start => {
                pos = i;
                st = State::PassHostPort;
              }
              State::PassHostPort => {
                // multiple colons means ipv6 address.
                if input == Input::Unreserved {
                    return Err(
                        "Illegal characters in IPv6 address.".to_string());
                }
                st = State::Ip6Host;
              }
              State::InHost => {
                pos = i;
                if input == Input::Unreserved {
                    // must be port
                    host = &rawurl[begin..i];
                    st = State::InPort;
                } else {
                    // can't be sure whether this is an ipv6 address or a port
                    st = State::Ip6Port;
                }
              }
              State::Ip6Port => {
                if input == Input::Unreserved {
                    return Err("Illegal characters in authority.".to_string());
                }
                st = State::Ip6Host;
              }
              State::Ip6Host => {
                if colon_count > 7 {
                    host = &rawurl[begin..i];
                    pos = i;
                    st = State::InPort;
                }
              }
              _ => return Err("Invalid ':' in authority.".to_string()),
            }
            input = Input::Digit; // reset input class
          }

          '@' => {
            input = Input::Digit; // reset input class
            colon_count = 0; // reset count
            match st {
              State::Start => {
                let user = rawurl[begin..i].to_string();
                userinfo = Some(UserInfo::new(user, None));
                st = State::InHost;
              }
              State::PassHostPort => {
                let user = rawurl[begin..pos].to_string();
                let pass = rawurl[pos+1..i].to_string();
                userinfo = Some(UserInfo::new(user, Some(pass)));
                st = State::InHost;
              }
              _ => return Err("Invalid '@' in authority.".to_string()),
            }
            begin = i+1;
          }

          '?' | '#' | '/' => {
            end = i;
            break;
          }
          _ => ()
        }
    }

    // finish up
    match st {
      State::Start => host = &rawurl[begin..end],
      State::PassHostPort
      | State::Ip6Port => {
        if input != Input::Digit {
            return Err("Non-digit characters in port.".to_string());
        }
        host = &rawurl[begin..pos];
        port = Some(&rawurl[pos+1..end]);
      }
      State::Ip6Host
      | State::InHost => host = &rawurl[begin..end],
      State::InPort => {
        if input != Input::Digit {
            return Err("Non-digit characters in port.".to_string());
        }
        port = Some(&rawurl[pos+1..end]);
      }
    }

    let rest = &rawurl[end..len];
    // If we have a port string, ensure it parses to u16.
    let port = match port {
        None => None,
        opt => match opt.and_then(|p| FromStr::from_str(p).ok()) {
            None => return Err(format!("Failed to parse port: {:?}", port)),
            opt => opt
        }
    };

    Ok((userinfo, host, port, rest))
}

// returns the path and unparsed part of url, or an error
fn get_path(rawurl: &str, is_authority: bool) -> DecodeResult<(String, &str)> {
    let len = rawurl.len();
    let mut end = len;
    for (i,c) in rawurl.chars().enumerate() {
        match c {
          'A' ... 'Z'
          | 'a' ... 'z'
          | '0' ... '9'
          | '&' |'\'' | '(' | ')' | '.'
          | '@' | ':' | '%' | '/' | '+'
          | '!' | '*' | ',' | ';' | '='
          | '_' | '-' | '~' => continue,
          '?' | '#' => {
            end = i;
            break;
          }
          _ => return Err("Invalid character in path.".to_string())
        }
    }

    if is_authority && end != 0 && !rawurl.starts_with("/") {
        Err("Non-empty path must begin with \
            '/' in presence of authority.".to_string())
    } else {
        Ok((try!(decode_component(&rawurl[0..end])), &rawurl[end..len]))
    }
}

// returns the parsed query and the fragment, if present
fn get_query_fragment(rawurl: &str) -> DecodeResult<(Query, Option<String>)> {
    let (before_fragment, raw_fragment) = split_char_first(rawurl, '#');

    // Parse the fragment if available
    let fragment = match raw_fragment {
        "" => None,
        raw => Some(try!(decode_component(raw)))
    };

    match before_fragment.slice_shift_char() {
        Some(('?', rest)) => Ok((try!(query_from_str(rest)), fragment)),
        None => Ok((vec!(), fragment)),
        _ => Err(format!("Query didn't start with '?': '{}..'", before_fragment)),
    }
}

impl FromStr for Url {
    type Err = String;
    fn from_str(s: &str) -> Result<Url, String> {
        Url::parse(s)
    }
}

impl FromStr for Path {
    type Err = String;
    fn from_str(s: &str) -> Result<Path, String> {
        Path::parse(s)
    }
}

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

use std::fmt;
use std::str::FromStr;
use std::num;
use std::str;

#[derive(Clone, PartialEq, Eq)]
pub struct Url {
    pub scheme: String,
    pub user: Option<UserInfo>,
    pub host: String,
    pub port: Option<u16>,
    pub path: Path,
}

#[derive(Clone, PartialEq, Eq)]
pub struct Path {
    pub path: String,
    pub query: Query,
    pub fragment: Option<String>
}

#[derive(Clone, PartialEq, Eq)]
pub struct UserInfo {
    pub user: String,
    pub pass: Option<String>
}

pub type Query = Vec<(String, String)>;

impl Url {
    pub fn new(scheme: String,
               user: Option<UserInfo>,
               host: String,
               port: Option<u16>,
               path: String,
               query: Query,
               fragment: Option<String>)
               -> Url {
        Url {
            scheme: scheme,
            user: user,
            host: host,
            port: port,
            path: Path::new(path, query, fragment)
        }
    }

    pub fn parse(rawurl: &str) -> DecodeResult<Url> {
        // scheme
        let (scheme, rest) = try!(get_scheme(rawurl));

        // authority
        let (userinfo, host, port, rest) = try!(get_authority(rest));

        // path
        let has_authority = host.len() > 0;
        let (path, rest) = try!(get_path(rest, has_authority));

        // query and fragment
        let (query, fragment) = try!(get_query_fragment(rest));

        let url = Url::new(scheme.to_string(),
                            userinfo,
                            host.to_string(),
                            port,
                            path,
                            query,
                            fragment);
        Ok(url)
    }
}

impl Path {
    pub fn new(path: String,
               query: Query,
               fragment: Option<String>)
               -> Path {
        Path {
            path: path,
            query: query,
            fragment: fragment,
        }
    }

    pub fn parse(rawpath: &str) -> DecodeResult<Path> {
        let (path, rest) = try!(get_path(rawpath, false));

        // query and fragment
        let (query, fragment) = try!(get_query_fragment(rest.as_slice()));

        Ok(Path{ path: path, query: query, fragment: fragment })
    }
}

impl UserInfo {
    #[inline]
    pub fn new(user: String, pass: Option<String>) -> UserInfo {
        UserInfo { user: user, pass: pass }
    }
}

pub type DecodeResult<T> = Result<T, String>;

pub fn decode_component(container: &str) -> DecodeResult<String> {
    decode_inner(container, false)
}

fn decode_inner(c: &str, full_url: bool) -> DecodeResult<String> {
    let mut out = String::new();
    let mut iter = c.as_bytes().iter().map(|&b| b);

    loop {
        match iter.next() {
            Some(b) => match b as char {
                '%' => {
                    let bytes = match (iter.next(), iter.next()) {
                        (Some(one), Some(two)) => [one as u8, two as u8],
                        _ => return Err(format!("Malformed input: found '%' \
                                                without two trailing bytes")),
                    };

                    // Only decode some characters if full_url:
                    match num::from_str_radix::<usize>(str::from_utf8(&bytes).unwrap(), 16).unwrap() as u8 as char {
                        // gen-delims:
                        ':' | '/' | '?' | '#' | '[' | ']' | '@' |

                        // sub-delims:
                        '!' | '$' | '&' | '"' | '(' | ')' | '*' |
                        '+' | ',' | ';' | '='
                            if full_url => {
                            out.push('%');
                            out.push(bytes[0] as char);
                            out.push(bytes[1] as char);
                        }

                        ch => out.push(ch)
                    }
                }
                ch => out.push(ch)
            },
            None => return Ok(out),
        }
    }
}

fn split_char_first(s: &str, c: char) -> (&str, &str) {
    let mut iter = s.splitn(1, c);

    match (iter.next(), iter.next()) {
        (Some(a), Some(b)) => (a, b),
        (Some(a), None) => (a, ""),
        (None, _) => unreachable!(),
    }
}

impl fmt::Debug for UserInfo {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self.pass {
            Some(ref pass) => write!(f, "{}:{}@", self.user, *pass),
            None => write!(f, "{}@", self.user),
        }
    }
}

fn query_from_str(rawquery: &str) -> DecodeResult<Query> {
    let mut query: Query = vec!();
    if !rawquery.is_empty() {
        for p in rawquery.split('&') {
            let (k, v) = split_char_first(p, '=');
            query.push((try!(decode_component(k)),
                        try!(decode_component(v))));
        }
    }

    Ok(query)
}

pub fn get_scheme(rawurl: &str) -> DecodeResult<(&str, &str)> {
    for (i,c) in rawurl.chars().enumerate() {
        let result = match c {
            'A' ... 'Z'
            | 'a' ... 'z' => continue,
            '0' ... '9' | '+' | '-' | '.' => {
                if i != 0 { continue }

                Err("url: Scheme must begin with a letter.".to_string())
            }
            ':' => {
                if i == 0 {
                    Err("url: Scheme cannot be empty.".to_string())
                } else {
                    Ok((&rawurl[0..i], &rawurl[i+1..rawurl.len()]))
                }
            }
            _ => Err("url: Invalid character in scheme.".to_string()),
        };

        return result;
    }

    Err("url: Scheme must be terminated with a colon.".to_string())
}

// returns userinfo, host, port, and unparsed part, or an error
fn get_authority(rawurl: &str) ->
    DecodeResult<(Option<UserInfo>, &str, Option<u16>, &str)> {
    enum State {
        Start, // starting state
        PassHostPort, // could be in user or port
        Ip6Port, // either in ipv6 host or port
        Ip6Host, // are in an ipv6 host
        InHost, // are in a host - may be ipv6, but don't know yet
        InPort // are in port
    }

    #[derive(Clone, PartialEq)]
    enum Input {
        Digit, // all digits
        Hex, // digits and letters a-f
        Unreserved // all other legal characters
    }

    if !rawurl.starts_with("//") {
        // there is no authority.
        return Ok((None, "", None, rawurl));
    }

    let len = rawurl.len();
    let mut st = State::Start;
    let mut input = Input::Digit; // most restricted, start here.

    let mut userinfo = None;
    let mut host = "";
    let mut port = None;

    let mut colon_count = 0usize;
    let mut pos = 0;
    let mut begin = 2;
    let mut end = len;

    for (i,c) in rawurl.chars().enumerate()
                               // ignore the leading '//' handled by early return
                               .skip(2) {
        // deal with input class first
        match c {
            '0' ... '9' => (),
            'A' ... 'F'
            | 'a' ... 'f' => {
                if input == Input::Digit {
                    input = Input::Hex;
                }
            }
            'G' ... 'Z'
            | 'g' ... 'z'
            | '-' | '.' | '_' | '~' | '%'
            | '&' |'\'' | '(' | ')' | '+'
            | '!' | '*' | ',' | ';' | '=' => input = Input::Unreserved,
            ':' | '@' | '?' | '#' | '/' => {
                // separators, don't change anything
            }
            _ => return Err("Illegal character in authority".to_string()),
        }

        // now process states
        match c {
          ':' => {
            colon_count += 1;
            match st {
              State::Start => {
                pos = i;
                st = State::PassHostPort;
              }
              State::PassHostPort => {
                // multiple colons means ipv6 address.
                if input == Input::Unreserved {
                    return Err(
                        "Illegal characters in IPv6 address.".to_string());
                }
                st = State::Ip6Host;
              }
              State::InHost => {
                pos = i;
                if input == Input::Unreserved {
                    // must be port
                    host = &rawurl[begin..i];
                    st = State::InPort;
                } else {
                    // can't be sure whether this is an ipv6 address or a port
                    st = State::Ip6Port;
                }
              }
              State::Ip6Port => {
                if input == Input::Unreserved {
                    return Err("Illegal characters in authority.".to_string());
                }
                st = State::Ip6Host;
              }
              State::Ip6Host => {
                if colon_count > 7 {
                    host = &rawurl[begin..i];
                    pos = i;
                    st = State::InPort;
                }
              }
              _ => return Err("Invalid ':' in authority.".to_string()),
            }
            input = Input::Digit; // reset input class
          }

          '@' => {
            input = Input::Digit; // reset input class
            colon_count = 0; // reset count
            match st {
              State::Start => {
                let user = rawurl[begin..i].to_string();
                userinfo = Some(UserInfo::new(user, None));
                st = State::InHost;
              }
              State::PassHostPort => {
                let user = rawurl[begin..pos].to_string();
                let pass = rawurl[pos+1..i].to_string();
                userinfo = Some(UserInfo::new(user, Some(pass)));
                st = State::InHost;
              }
              _ => return Err("Invalid '@' in authority.".to_string()),
            }
            begin = i+1;
          }

          '?' | '#' | '/' => {
            end = i;
            break;
          }
          _ => ()
        }
    }

    // finish up
    match st {
      State::Start => host = &rawurl[begin..end],
      State::PassHostPort
      | State::Ip6Port => {
        if input != Input::Digit {
            return Err("Non-digit characters in port.".to_string());
        }
        host = &rawurl[begin..pos];
        port = Some(&rawurl[pos+1..end]);
      }
      State::Ip6Host
      | State::InHost => host = &rawurl[begin..end],
      State::InPort => {
        if input != Input::Digit {
            return Err("Non-digit characters in port.".to_string());
        }
        port = Some(&rawurl[pos+1..end]);
      }
    }

    let rest = &rawurl[end..len];
    // If we have a port string, ensure it parses to u16.
    let port = match port {
        None => None,
        opt => match opt.and_then(|p| FromStr::from_str(p).ok()) {
            None => return Err(format!("Failed to parse port: {:?}", port)),
            opt => opt
        }
    };

    Ok((userinfo, host, port, rest))
}

// returns the path and unparsed part of url, or an error
fn get_path(rawurl: &str, is_authority: bool) -> DecodeResult<(String, &str)> {
    let len = rawurl.len();
    let mut end = len;
    for (i,c) in rawurl.chars().enumerate() {
        match c {
          'A' ... 'Z'
          | 'a' ... 'z'
          | '0' ... '9'
          | '&' |'\'' | '(' | ')' | '.'
          | '@' | ':' | '%' | '/' | '+'
          | '!' | '*' | ',' | ';' | '='
          | '_' | '-' | '~' => continue,
          '?' | '#' => {
            end = i;
            break;
          }
          _ => return Err("Invalid character in path.".to_string())
        }
    }

    if is_authority && end != 0 && !rawurl.starts_with("/") {
        Err("Non-empty path must begin with \
            '/' in presence of authority.".to_string())
    } else {
        Ok((try!(decode_component(&rawurl[0..end])), &rawurl[end..len]))
    }
}

// returns the parsed query and the fragment, if present
fn get_query_fragment(rawurl: &str) -> DecodeResult<(Query, Option<String>)> {
    let (before_fragment, raw_fragment) = split_char_first(rawurl, '#');

    // Parse the fragment if available
    let fragment = match raw_fragment {
        "" => None,
        raw => Some(try!(decode_component(raw)))
    };

    match before_fragment.slice_shift_char() {
        Some(('?', rest)) => Ok((try!(query_from_str(rest)), fragment)),
        None => Ok((vec!(), fragment)),
        _ => Err(format!("Query didn't start with '?': '{}..'", before_fragment)),
    }
}

impl FromStr for Url {
    type Err = String;
    fn from_str(s: &str) -> Result<Url, String> {
        Url::parse(s)
    }
}

impl FromStr for Path {
    type Err = String;
    fn from_str(s: &str) -> Result<Path, String> {
        Path::parse(s)
    }
}

<|endoftext|>