<commit_before>#![feature(libc)]
#![feature(rustc_private)]

extern crate libc;
use libc::{c_int, c_ulong, c_void};

extern crate rustc_back;

use std::io::Error;
use std::result::Result;
use std::os::unix::io::AsRawFd;

#[link(name = "c")]
extern {
    fn ioctl(fd : c_int, request : c_ulong, ...) -> c_int;
}

const IOC_WRITE: i32 = 1;
const IOC_READ:  i32 = 2;

const IOC_NRBITS:   usize = 8;
const IOC_TYPEBITS: usize = 8;
const IOC_SIZEBITS: usize = 14;

const IOC_NRSHIFT:   usize = 0us;
const IOC_TYPESHIFT: usize = IOC_NRSHIFT   + IOC_NRBITS;
const IOC_SIZESHIFT: usize = IOC_TYPESHIFT + IOC_TYPEBITS;
const IOC_DIRSHIFT:  usize = IOC_SIZESHIFT + IOC_SIZEBITS;

#[inline]
pub fn ioc(dir: i32, ty: i32, nr: i32, size: i32) -> c_ulong {
    ((dir  << IOC_DIRSHIFT)  |
    (ty   << IOC_TYPESHIFT) |
    (nr   << IOC_NRSHIFT)   |
    (size << IOC_SIZESHIFT)) as c_ulong
}

fn get_hot_data(fd: c_int) -> Result<hot_data, Error> {
    let mut result = hot_data { live: 1,
                                resv: [0,0,0],
                                temp: 0,
                                avg_delta_reads: 0,
                                avg_delta_writes: 0,
                                last_read_time: 0,
                                last_write_time: 0,
                                num_reads: 0,
                                num_writes: 0,
                                future: [0,0,0,0]};
    unsafe {
        if ioctl(fd, ioc(IOC_READ, 'f' as i32, 17, std::mem::size_of::<hot_data>() as i32), &mut result) == 0
        {
            Ok(result)
        }
        else
        {
            Err(Error::last_os_error())
        }
    }
}

#[cfg(test)]
struct HotDataSupportingFixture {
    base_dir : std::path::PathBuf,
    fs_image_file : std::fs::File,
    fs_image_dir : std::path::PathBuf
}

#[cfg(test)]
impl Drop for HotDataSupportingFixture {
    fn drop(&mut self) {
        assert!(Command::new("sudo").arg("umount").arg(&self.base_dir.as_os_str()).status().is_ok());
        assert!(std::fs::remove_dir_all(&self.base_dir).is_ok());
        assert!(std::fs::remove_dir_all(&self.fs_image_dir).is_ok());
    }
}

#[cfg(test)]
use std::process::Command;

#[cfg(test)]
impl HotDataSupportingFixture {
    fn new_btrfs() -> HotDataSupportingFixture {
        let tmpdir = rustc_back::tempdir::TempDir::new("hot-data-test").unwrap();
        let image_path = tmpdir.path().join("btrfs-image");
        let mount_dir = tmpdir.path().join("btrfs-mount-point");

        let image_file = std::fs::File::create(&image_path).unwrap();
        assert!(image_file.set_len(1024*1024*100).is_ok());
        assert!(image_file.sync_all().is_ok());

        assert!(std::fs::create_dir(&mount_dir).is_ok());

        assert!(Command::new("mkfs.btrfs").arg(&image_path.as_os_str()).status().is_ok());
        assert!(Command::new("sudo").arg("mount").arg("-o").arg("hot_track").arg(&image_path.as_os_str()).arg(&mount_dir.as_os_str()).status().is_ok());
        assert!(Command::new("sudo").arg("chmod").arg("777").arg(&mount_dir.as_os_str()).status().is_ok());

        HotDataSupportingFixture { base_dir : mount_dir,
                                   fs_image_file : image_file,
                                   fs_image_dir : tmpdir.into_path() }
    }

    fn new_xfs() -> HotDataSupportingFixture {
        let tmpdir = rustc_back::tempdir::TempDir::new("hot-data-test").unwrap();
        let image_path = tmpdir.path().join("xfs-image");
        let mount_dir = tmpdir.path().join("xfs-mount-point");

        let image_file = std::fs::File::create(&image_path).unwrap();
        assert!(image_file.set_len(1024*1024*100).is_ok());
        assert!(image_file.sync_all().is_ok());

        assert!(std::fs::create_dir(&mount_dir).is_ok());

        assert!(Command::new("mkfs.xfs").arg(&image_path.as_os_str()).status().is_ok());
        assert!(Command::new("sudo").arg("mount").arg("-o").arg("hot_track").arg(&image_path.as_os_str()).arg(&mount_dir.as_os_str()).status().is_ok());
        assert!(Command::new("sudo").arg("chmod").arg("777").arg(&mount_dir.as_os_str()).status().is_ok());

        HotDataSupportingFixture { base_dir : mount_dir,
                                   fs_image_file : image_file,
                                   fs_image_dir : tmpdir.into_path() }
    }
}

#[test]
fn ioctl_binding_returns_error() {
    match get_hot_data(33) {
        Ok(_) => panic!("ioctl unexpectedly succeeded"),
        Err(e) => assert_eq!(e.raw_os_error().unwrap(), 9) // EBADF == 9
    }
}

#[test]
fn get_hot_data_returns_unsupported() {
    let test_file = std::fs::File::open("/home/chris/.zshrc").ok().unwrap();
    match get_hot_data(test_file.as_raw_fd()) {
        Ok(_) => panic!("Call unexpectedly succeeded"),
        Err(e) => assert_eq!(e.raw_os_error().unwrap(), 95) // ENOTSUP == 95
    }
}

#[test]
fn get_hot_data_returns_no_data() {
    let fixture = HotDataSupportingFixture::new_btrfs();

    let test_file = match std::fs::File::create(&fixture.base_dir.join("test")) {
        Ok(file) => file,
        Err(e) => panic!("Failed to create {:?}: {}", &fixture.base_dir.join("test"), e)
    };
    match get_hot_data(test_file.as_raw_fd()) {
        Ok(_) => panic!("Call unexpectedly succeeded"),
        Err(e) => assert_eq!(e.raw_os_error().unwrap(), 61) // ENODATA == 61
    }
}

#[test]
fn get_hot_data_returns_fault() {
    let fixture = HotDataSupportingFixture::new_btrfs();

    let test_file = match std::fs::File::create(&fixture.base_dir.join("test")) {
        Ok(file) => file,
        Err(e) => panic!("Failed to create {:?}: {}", &fixture.base_dir.join("test"), e)
    };

    unsafe {
        if ioctl(test_file.as_raw_fd(), ioc(IOC_READ, 'f' as i32, 17, std::mem::size_of::<hot_data>() as i32), 0) == 0
        {
            panic!("Call unexpectedly succeeded");
        }
        else
        {
            assert_eq!(Error::last_os_error().raw_os_error().unwrap(), 14) // EFAULT == 14
        }
    }
}

#[cfg(test)]
use std::io::Write;
#[cfg(test)]
use std::io::Read;

#[test]
fn get_hot_data_has_correct_read_write_count() {
    let fixture = HotDataSupportingFixture::new_xfs();
    let test_file_name = fixture.base_dir.join("test_file");

    {
        let mut test_file = match std::fs::File::create(&test_file_name) {
            Ok(file) => file,
            Err(e) => panic!("Failed to create {:?}: {}", &test_file_name, e)
        };
        match test_file.write_all(b"Hello, I'm a string") {
            Err(why) => panic!("Failed to write: {}", why),
            Ok(_) => {}
        }
        test_file.sync_all();
    }

    let mut hello = match std::fs::File::open(&test_file_name) {
        Ok(file) => file,
        Err(e) => panic!("Failed to open {:?}: {}", &test_file_name, e)
    };

    let mut data = String::new();
    match hello.read_to_string(&mut data) {
        Ok(_) => assert_eq!(data, "Hello, I'm a string"),
        Err(e) => panic!("Failed to read from {:?}: {}", &test_file_name, e)
    }

    let info = match get_hot_data(hello.as_raw_fd()) {
        Ok(x) => x,
        Err(why) => panic!("get_hot_data failed: {}", why)
    };

    assert_eq!(info.num_reads, 1);
    assert_eq!(info.num_writes, 1);
}

#[repr(C)]
struct hot_data {
    live : u8,
    resv : [u8; 3],
    temp : u32,
    avg_delta_reads : u64,
    avg_delta_writes : u64,
    last_read_time : u64,
    last_write_time : u64,
    num_reads : u32,
    num_writes : u32,
    future : [u64; 4]
}
<commit_msg>Parametrise fixture on mkfs command<commit_after>#![feature(libc)]
#![feature(rustc_private)]

extern crate libc;
use libc::{c_int, c_ulong, c_void};

extern crate rustc_back;

use std::io::Error;
use std::result::Result;
use std::os::unix::io::AsRawFd;

#[link(name = "c")]
extern {
    fn ioctl(fd : c_int, request : c_ulong, ...) -> c_int;
}

const IOC_WRITE: i32 = 1;
const IOC_READ:  i32 = 2;

const IOC_NRBITS:   usize = 8;
const IOC_TYPEBITS: usize = 8;
const IOC_SIZEBITS: usize = 14;

const IOC_NRSHIFT:   usize = 0us;
const IOC_TYPESHIFT: usize = IOC_NRSHIFT   + IOC_NRBITS;
const IOC_SIZESHIFT: usize = IOC_TYPESHIFT + IOC_TYPEBITS;
const IOC_DIRSHIFT:  usize = IOC_SIZESHIFT + IOC_SIZEBITS;

#[inline]
pub fn ioc(dir: i32, ty: i32, nr: i32, size: i32) -> c_ulong {
    ((dir  << IOC_DIRSHIFT)  |
    (ty   << IOC_TYPESHIFT) |
    (nr   << IOC_NRSHIFT)   |
    (size << IOC_SIZESHIFT)) as c_ulong
}

fn get_hot_data(fd: c_int) -> Result<hot_data, Error> {
    let mut result = hot_data { live: 1,
                                resv: [0,0,0],
                                temp: 0,
                                avg_delta_reads: 0,
                                avg_delta_writes: 0,
                                last_read_time: 0,
                                last_write_time: 0,
                                num_reads: 0,
                                num_writes: 0,
                                future: [0,0,0,0]};
    unsafe {
        if ioctl(fd, ioc(IOC_READ, 'f' as i32, 17, std::mem::size_of::<hot_data>() as i32), &mut result) == 0
        {
            Ok(result)
        }
        else
        {
            Err(Error::last_os_error())
        }
    }
}

#[cfg(test)]
struct HotDataFixture {
    base_dir : std::path::PathBuf,
    fs_image_file : std::fs::File,
    fs_image_dir : std::path::PathBuf
}

#[cfg(test)]
impl Drop for HotDataFixture {
    fn drop(&mut self) {
        assert!(Command::new("sudo").arg("umount").arg(&self.base_dir.as_os_str()).status().is_ok());
        assert!(std::fs::remove_dir_all(&self.base_dir).is_ok());
        assert!(std::fs::remove_dir_all(&self.fs_image_dir).is_ok());
    }
}

#[cfg(test)]
use std::process::Command;

#[cfg(test)]
impl HotDataFixture {
    fn new(mkfs_command : &str) -> HotDataFixture {
        let tmpdir = rustc_back::tempdir::TempDir::new("hot-data-test").unwrap();
        let image_path = tmpdir.path().join("btrfs-image");
        let mount_dir = tmpdir.path().join("btrfs-mount-point");

        let image_file = std::fs::File::create(&image_path).unwrap();
        assert!(image_file.set_len(1024*1024*100).is_ok());
        assert!(image_file.sync_all().is_ok());

        assert!(std::fs::create_dir(&mount_dir).is_ok());

        assert!(Command::new(mkfs_command).arg(&image_path.as_os_str()).status().is_ok());
        assert!(Command::new("sudo").arg("mount").arg("-o").arg("hot_track").arg(&image_path.as_os_str()).arg(&mount_dir.as_os_str()).status().is_ok());
        assert!(Command::new("sudo").arg("chmod").arg("777").arg(&mount_dir.as_os_str()).status().is_ok());

        HotDataFixture { base_dir : mount_dir,
                         fs_image_file : image_file,
                         fs_image_dir : tmpdir.into_path() }
    }
}

#[test]
fn ioctl_binding_returns_error() {
    match get_hot_data(33) {
        Ok(_) => panic!("ioctl unexpectedly succeeded"),
        Err(e) => assert_eq!(e.raw_os_error().unwrap(), 9) // EBADF == 9
    }
}

#[test]
fn get_hot_data_returns_unsupported() {
    let test_file = std::fs::File::open("/home/chris/.zshrc").ok().unwrap();
    match get_hot_data(test_file.as_raw_fd()) {
        Ok(_) => panic!("Call unexpectedly succeeded"),
        Err(e) => assert_eq!(e.raw_os_error().unwrap(), 95) // ENOTSUP == 95
    }
}

#[test]
fn get_hot_data_returns_no_data() {
    let fixture = HotDataFixture::new("mkfs.btrfs");

    let test_file = match std::fs::File::create(&fixture.base_dir.join("test")) {
        Ok(file) => file,
        Err(e) => panic!("Failed to create {:?}: {}", &fixture.base_dir.join("test"), e)
    };
    match get_hot_data(test_file.as_raw_fd()) {
        Ok(_) => panic!("Call unexpectedly succeeded"),
        Err(e) => assert_eq!(e.raw_os_error().unwrap(), 61) // ENODATA == 61
    }
}

#[test]
fn get_hot_data_returns_fault() {
    let fixture = HotDataFixture::new("mkfs.btrfs");

    let test_file = match std::fs::File::create(&fixture.base_dir.join("test")) {
        Ok(file) => file,
        Err(e) => panic!("Failed to create {:?}: {}", &fixture.base_dir.join("test"), e)
    };

    unsafe {
        if ioctl(test_file.as_raw_fd(), ioc(IOC_READ, 'f' as i32, 17, std::mem::size_of::<hot_data>() as i32), 0) == 0
        {
            panic!("Call unexpectedly succeeded");
        }
        else
        {
            assert_eq!(Error::last_os_error().raw_os_error().unwrap(), 14) // EFAULT == 14
        }
    }
}

#[cfg(test)]
use std::io::Write;
#[cfg(test)]
use std::io::Read;

#[test]
fn get_hot_data_has_correct_read_write_count() {
    let fixture = HotDataFixture::new("mkfs.xfs");
    let test_file_name = fixture.base_dir.join("test_file");

    {
        let mut test_file = match std::fs::File::create(&test_file_name) {
            Ok(file) => file,
            Err(e) => panic!("Failed to create {:?}: {}", &test_file_name, e)
        };
        match test_file.write_all(b"Hello, I'm a string") {
            Err(why) => panic!("Failed to write: {}", why),
            Ok(_) => {}
        }
        test_file.sync_all();
    }

    let mut hello = match std::fs::File::open(&test_file_name) {
        Ok(file) => file,
        Err(e) => panic!("Failed to open {:?}: {}", &test_file_name, e)
    };

    let mut data = String::new();
    match hello.read_to_string(&mut data) {
        Ok(_) => assert_eq!(data, "Hello, I'm a string"),
        Err(e) => panic!("Failed to read from {:?}: {}", &test_file_name, e)
    }

    let info = match get_hot_data(hello.as_raw_fd()) {
        Ok(x) => x,
        Err(why) => panic!("get_hot_data failed: {}", why)
    };

    assert_eq!(info.num_reads, 1);
    assert_eq!(info.num_writes, 1);
}

#[repr(C)]
struct hot_data {
    live : u8,
    resv : [u8; 3],
    temp : u32,
    avg_delta_reads : u64,
    avg_delta_writes : u64,
    last_read_time : u64,
    last_write_time : u64,
    num_reads : u32,
    num_writes : u32,
    future : [u64; 4]
}
<|endoftext|>


<commit_before>#![no_std]
#![feature(phase)]

//! Convert between characters and their standard names.
//!
//! This crate provides two functions for mapping from a `char` to the
//! name given by the Unicode standard (7.0). There are no runtime
//! requirements and this is usable with only `core`, but the
//! associated tables are large (8MB).
//!
//! ```rust
//! extern crate unicode_names;
//!
//! fn main() {
//!     println!("☃ is called {}", unicode_names::name('☃')); // SNOWMAN
//!     println!("{} is happy", unicode_names::character("white smiling face")); // ☺
//!     // (NB. case insensitivity)
//! }
//! ```
//!
//! [**Source**](https://github.com/huonw/unicode_names).
//!
//! # Macros
//!
//! The associated `unicode_names_macros` crate provides two macros
//! for converting at compile-time, giving named literals similar to
//! Python's `"\N{...}"`.
//!
//! - `named_char!(name)` takes a single string `name` and creates a
//!   `char` literal.
//! - `named!(string)` takes a string and replaces any `\\N{name}`
//!   sequences with the character with that name. NB. String escape
//!   sequences cannot be customised, so the extra backslash (or a raw
//!   string) is required.
//!
//! ```rust,ignore
//! #![feature(phase)]
//!
//! #[phase(plugin)] extern crate unicode_names_macros;
//!
//! fn main() {
//!     let x: char = named_char!("snowman");
//!     assert_eq!(x, '☃');
//!
//!     let y: &str = named!("foo bar \\N{BLACK STAR} baz qux");
//!     assert_eq!(y, "foo bar ★ baz qux");
//! }
//! ```
//!
//! # Cargo-enabled
//!
//! Add either (or both!) of the following to your `Cargo.toml`.
//!
//! ```toml
//! [dependencies.unicode_names]
//! git = "https://github.com/huonw/unicode_names"
//!
//! [dependencies.unicode_names_macros]
//! git = "https://github.com/huonw/unicode_names_macros"
//! ```

#[phase(link, plugin)] extern crate core;

#[cfg(test)] #[phase(link, plugin)] extern crate std;
#[cfg(test)] extern crate native;
#[cfg(test)] extern crate test;

use core::cmp::{Equal, Less, Greater};
use core::collections::Collection;
use core::option::Option;
use core::iter::{order, Iterator, DoubleEndedIterator};
use core::slice::{ImmutableSlice, MutableSlice};
use core::str::StrSlice;

#[allow(dead_code)]
mod generated;

/// Find the name of `c`, or `None` if `c` has no name.
///
/// # Example
///
/// ```rust
/// assert_eq!(unicode_names::name('a'), Some("LATIN SMALL LETTER A"));
/// assert_eq!(unicode_names::name('\u2605'), Some("BLACK STAR"));
/// assert_eq!(unicode_names::name('☃'), Some("SNOWMAN"));
///
/// // control code
/// assert_eq!(unicode_names::name('\x00'), None);
/// // unassigned
/// assert_eq!(unicode_names::name('\U0010FFFF'), None);
/// ```
pub fn name(c: char) -> Option<&'static str> {
    generated::CHARACTER_TO_NAME.binary_search(|&(lo,hi, _)| {
        if c < lo {
            Greater
        } else if hi < c {
            Less
        } else {
            Equal
        }
    }).found().map(|idx| {
        let (lo, _, names) = generated::CHARACTER_TO_NAME[idx];
        names[c as uint - lo as uint]
    })
}

/// Find the character called `name`, or `None` if no such character
/// exists.
///
/// This searches case-insensitively.
///
/// # Example
///
/// ```rust
/// assert_eq!(unicode_names::character("LATIN SMALL LETTER A"), Some('a'));
/// assert_eq!(unicode_names::character("latin SMALL letter A"), Some('a'));
/// assert_eq!(unicode_names::character("latin small letter a"), Some('a'));
/// assert_eq!(unicode_names::character("BLACK STAR"), Some('★'));
/// assert_eq!(unicode_names::character("SNOWMAN"), Some('☃'));
///
/// assert_eq!(unicode_names::character("nonsense"), None);
/// ```
pub fn character(name: &str) -> Option<char> {
    let mut buf = [0u8, .. generated::MAX_NAME_LENGTH + 1];
    for (place, byte) in buf.mut_iter().zip(name.bytes()) {
        *place = ASCII_UPPER_MAP[byte as uint]
    }
    let search_name = buf.slice_to(name.len());

    generated::NAME_TO_CHARACTER.binary_search(|&(this_name, _)| {
        // reverse order because this is more unique, and thus more
        // efficient (less time spend iterating over common LATIN
        // CAPITAL LETTER ... etc. prefixes)
        order::cmp(this_name.bytes().rev(),
                   search_name.iter().map(|&b| b).rev())
    }).found().map(|idx| {
        let (_, c) = generated::NAME_TO_CHARACTER[idx];
        c
    })
}

// FIXME: use the stdlib one if/when std::ascii moves into `core` (or
// some such).
static ASCII_UPPER_MAP: [u8, ..256] = [
    0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
    0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
    0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
    0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
    b' ', b'!', b'"', b'#', b'$', b'%', b'&', b'\'', // " // syntax highlighting :/
    b'(', b')', b'*', b'+', b',', b'-', b'.', b'/',
    b'0', b'1', b'2', b'3', b'4', b'5', b'6', b'7',
    b'8', b'9', b':', b';', b'<', b'=', b'>', b'?',
    b'@', b'A', b'B', b'C', b'D', b'E', b'F', b'G',
    b'H', b'I', b'J', b'K', b'L', b'M', b'N', b'O',
    b'P', b'Q', b'R', b'S', b'T', b'U', b'V', b'W',
    b'X', b'Y', b'Z', b'[', b'\\', b']', b'^', b'_',
    b'`',

          b'A', b'B', b'C', b'D', b'E', b'F', b'G',
    b'H', b'I', b'J', b'K', b'L', b'M', b'N', b'O',
    b'P', b'Q', b'R', b'S', b'T', b'U', b'V', b'W',
    b'X', b'Y', b'Z',

                      b'{', b'|', b'}', b'~', 0x7f,
    0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
    0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
    0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
    0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f,
    0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,
    0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf,
    0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7,
    0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf,
    0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7,
    0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf,
    0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7,
    0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf,
    0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7,
    0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef,
    0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7,
    0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff,
];

#[cfg(test)]
mod tests {
    use core::collections::Collection;
    use core::slice::ImmutableSlice;
    use core::option::{None, Some};
    use core::iter::{Iterator, range};
    use core::char;

    use std::ascii::AsciiExt;
    use std::rand::{Rng, XorShiftRng, SeedableRng};
    use std::str::Str;
    use std::vec::Vec;

    use test::{mod, Bencher};

    use super::{generated, name, character};

    #[test]
    fn exhaustive_positive() {
        for &(n, c) in generated::NAME_TO_CHARACTER.iter() {
            assert_eq!(name(c), Some(n));
            assert_eq!(character(n), Some(c));
            assert_eq!(character(n.to_ascii_lower().as_slice()), Some(c))
        }
    }

    #[test]
    fn exhaustive_name_negative() {
        // check that gaps in the CHARACTER_TO_NAME table have no
        // names (these are unassigned/control codes).
        fn test_range(from: u32, to: u32) {
            for x in range(from, to) {
                match char::from_u32(x) {
                    None => {}
                    Some(c) => {
                        assert_eq!(name(c), None);
                    }
                }
            }
        }

        let mut last = 0;
        for &(lo, hi, _) in generated::CHARACTER_TO_NAME.iter() {
            test_range(last, lo as u32);
            last = hi as u32 + 1;
        }
        test_range(last, 0x10FFFF + 1)
    }

    #[test]
    fn character_negative() {
        let names = [
            "",
            "x",
            "öäå",
            "SPAACE"
            ];
        for &n in names.iter() {
            assert_eq!(character(n), None);
        }
    }

    #[bench]
    fn name_one_hundreth(b: &mut Bencher) {
        let mut chars: Vec<char> = range(0u32, 0x10FFFF + 1).filter_map(char::from_u32).collect();

        // be consistent across runs, but avoid sequential/caching.
        let mut rng: XorShiftRng = SeedableRng::from_seed([0xFF00FF00, 0xF0F0F0F0,
                                                           0x00FF00FF, 0x0F0F0F0F]);
        rng.shuffle(chars.as_mut_slice());
        let new_len = chars.len() / 100;
        chars.truncate(new_len);

        b.iter(|| {
            for c in chars.iter() {
                test::black_box(name(*c));
            }
        })
    }

    #[bench]
    fn character_one_hundreth(b: &mut Bencher) {
        let mut names: Vec<&str> = generated::NAME_TO_CHARACTER.iter().map(|&(n,_)| n).collect();
        // be consistent across runs, but avoid sequential/caching.
        let mut rng: XorShiftRng = SeedableRng::from_seed([0xFF00FF00, 0xF0F0F0F0,
                                                           0x00FF00FF, 0x0F0F0F0F]);
        rng.shuffle(names.as_mut_slice());

        let new_len = names.len() / 100;
        names.truncate(new_len);
        b.iter(|| {
            for n in names.iter() {
                test::black_box(character(*n))
            }
        })
    }
}
<commit_msg>Docs should say the right thing/point at the right repo.<commit_after>#![no_std]
#![feature(phase)]

//! Convert between characters and their standard names.
//!
//! This crate provides two functions for mapping from a `char` to the
//! name given by the Unicode standard (7.0). There are no runtime
//! requirements and this is usable with only `core`, but the
//! associated tables are large (8MB).
//!
//! ```rust
//! extern crate unicode_names;
//!
//! fn main() {
//!     println!("☃ is called {}", unicode_names::name('☃')); // SNOWMAN
//!     println!("{} is happy", unicode_names::character("white smiling face")); // ☺
//!     // (NB. case insensitivity)
//! }
//! ```
//!
//! [**Source**](https://github.com/huonw/unicode_names).
//!
//! # Macros
//!
//! The associated `unicode_names_macros` crate provides two macros
//! for converting at compile-time, giving named literals similar to
//! Python's `"\N{...}"`.
//!
//! - `named_char!(name)` takes a single string `name` and creates a
//!   `char` literal.
//! - `named!(string)` takes a string and replaces any `\\N{name}`
//!   sequences with the character with that name. NB. String escape
//!   sequences cannot be customised, so the extra backslash (or a raw
//!   string) is required.
//!
//! ```rust,ignore
//! #![feature(phase)]
//!
//! #[phase(plugin)] extern crate unicode_names_macros;
//!
//! fn main() {
//!     let x: char = named_char!("snowman");
//!     assert_eq!(x, '☃');
//!
//!     let y: &str = named!("foo bar \\N{BLACK STAR} baz qux");
//!     assert_eq!(y, "foo bar ★ baz qux");
//! }
//! ```
//!
//! # Cargo-enabled
//!
//! Add either (or both!) of the following to your `Cargo.toml`.
//!
//! ```toml
//! [dependencies.unicode_names]
//! git = "https://github.com/huonw/unicode_names"
//!
//! [dependencies.unicode_names_macros]
//! git = "https://github.com/huonw/unicode_names"
//! ```

#[phase(link, plugin)] extern crate core;

#[cfg(test)] #[phase(link, plugin)] extern crate std;
#[cfg(test)] extern crate native;
#[cfg(test)] extern crate test;

use core::cmp::{Equal, Less, Greater};
use core::collections::Collection;
use core::option::Option;
use core::iter::{order, Iterator, DoubleEndedIterator};
use core::slice::{ImmutableSlice, MutableSlice};
use core::str::StrSlice;

#[allow(dead_code)]
mod generated;

/// Find the name of `c`, or `None` if `c` has no name.
///
/// # Example
///
/// ```rust
/// assert_eq!(unicode_names::name('a'), Some("LATIN SMALL LETTER A"));
/// assert_eq!(unicode_names::name('\u2605'), Some("BLACK STAR"));
/// assert_eq!(unicode_names::name('☃'), Some("SNOWMAN"));
///
/// // control code
/// assert_eq!(unicode_names::name('\x00'), None);
/// // unassigned
/// assert_eq!(unicode_names::name('\U0010FFFF'), None);
/// ```
pub fn name(c: char) -> Option<&'static str> {
    generated::CHARACTER_TO_NAME.binary_search(|&(lo,hi, _)| {
        if c < lo {
            Greater
        } else if hi < c {
            Less
        } else {
            Equal
        }
    }).found().map(|idx| {
        let (lo, _, names) = generated::CHARACTER_TO_NAME[idx];
        names[c as uint - lo as uint]
    })
}

/// Find the character called `name`, or `None` if no such character
/// exists.
///
/// This searches case-insensitively.
///
/// # Example
///
/// ```rust
/// assert_eq!(unicode_names::character("LATIN SMALL LETTER A"), Some('a'));
/// assert_eq!(unicode_names::character("latin SMALL letter A"), Some('a'));
/// assert_eq!(unicode_names::character("latin small letter a"), Some('a'));
/// assert_eq!(unicode_names::character("BLACK STAR"), Some('★'));
/// assert_eq!(unicode_names::character("SNOWMAN"), Some('☃'));
///
/// assert_eq!(unicode_names::character("nonsense"), None);
/// ```
pub fn character(name: &str) -> Option<char> {
    let mut buf = [0u8, .. generated::MAX_NAME_LENGTH + 1];
    for (place, byte) in buf.mut_iter().zip(name.bytes()) {
        *place = ASCII_UPPER_MAP[byte as uint]
    }
    let search_name = buf.slice_to(name.len());

    generated::NAME_TO_CHARACTER.binary_search(|&(this_name, _)| {
        // reverse order because this is more unique, and thus more
        // efficient (less time spend iterating over common LATIN
        // CAPITAL LETTER ... etc. prefixes)
        order::cmp(this_name.bytes().rev(),
                   search_name.iter().map(|&b| b).rev())
    }).found().map(|idx| {
        let (_, c) = generated::NAME_TO_CHARACTER[idx];
        c
    })
}

// FIXME: use the stdlib one if/when std::ascii moves into `core` (or
// some such).
static ASCII_UPPER_MAP: [u8, ..256] = [
    0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
    0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
    0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
    0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
    b' ', b'!', b'"', b'#', b'$', b'%', b'&', b'\'', // " // syntax highlighting :/
    b'(', b')', b'*', b'+', b',', b'-', b'.', b'/',
    b'0', b'1', b'2', b'3', b'4', b'5', b'6', b'7',
    b'8', b'9', b':', b';', b'<', b'=', b'>', b'?',
    b'@', b'A', b'B', b'C', b'D', b'E', b'F', b'G',
    b'H', b'I', b'J', b'K', b'L', b'M', b'N', b'O',
    b'P', b'Q', b'R', b'S', b'T', b'U', b'V', b'W',
    b'X', b'Y', b'Z', b'[', b'\\', b']', b'^', b'_',
    b'`',

          b'A', b'B', b'C', b'D', b'E', b'F', b'G',
    b'H', b'I', b'J', b'K', b'L', b'M', b'N', b'O',
    b'P', b'Q', b'R', b'S', b'T', b'U', b'V', b'W',
    b'X', b'Y', b'Z',

                      b'{', b'|', b'}', b'~', 0x7f,
    0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
    0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
    0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
    0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f,
    0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,
    0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf,
    0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7,
    0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf,
    0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7,
    0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf,
    0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7,
    0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf,
    0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7,
    0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef,
    0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7,
    0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff,
];

#[cfg(test)]
mod tests {
    use core::collections::Collection;
    use core::slice::ImmutableSlice;
    use core::option::{None, Some};
    use core::iter::{Iterator, range};
    use core::char;

    use std::ascii::AsciiExt;
    use std::rand::{Rng, XorShiftRng, SeedableRng};
    use std::str::Str;
    use std::vec::Vec;

    use test::{mod, Bencher};

    use super::{generated, name, character};

    #[test]
    fn exhaustive_positive() {
        for &(n, c) in generated::NAME_TO_CHARACTER.iter() {
            assert_eq!(name(c), Some(n));
            assert_eq!(character(n), Some(c));
            assert_eq!(character(n.to_ascii_lower().as_slice()), Some(c))
        }
    }

    #[test]
    fn exhaustive_name_negative() {
        // check that gaps in the CHARACTER_TO_NAME table have no
        // names (these are unassigned/control codes).
        fn test_range(from: u32, to: u32) {
            for x in range(from, to) {
                match char::from_u32(x) {
                    None => {}
                    Some(c) => {
                        assert_eq!(name(c), None);
                    }
                }
            }
        }

        let mut last = 0;
        for &(lo, hi, _) in generated::CHARACTER_TO_NAME.iter() {
            test_range(last, lo as u32);
            last = hi as u32 + 1;
        }
        test_range(last, 0x10FFFF + 1)
    }

    #[test]
    fn character_negative() {
        let names = [
            "",
            "x",
            "öäå",
            "SPAACE"
            ];
        for &n in names.iter() {
            assert_eq!(character(n), None);
        }
    }

    #[bench]
    fn name_one_hundreth(b: &mut Bencher) {
        let mut chars: Vec<char> = range(0u32, 0x10FFFF + 1).filter_map(char::from_u32).collect();

        // be consistent across runs, but avoid sequential/caching.
        let mut rng: XorShiftRng = SeedableRng::from_seed([0xFF00FF00, 0xF0F0F0F0,
                                                           0x00FF00FF, 0x0F0F0F0F]);
        rng.shuffle(chars.as_mut_slice());
        let new_len = chars.len() / 100;
        chars.truncate(new_len);

        b.iter(|| {
            for c in chars.iter() {
                test::black_box(name(*c));
            }
        })
    }

    #[bench]
    fn character_one_hundreth(b: &mut Bencher) {
        let mut names: Vec<&str> = generated::NAME_TO_CHARACTER.iter().map(|&(n,_)| n).collect();
        // be consistent across runs, but avoid sequential/caching.
        let mut rng: XorShiftRng = SeedableRng::from_seed([0xFF00FF00, 0xF0F0F0F0,
                                                           0x00FF00FF, 0x0F0F0F0F]);
        rng.shuffle(names.as_mut_slice());

        let new_len = names.len() / 100;
        names.truncate(new_len);
        b.iter(|| {
            for n in names.iter() {
                test::black_box(character(*n))
            }
        })
    }
}
<|endoftext|>


<commit_before>//! # Feature flags
//!
//! This crate exposes a number of features. These can be enabled or disabled as shown
//! [in Cargo's documentation](https://doc.rust-lang.org/cargo/reference/features.html). Features
//! are _disabled_ by default unless otherwise noted.
//!
//! Reliance on a given feature is always indicated alongside the item definition.
//!
//! - `std` (_enabled by default, implicitly enables `alloc`_)
//!
//!   This enables a number of features that depend on the standard library.
//!
//! - `alloc` (_enabled by default via `std`_)
//!
//!   Enables a number of features that require the ability to dynamically allocate memory.
//!
//! - `macros`
//!
//!   Enables macros that provide compile-time verification of values and intuitive syntax.
//!
//! - `formatting` (_implicitly enables `std`_)
//!
//!   Enables formatting of most structs.
//!
//! - `parsing`
//!
//!   Enables parsing of most structs.
//!
//! - `local-offset` (_implicitly enables `std`_)
//!
//!   This feature enables a number of methods that allow obtaining the system's UTC offset.
//!
//! - `large-dates`
//!
//!   By default, only years within the ±9999 range (inclusive) are supported. If you need support
//!   for years outside this range, consider enabling this feature; the supported range will be
//!   increased to ±999,999.
//!
//!   Note that enabling this feature has some costs, as it means forgoing some optimizations.
//!   Ambiguities may be introduced when parsing that would not otherwise exist.
//!
//! - `serde`
//!
//!   Enables [serde](https://docs.rs/serde) support for all types except [`Instant`].
//!
//! - `serde-human-readable` (_implicitly enables `serde`, `formatting`, and `parsing`_)
//!
//!   Allows serde representations to use a human-readable format. This is determined by the
//!   serializer, not the user. If this feature is not enabled or if the serializer requests a
//!   non-human-readable format, a format optimized for binary representation will be used.
//!
//!   Libraries should never enable this feature, as the decision of what format to use should be up
//!   to the user.
//!
//! - `serde-well-known` (_implicitly enables `serde/alloc`, `formatting`, and `parsing`_)
//!
//!   Enables support for serializing and deserializing well-known formats using serde's
//!   [`#[with]` attribute](https://serde.rs/field-attrs.html#with).
//!
//! - `rand`
//!
//!   Enables [rand](https://docs.rs/rand) support for all types.
//!
//! - `quickcheck` (_implicitly enables `alloc`_)
//!
//!   Enables [quickcheck](https://docs.rs/quickcheck) support for all types except [`Instant`].
//!
//! - `wasm-bindgen`
//!
//!   Enables [wasm-bindgen](https://github.com/rustwasm/wasm-bindgen) support for converting
//!   [JavaScript dates](https://rustwasm.github.io/wasm-bindgen/api/js_sys/struct.Date.html), as
//!   well as obtaining the UTC offset from JavaScript.
//!
//! One pseudo-feature flag that is only available to end users is the `unsound_local_offset` cfg.
//! As the name indicates, using the feature is unsound, and [may cause unexpected segmentation
//! faults](https://github.com/time-rs/time/issues/293). Unlike other flags, this is deliberately
//! only available to end users; this is to ensure that a user doesn't have unsound behavior without
//! knowing it. To enable this behavior, you must use `RUSTFLAGS="--cfg unsound_local_offset" cargo
//! build` or similar. Note: This flag is _not tested anywhere_, including in the regular test of
//! the powerset of all feature flags. Use at your own risk. Without this flag, any method that
//! requires the local offset will return the `Err` variant when otherwise unsound.

#![doc(html_playground_url = "https://play.rust-lang.org")]
#![cfg_attr(__time_03_docs, feature(doc_auto_cfg, doc_notable_trait))]
#![cfg_attr(
    __time_03_docs,
    deny(rustdoc::broken_intra_doc_links, rustdoc::private_intra_doc_links)
)]
#![cfg_attr(not(feature = "std"), no_std)]
#![deny(
    anonymous_parameters,
    clippy::all,
    clippy::alloc_instead_of_core,
    clippy::explicit_auto_deref,
    clippy::obfuscated_if_else,
    clippy::std_instead_of_core,
    clippy::undocumented_unsafe_blocks,
    const_err,
    illegal_floating_point_literal_pattern,
    late_bound_lifetime_arguments,
    path_statements,
    patterns_in_fns_without_body,
    rust_2018_idioms,
    trivial_casts,
    trivial_numeric_casts,
    unreachable_pub,
    unsafe_op_in_unsafe_fn,
    unused_extern_crates
)]
#![warn(
    clippy::dbg_macro,
    clippy::decimal_literal_representation,
    clippy::get_unwrap,
    clippy::missing_docs_in_private_items,
    clippy::nursery,
    clippy::print_stdout,
    clippy::todo,
    clippy::unimplemented,
    clippy::unnested_or_patterns,
    clippy::unwrap_in_result,
    clippy::unwrap_used,
    clippy::use_debug,
    deprecated_in_future,
    missing_copy_implementations,
    missing_debug_implementations,
    unused_qualifications,
    variant_size_differences
)]
#![allow(clippy::redundant_pub_crate)]
#![doc(html_favicon_url = "https://avatars0.githubusercontent.com/u/55999857")]
#![doc(html_logo_url = "https://avatars0.githubusercontent.com/u/55999857")]
#![doc(test(attr(deny(warnings))))]

#[allow(unused_extern_crates)]
#[cfg(feature = "alloc")]
extern crate alloc;

// region: macros
/// Helper macro for easily implementing `OpAssign`.
macro_rules! __impl_assign {
    ($sym:tt $op:ident $fn:ident $target:ty : $($(#[$attr:meta])* $t:ty),+) => {$(
        #[allow(unused_qualifications)]
        $(#[$attr])*
        impl core::ops::$op<$t> for $target {
            fn $fn(&mut self, rhs: $t) {
                *self = *self $sym rhs;
            }
        }
    )+};
}

/// Implement `AddAssign` for the provided types.
macro_rules! impl_add_assign {
    ($target:ty : $($(#[$attr:meta])* $t:ty),+ $(,)?) => {
        __impl_assign!(+ AddAssign add_assign $target : $($(#[$attr])* $t),+);
    };
}

/// Implement `SubAssign` for the provided types.
macro_rules! impl_sub_assign {
    ($target:ty : $($(#[$attr:meta])* $t:ty),+ $(,)?) => {
        __impl_assign!(- SubAssign sub_assign $target : $($(#[$attr])* $t),+);
    };
}

/// Implement `MulAssign` for the provided types.
macro_rules! impl_mul_assign {
    ($target:ty : $($(#[$attr:meta])* $t:ty),+ $(,)?) => {
        __impl_assign!(* MulAssign mul_assign $target : $($(#[$attr])* $t),+);
    };
}

/// Implement `DivAssign` for the provided types.
macro_rules! impl_div_assign {
    ($target:ty : $($(#[$attr:meta])* $t:ty),+ $(,)?) => {
        __impl_assign!(/ DivAssign div_assign $target : $($(#[$attr])* $t),+);
    };
}

/// Division of integers, rounding the resulting value towards negative infinity.
macro_rules! div_floor {
    ($a:expr, $b:expr) => {{
        let _a = $a;
        let _b = $b;

        let (_quotient, _remainder) = (_a / _b, _a % _b);

        if (_remainder > 0 && _b < 0) || (_remainder < 0 && _b > 0) {
            _quotient - 1
        } else {
            _quotient
        }
    }};
}

/// Cascade an out-of-bounds value.
macro_rules! cascade {
    (@ordinal ordinal) => {};
    (@year year) => {};

    // Cascade an out-of-bounds value from "from" to "to".
    ($from:ident in $min:literal.. $max:literal => $to:tt) => {
        #[allow(unused_comparisons, unused_assignments)]
        if $from >= $max {
            $from -= $max - $min;
            $to += 1;
        } else if $from < $min {
            $from += $max - $min;
            $to -= 1;
        }
    };

    // Special case the ordinal-to-year cascade, as it has different behavior.
    ($ordinal:ident => $year:ident) => {
        // We need to actually capture the idents. Without this, macro hygiene causes errors.
        cascade!(@ordinal $ordinal);
        cascade!(@year $year);
        #[allow(unused_assignments)]
        if $ordinal > crate::util::days_in_year($year) as i16 {
            $ordinal -= crate::util::days_in_year($year) as i16;
            $year += 1;
        } else if $ordinal < 1 {
            $year -= 1;
            $ordinal += crate::util::days_in_year($year) as i16;
        }
    };
}

/// Returns `Err(error::ComponentRange)` if the value is not in range.
macro_rules! ensure_value_in_range {
    ($value:ident in $start:expr => $end:expr) => {{
        let _start = $start;
        let _end = $end;
        #[allow(trivial_numeric_casts, unused_comparisons)]
        if $value < _start || $value > _end {
            return Err(crate::error::ComponentRange {
                name: stringify!($value),
                minimum: _start as _,
                maximum: _end as _,
                value: $value as _,
                conditional_range: false,
            });
        }
    }};

    ($value:ident conditionally in $start:expr => $end:expr) => {{
        let _start = $start;
        let _end = $end;
        #[allow(trivial_numeric_casts, unused_comparisons)]
        if $value < _start || $value > _end {
            return Err(crate::error::ComponentRange {
                name: stringify!($value),
                minimum: _start as _,
                maximum: _end as _,
                value: $value as _,
                conditional_range: true,
            });
        }
    }};
}

/// Try to unwrap an expression, returning if not possible.
///
/// This is similar to the `?` operator, but does not perform `.into()`. Because of this, it is
/// usable in `const` contexts.
macro_rules! const_try {
    ($e:expr) => {
        match $e {
            Ok(value) => value,
            Err(error) => return Err(error),
        }
    };
}

/// Try to unwrap an expression, returning if not possible.
///
/// This is similar to the `?` operator, but is usable in `const` contexts.
macro_rules! const_try_opt {
    ($e:expr) => {
        match $e {
            Some(value) => value,
            None => return None,
        }
    };
}

/// Try to unwrap an expression, panicking if not possible.
///
/// This is similar to `$e.expect($message)`, but is usable in `const` contexts.
macro_rules! expect_opt {
    ($e:expr, $message:literal) => {
        match $e {
            Some(value) => value,
            None => crate::expect_failed($message),
        }
    };
}
// endregion macros

mod date;
mod duration;
pub mod error;
pub mod ext;
#[cfg(any(feature = "formatting", feature = "parsing"))]
pub mod format_description;
#[cfg(feature = "formatting")]
pub mod formatting;
#[cfg(feature = "std")]
mod instant;
#[cfg(feature = "macros")]
pub mod macros;
mod month;
mod offset_date_time;
#[cfg(feature = "parsing")]
pub mod parsing;
mod primitive_date_time;
#[cfg(feature = "quickcheck")]
mod quickcheck;
#[cfg(feature = "rand")]
mod rand;
#[cfg(feature = "serde")]
#[allow(missing_copy_implementations, missing_debug_implementations)]
pub mod serde;
mod sys;
#[cfg(test)]
mod tests;
mod time;
mod utc_offset;
pub mod util;
mod weekday;

pub use crate::date::Date;
pub use crate::duration::Duration;
pub use crate::error::Error;
#[cfg(feature = "std")]
pub use crate::instant::Instant;
pub use crate::month::Month;
pub use crate::offset_date_time::OffsetDateTime;
pub use crate::primitive_date_time::PrimitiveDateTime;
pub use crate::time::Time;
pub use crate::utc_offset::UtcOffset;
pub use crate::weekday::Weekday;

/// An alias for [`std::result::Result`] with a generic error from the time crate.
pub type Result<T> = core::result::Result<T, Error>;

/// This is a separate function to reduce the code size of `expect_opt!`.
#[inline(never)]
#[cold]
#[track_caller]
const fn expect_failed(message: &str) -> ! {
    panic!("{}", message)
}
<commit_msg>Unconditionally enable rustdoc-prefixed lints<commit_after>//! # Feature flags
//!
//! This crate exposes a number of features. These can be enabled or disabled as shown
//! [in Cargo's documentation](https://doc.rust-lang.org/cargo/reference/features.html). Features
//! are _disabled_ by default unless otherwise noted.
//!
//! Reliance on a given feature is always indicated alongside the item definition.
//!
//! - `std` (_enabled by default, implicitly enables `alloc`_)
//!
//!   This enables a number of features that depend on the standard library.
//!
//! - `alloc` (_enabled by default via `std`_)
//!
//!   Enables a number of features that require the ability to dynamically allocate memory.
//!
//! - `macros`
//!
//!   Enables macros that provide compile-time verification of values and intuitive syntax.
//!
//! - `formatting` (_implicitly enables `std`_)
//!
//!   Enables formatting of most structs.
//!
//! - `parsing`
//!
//!   Enables parsing of most structs.
//!
//! - `local-offset` (_implicitly enables `std`_)
//!
//!   This feature enables a number of methods that allow obtaining the system's UTC offset.
//!
//! - `large-dates`
//!
//!   By default, only years within the ±9999 range (inclusive) are supported. If you need support
//!   for years outside this range, consider enabling this feature; the supported range will be
//!   increased to ±999,999.
//!
//!   Note that enabling this feature has some costs, as it means forgoing some optimizations.
//!   Ambiguities may be introduced when parsing that would not otherwise exist.
//!
//! - `serde`
//!
//!   Enables [serde](https://docs.rs/serde) support for all types except [`Instant`].
//!
//! - `serde-human-readable` (_implicitly enables `serde`, `formatting`, and `parsing`_)
//!
//!   Allows serde representations to use a human-readable format. This is determined by the
//!   serializer, not the user. If this feature is not enabled or if the serializer requests a
//!   non-human-readable format, a format optimized for binary representation will be used.
//!
//!   Libraries should never enable this feature, as the decision of what format to use should be up
//!   to the user.
//!
//! - `serde-well-known` (_implicitly enables `serde/alloc`, `formatting`, and `parsing`_)
//!
//!   Enables support for serializing and deserializing well-known formats using serde's
//!   [`#[with]` attribute](https://serde.rs/field-attrs.html#with).
//!
//! - `rand`
//!
//!   Enables [rand](https://docs.rs/rand) support for all types.
//!
//! - `quickcheck` (_implicitly enables `alloc`_)
//!
//!   Enables [quickcheck](https://docs.rs/quickcheck) support for all types except [`Instant`].
//!
//! - `wasm-bindgen`
//!
//!   Enables [wasm-bindgen](https://github.com/rustwasm/wasm-bindgen) support for converting
//!   [JavaScript dates](https://rustwasm.github.io/wasm-bindgen/api/js_sys/struct.Date.html), as
//!   well as obtaining the UTC offset from JavaScript.
//!
//! One pseudo-feature flag that is only available to end users is the `unsound_local_offset` cfg.
//! As the name indicates, using the feature is unsound, and [may cause unexpected segmentation
//! faults](https://github.com/time-rs/time/issues/293). Unlike other flags, this is deliberately
//! only available to end users; this is to ensure that a user doesn't have unsound behavior without
//! knowing it. To enable this behavior, you must use `RUSTFLAGS="--cfg unsound_local_offset" cargo
//! build` or similar. Note: This flag is _not tested anywhere_, including in the regular test of
//! the powerset of all feature flags. Use at your own risk. Without this flag, any method that
//! requires the local offset will return the `Err` variant when otherwise unsound.

#![doc(html_playground_url = "https://play.rust-lang.org")]
#![cfg_attr(__time_03_docs, feature(doc_auto_cfg, doc_notable_trait))]
#![cfg_attr(not(feature = "std"), no_std)]
#![deny(
    anonymous_parameters,
    clippy::all,
    clippy::alloc_instead_of_core,
    clippy::explicit_auto_deref,
    clippy::obfuscated_if_else,
    clippy::std_instead_of_core,
    clippy::undocumented_unsafe_blocks,
    const_err,
    illegal_floating_point_literal_pattern,
    late_bound_lifetime_arguments,
    path_statements,
    patterns_in_fns_without_body,
    rust_2018_idioms,
    trivial_casts,
    trivial_numeric_casts,
    unreachable_pub,
    unsafe_op_in_unsafe_fn,
    unused_extern_crates,
    rustdoc::broken_intra_doc_links,
    rustdoc::private_intra_doc_links
)]
#![warn(
    clippy::dbg_macro,
    clippy::decimal_literal_representation,
    clippy::get_unwrap,
    clippy::missing_docs_in_private_items,
    clippy::nursery,
    clippy::print_stdout,
    clippy::todo,
    clippy::unimplemented,
    clippy::unnested_or_patterns,
    clippy::unwrap_in_result,
    clippy::unwrap_used,
    clippy::use_debug,
    deprecated_in_future,
    missing_copy_implementations,
    missing_debug_implementations,
    unused_qualifications,
    variant_size_differences
)]
#![allow(clippy::redundant_pub_crate)]
#![doc(html_favicon_url = "https://avatars0.githubusercontent.com/u/55999857")]
#![doc(html_logo_url = "https://avatars0.githubusercontent.com/u/55999857")]
#![doc(test(attr(deny(warnings))))]

#[allow(unused_extern_crates)]
#[cfg(feature = "alloc")]
extern crate alloc;

// region: macros
/// Helper macro for easily implementing `OpAssign`.
macro_rules! __impl_assign {
    ($sym:tt $op:ident $fn:ident $target:ty : $($(#[$attr:meta])* $t:ty),+) => {$(
        #[allow(unused_qualifications)]
        $(#[$attr])*
        impl core::ops::$op<$t> for $target {
            fn $fn(&mut self, rhs: $t) {
                *self = *self $sym rhs;
            }
        }
    )+};
}

/// Implement `AddAssign` for the provided types.
macro_rules! impl_add_assign {
    ($target:ty : $($(#[$attr:meta])* $t:ty),+ $(,)?) => {
        __impl_assign!(+ AddAssign add_assign $target : $($(#[$attr])* $t),+);
    };
}

/// Implement `SubAssign` for the provided types.
macro_rules! impl_sub_assign {
    ($target:ty : $($(#[$attr:meta])* $t:ty),+ $(,)?) => {
        __impl_assign!(- SubAssign sub_assign $target : $($(#[$attr])* $t),+);
    };
}

/// Implement `MulAssign` for the provided types.
macro_rules! impl_mul_assign {
    ($target:ty : $($(#[$attr:meta])* $t:ty),+ $(,)?) => {
        __impl_assign!(* MulAssign mul_assign $target : $($(#[$attr])* $t),+);
    };
}

/// Implement `DivAssign` for the provided types.
macro_rules! impl_div_assign {
    ($target:ty : $($(#[$attr:meta])* $t:ty),+ $(,)?) => {
        __impl_assign!(/ DivAssign div_assign $target : $($(#[$attr])* $t),+);
    };
}

/// Division of integers, rounding the resulting value towards negative infinity.
macro_rules! div_floor {
    ($a:expr, $b:expr) => {{
        let _a = $a;
        let _b = $b;

        let (_quotient, _remainder) = (_a / _b, _a % _b);

        if (_remainder > 0 && _b < 0) || (_remainder < 0 && _b > 0) {
            _quotient - 1
        } else {
            _quotient
        }
    }};
}

/// Cascade an out-of-bounds value.
macro_rules! cascade {
    (@ordinal ordinal) => {};
    (@year year) => {};

    // Cascade an out-of-bounds value from "from" to "to".
    ($from:ident in $min:literal.. $max:literal => $to:tt) => {
        #[allow(unused_comparisons, unused_assignments)]
        if $from >= $max {
            $from -= $max - $min;
            $to += 1;
        } else if $from < $min {
            $from += $max - $min;
            $to -= 1;
        }
    };

    // Special case the ordinal-to-year cascade, as it has different behavior.
    ($ordinal:ident => $year:ident) => {
        // We need to actually capture the idents. Without this, macro hygiene causes errors.
        cascade!(@ordinal $ordinal);
        cascade!(@year $year);
        #[allow(unused_assignments)]
        if $ordinal > crate::util::days_in_year($year) as i16 {
            $ordinal -= crate::util::days_in_year($year) as i16;
            $year += 1;
        } else if $ordinal < 1 {
            $year -= 1;
            $ordinal += crate::util::days_in_year($year) as i16;
        }
    };
}

/// Returns `Err(error::ComponentRange)` if the value is not in range.
macro_rules! ensure_value_in_range {
    ($value:ident in $start:expr => $end:expr) => {{
        let _start = $start;
        let _end = $end;
        #[allow(trivial_numeric_casts, unused_comparisons)]
        if $value < _start || $value > _end {
            return Err(crate::error::ComponentRange {
                name: stringify!($value),
                minimum: _start as _,
                maximum: _end as _,
                value: $value as _,
                conditional_range: false,
            });
        }
    }};

    ($value:ident conditionally in $start:expr => $end:expr) => {{
        let _start = $start;
        let _end = $end;
        #[allow(trivial_numeric_casts, unused_comparisons)]
        if $value < _start || $value > _end {
            return Err(crate::error::ComponentRange {
                name: stringify!($value),
                minimum: _start as _,
                maximum: _end as _,
                value: $value as _,
                conditional_range: true,
            });
        }
    }};
}

/// Try to unwrap an expression, returning if not possible.
///
/// This is similar to the `?` operator, but does not perform `.into()`. Because of this, it is
/// usable in `const` contexts.
macro_rules! const_try {
    ($e:expr) => {
        match $e {
            Ok(value) => value,
            Err(error) => return Err(error),
        }
    };
}

/// Try to unwrap an expression, returning if not possible.
///
/// This is similar to the `?` operator, but is usable in `const` contexts.
macro_rules! const_try_opt {
    ($e:expr) => {
        match $e {
            Some(value) => value,
            None => return None,
        }
    };
}

/// Try to unwrap an expression, panicking if not possible.
///
/// This is similar to `$e.expect($message)`, but is usable in `const` contexts.
macro_rules! expect_opt {
    ($e:expr, $message:literal) => {
        match $e {
            Some(value) => value,
            None => crate::expect_failed($message),
        }
    };
}
// endregion macros

mod date;
mod duration;
pub mod error;
pub mod ext;
#[cfg(any(feature = "formatting", feature = "parsing"))]
pub mod format_description;
#[cfg(feature = "formatting")]
pub mod formatting;
#[cfg(feature = "std")]
mod instant;
#[cfg(feature = "macros")]
pub mod macros;
mod month;
mod offset_date_time;
#[cfg(feature = "parsing")]
pub mod parsing;
mod primitive_date_time;
#[cfg(feature = "quickcheck")]
mod quickcheck;
#[cfg(feature = "rand")]
mod rand;
#[cfg(feature = "serde")]
#[allow(missing_copy_implementations, missing_debug_implementations)]
pub mod serde;
mod sys;
#[cfg(test)]
mod tests;
mod time;
mod utc_offset;
pub mod util;
mod weekday;

pub use crate::date::Date;
pub use crate::duration::Duration;
pub use crate::error::Error;
#[cfg(feature = "std")]
pub use crate::instant::Instant;
pub use crate::month::Month;
pub use crate::offset_date_time::OffsetDateTime;
pub use crate::primitive_date_time::PrimitiveDateTime;
pub use crate::time::Time;
pub use crate::utc_offset::UtcOffset;
pub use crate::weekday::Weekday;

/// An alias for [`std::result::Result`] with a generic error from the time crate.
pub type Result<T> = core::result::Result<T, Error>;

/// This is a separate function to reduce the code size of `expect_opt!`.
#[inline(never)]
#[cold]
#[track_caller]
const fn expect_failed(message: &str) -> ! {
    panic!("{}", message)
}
<|endoftext|>


<commit_before>// Copyright 2015 The tiny-http Contributors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//	http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

/*!
# Simple usage

## Creating the server

The easiest way to create a server is to call `Server::http()`.

The `http()` function returns an `IoResult<Server>` which will return an error
in the case where the server creation fails (for example if the listening port is already
occupied).

```no_run
let server = tiny_http::Server::http("0.0.0.0:0").unwrap();
```

A newly-created `Server` will immediatly start listening for incoming connections and HTTP
requests.

## Receiving requests

Calling `server.recv()` will block until the next request is available.
This function returns an `IoResult<Request>`, so you need to handle the possible errors.

```no_run
# let server = tiny_http::Server::http("0.0.0.0:0").unwrap();

loop {
    // blocks until the next request is received
    let request = match server.recv() {
        Ok(rq) => rq,
        Err(e) => { println!("error: {}", e); break }
    };

    // do something with the request
    // ...
}
```

In a real-case scenario, you will probably want to spawn multiple worker tasks and call
`server.recv()` on all of them. Like this:

```no_run
# use std::sync::Arc;
# use std::thread;
# let server = tiny_http::Server::http("0.0.0.0:0").unwrap();
let server = Arc::new(server);
let mut guards = Vec::with_capacity(4);

for _ in (0 .. 4) {
    let server = server.clone();

    let guard = thread::spawn(move || {
        loop {
            let rq = server.recv().unwrap();

            // ...
        }
    });

    guards.push(guard);
}
```

If you don't want to block, you can call `server.try_recv()` instead.

## Handling requests

The `Request` object returned by `server.recv()` contains informations about the client's request.
The most useful methods are probably `request.method()` and `request.url()` which return
the requested method (`GET`, `POST`, etc.) and url.

To handle a request, you need to create a `Response` object. See the docs of this object for
more infos. Here is an example of creating a `Response` from a file:

```no_run
# use std::fs::File;
# use std::path::Path;
let response = tiny_http::Response::from_file(File::open(&Path::new("image.png")).unwrap());
```

All that remains to do is call `request.respond()`:

```no_run
# use std::fs::File;
# use std::path::Path;
# let server = tiny_http::Server::http("0.0.0.0:0").unwrap();
# let request = server.recv().unwrap();
# let response = tiny_http::Response::from_file(File::open(&Path::new("image.png")).unwrap());
request.respond(response)
```
*/
#![crate_name = "tiny_http"]
#![crate_type = "lib"]
#![forbid(unsafe_code)]

extern crate ascii;
extern crate chunked_transfer;
extern crate encoding;
extern crate url;
extern crate chrono;

#[cfg(feature = "ssl")]
extern crate openssl;

use std::error::Error;
use std::io::Error as IoError;
use std::io::Result as IoResult;
use std::sync::Arc;
use std::sync::atomic::AtomicBool;
use std::thread;
use std::net;
use std::net::ToSocketAddrs;

use client::ClientConnection;
use util::MessagesQueue;

pub use common::{Header, HeaderField, HTTPVersion, Method, StatusCode};
pub use request::Request;
pub use response::{ResponseBox, Response};

mod client;
mod common;
mod request;
mod response;

#[allow(dead_code)]     // TODO: remove when everything is implemented
mod util;

/// The main class of this library.
///
/// Destroying this object will immediatly close the listening socket annd the reading
///  part of all the client's connections. Requests that have already been returned by
///  the `recv()` function will not close and the responses will be transferred to the client.
pub struct Server {
    // should be false as long as the server exists
    // when set to true, all the subtasks will close within a few hundreds ms
    close: Arc<AtomicBool>,

    // queue for messages received by child threads
    messages: Arc<MessagesQueue<Message>>,

    // result of TcpListener::local_addr()
    listening_addr: net::SocketAddr,
}

enum Message {
    Error(IoError),
    NewRequest(Request),
}

impl From<IoError> for Message {
    fn from(e: IoError) -> Message {
        Message::Error(e)
    }
}

impl From<Request> for Message {
    fn from(rq: Request) -> Message {
        Message::NewRequest(rq)
    }
}

// this trait is to make sure that Server implements Share and Send
#[doc(hidden)]
trait MustBeShareDummy : Sync + Send {}
#[doc(hidden)]
impl MustBeShareDummy for Server {}

pub struct IncomingRequests<'a> {
    server: &'a Server
}

/// Represents the parameters required to create a server.
#[derive(Debug, Clone)]
pub struct ServerConfig<A> where A: ToSocketAddrs {
    /// The addresses to listen to.
    pub addr: A,

    /// If `Some`, then the server will use SSL to encode the communications.
    pub ssl: Option<SslConfig>,
}

/// Configuration of the server for SSL.
#[derive(Debug, Clone)]
pub struct SslConfig {
    /// Contains the public certificate to send to clients.
    pub certificate: Vec<u8>,
    /// Contains the ultra-secret private key used to decode communications.
    pub private_key: Vec<u8>,
}

impl Server {
    /// Shortcut for a simple server on a specific address.
    #[inline]
    pub fn http<A>(addr: A) -> Result<Server, Box<Error + Send + Sync + 'static>>
        where A: ToSocketAddrs
    {
        Server::new(ServerConfig {
            addr: addr,
            ssl: None,
        })
    }

    /// Shortcut for an HTTPS server on a specific address.
    #[cfg(feature = "ssl")]
    #[inline]
    pub fn https<A>(addr: A, config: SslConfig)
                    -> Result<Server, Box<Error + Send + Sync + 'static>>
        where A: ToSocketAddrs
    {
        Server::new(ServerConfig {
            addr: addr,
            ssl: Some(config),
        })
    }

    /// Builds a new server that listens on the specified address.
    pub fn new<A>(config: ServerConfig<A>) -> Result<Server, Box<Error + Send + Sync + 'static>>
        where A: ToSocketAddrs
    {
        // building the "close" variable
        let close_trigger = Arc::new(AtomicBool::new(false));

        // building the TcpListener
        let (server, local_addr) = {
            let listener = try!(net::TcpListener::bind(config.addr));
            let local_addr = try!(listener.local_addr());
            (listener, local_addr)
        };

        // building the SSL capabilities
        #[cfg(feature = "ssl")]
        type SslContext = openssl::ssl::SslContext;
        #[cfg(not(feature = "ssl"))]
        type SslContext = ();
        let ssl: Option<SslContext> = match config.ssl {
            #[cfg(feature = "ssl")]
            Some(mut config) => {
                use std::io::Cursor;
                use openssl::ssl;
                use openssl::x509::X509;
                use openssl::crypto::pkey::PKey;
                use openssl::ssl::SSL_VERIFY_PEER;

                let mut ctxt = try!(SslContext::new(ssl::SslMethod::Sslv23));
                try!(ctxt.set_cipher_list("DEFAULT"));
                let certificate = try!(X509::from_pem(&mut Cursor::new(&config.certificate)));
                try!(ctxt.set_certificate(&certificate));
                let private_key = try!(PKey::private_key_from_pem(&mut Cursor::new(&config.private_key)));
                try!(ctxt.set_private_key(&private_key));
                //ctxt.set_verify(SSL_VERIFY_PEER, None);
                try!(ctxt.check_private_key());

                // let's wipe the certificate and private key from memory, because we're
                // better safe than sorry
                for b in &mut config.certificate { *b = 0; }
                for b in &mut config.private_key { *b = 0; }

                Some(ctxt)
            },
            #[cfg(not(feature = "ssl"))]
            Some(_) => return Err("Building a server with SSL requires enabling the `ssl` feature \
                                   in tiny-http".to_owned().into()),
            None => None,
        };

        // creating a task where server.accept() is continuously called
        // and ClientConnection objects are pushed in the messages queue
        let messages = MessagesQueue::with_capacity(8);

        let inside_close_trigger = close_trigger.clone();
        let inside_messages = messages.clone();
        thread::spawn(move || {
            // a tasks pool is used to dispatch the connections into threads
            let tasks_pool = util::TaskPool::new();

            loop {
                let new_client = server.accept().map(|(sock, _)| {
                    use util::RefinedTcpStream;

                    let (read_closable, write_closable) = match ssl {
                        None => RefinedTcpStream::new(sock),
                        #[cfg(feature = "ssl")]
                        Some(ref ssl) => {
                            let sock = openssl::ssl::SslStream::accept(ssl, sock).unwrap();     // FIXME: handle this error
                            RefinedTcpStream::new(sock)
                        },
                        #[cfg(not(feature = "ssl"))]
                        Some(_) => unreachable!(),
                    };

                    ClientConnection::new(write_closable, read_closable)
                });

                match new_client {
                    Ok(client) => {
                        let messages = inside_messages.clone();
                        let mut client = Some(client);
                        tasks_pool.spawn(Box::new(move || {
                            if let Some(client) = client.take() {
                                for rq in client {
                                    messages.push(rq.into());
                                }
                            }
                        }));
                    },

                    Err(e) => {
                        inside_messages.push(e.into());
                        break;
                    }
                }
            }
        });

        // result
        Ok(Server {
            messages: messages,
            close: close_trigger,
            listening_addr: local_addr,
        })
    }

    /// Returns an iterator for all the incoming requests.
    ///
    /// The iterator will return `None` if the server socket is shutdown.
    #[inline]
    pub fn incoming_requests(&self) -> IncomingRequests {
        IncomingRequests { server: self }
    }

    /// Returns the address the server is listening to.
    #[inline]
    pub fn server_addr(&self) -> net::SocketAddr {
        self.listening_addr.clone()
    }

    /// Returns the number of clients currently connected to the server.
    pub fn num_connections(&self) -> usize {
        unimplemented!()
        //self.requests_receiver.lock().len()
    }

    /// Blocks until an HTTP request has been submitted and returns it.
    pub fn recv(&self) -> IoResult<Request> {
        loop {
            match self.messages.pop() {
                Message::Error(err) => return Err(err),
                Message::NewRequest(rq) => return Ok(rq),
            }
        }
    }

    /// Same as `recv()` but doesn't block.
    pub fn try_recv(&self) -> IoResult<Option<Request>> {
        loop {
            match self.messages.try_pop() {
                Some(Message::Error(err)) => return Err(err),
                Some(Message::NewRequest(rq)) => return Ok(Some(rq)),
                None => return Ok(None)
            }
        }
    }
}

impl<'a> Iterator for IncomingRequests<'a> {
    type Item = Request;
    fn next(&mut self) -> Option<Request> {
        self.server.recv().ok()
    }
}

impl Drop for Server {
    fn drop(&mut self) {
        use std::sync::atomic::Ordering::Relaxed;
        self.close.store(true, Relaxed);
    }
}
<commit_msg>Handle SSL errors when receiving a connection<commit_after>// Copyright 2015 The tiny-http Contributors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//	http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

/*!
# Simple usage

## Creating the server

The easiest way to create a server is to call `Server::http()`.

The `http()` function returns an `IoResult<Server>` which will return an error
in the case where the server creation fails (for example if the listening port is already
occupied).

```no_run
let server = tiny_http::Server::http("0.0.0.0:0").unwrap();
```

A newly-created `Server` will immediatly start listening for incoming connections and HTTP
requests.

## Receiving requests

Calling `server.recv()` will block until the next request is available.
This function returns an `IoResult<Request>`, so you need to handle the possible errors.

```no_run
# let server = tiny_http::Server::http("0.0.0.0:0").unwrap();

loop {
    // blocks until the next request is received
    let request = match server.recv() {
        Ok(rq) => rq,
        Err(e) => { println!("error: {}", e); break }
    };

    // do something with the request
    // ...
}
```

In a real-case scenario, you will probably want to spawn multiple worker tasks and call
`server.recv()` on all of them. Like this:

```no_run
# use std::sync::Arc;
# use std::thread;
# let server = tiny_http::Server::http("0.0.0.0:0").unwrap();
let server = Arc::new(server);
let mut guards = Vec::with_capacity(4);

for _ in (0 .. 4) {
    let server = server.clone();

    let guard = thread::spawn(move || {
        loop {
            let rq = server.recv().unwrap();

            // ...
        }
    });

    guards.push(guard);
}
```

If you don't want to block, you can call `server.try_recv()` instead.

## Handling requests

The `Request` object returned by `server.recv()` contains informations about the client's request.
The most useful methods are probably `request.method()` and `request.url()` which return
the requested method (`GET`, `POST`, etc.) and url.

To handle a request, you need to create a `Response` object. See the docs of this object for
more infos. Here is an example of creating a `Response` from a file:

```no_run
# use std::fs::File;
# use std::path::Path;
let response = tiny_http::Response::from_file(File::open(&Path::new("image.png")).unwrap());
```

All that remains to do is call `request.respond()`:

```no_run
# use std::fs::File;
# use std::path::Path;
# let server = tiny_http::Server::http("0.0.0.0:0").unwrap();
# let request = server.recv().unwrap();
# let response = tiny_http::Response::from_file(File::open(&Path::new("image.png")).unwrap());
request.respond(response)
```
*/
#![crate_name = "tiny_http"]
#![crate_type = "lib"]
#![forbid(unsafe_code)]

extern crate ascii;
extern crate chunked_transfer;
extern crate encoding;
extern crate url;
extern crate chrono;

#[cfg(feature = "ssl")]
extern crate openssl;

use std::error::Error;
use std::io::Error as IoError;
use std::io::Result as IoResult;
use std::sync::Arc;
use std::sync::atomic::AtomicBool;
use std::thread;
use std::net;
use std::net::ToSocketAddrs;

use client::ClientConnection;
use util::MessagesQueue;

pub use common::{Header, HeaderField, HTTPVersion, Method, StatusCode};
pub use request::Request;
pub use response::{ResponseBox, Response};

mod client;
mod common;
mod request;
mod response;

#[allow(dead_code)]     // TODO: remove when everything is implemented
mod util;

/// The main class of this library.
///
/// Destroying this object will immediatly close the listening socket annd the reading
///  part of all the client's connections. Requests that have already been returned by
///  the `recv()` function will not close and the responses will be transferred to the client.
pub struct Server {
    // should be false as long as the server exists
    // when set to true, all the subtasks will close within a few hundreds ms
    close: Arc<AtomicBool>,

    // queue for messages received by child threads
    messages: Arc<MessagesQueue<Message>>,

    // result of TcpListener::local_addr()
    listening_addr: net::SocketAddr,
}

enum Message {
    Error(IoError),
    NewRequest(Request),
}

impl From<IoError> for Message {
    fn from(e: IoError) -> Message {
        Message::Error(e)
    }
}

impl From<Request> for Message {
    fn from(rq: Request) -> Message {
        Message::NewRequest(rq)
    }
}

// this trait is to make sure that Server implements Share and Send
#[doc(hidden)]
trait MustBeShareDummy : Sync + Send {}
#[doc(hidden)]
impl MustBeShareDummy for Server {}

pub struct IncomingRequests<'a> {
    server: &'a Server
}

/// Represents the parameters required to create a server.
#[derive(Debug, Clone)]
pub struct ServerConfig<A> where A: ToSocketAddrs {
    /// The addresses to listen to.
    pub addr: A,

    /// If `Some`, then the server will use SSL to encode the communications.
    pub ssl: Option<SslConfig>,
}

/// Configuration of the server for SSL.
#[derive(Debug, Clone)]
pub struct SslConfig {
    /// Contains the public certificate to send to clients.
    pub certificate: Vec<u8>,
    /// Contains the ultra-secret private key used to decode communications.
    pub private_key: Vec<u8>,
}

impl Server {
    /// Shortcut for a simple server on a specific address.
    #[inline]
    pub fn http<A>(addr: A) -> Result<Server, Box<Error + Send + Sync + 'static>>
        where A: ToSocketAddrs
    {
        Server::new(ServerConfig {
            addr: addr,
            ssl: None,
        })
    }

    /// Shortcut for an HTTPS server on a specific address.
    #[cfg(feature = "ssl")]
    #[inline]
    pub fn https<A>(addr: A, config: SslConfig)
                    -> Result<Server, Box<Error + Send + Sync + 'static>>
        where A: ToSocketAddrs
    {
        Server::new(ServerConfig {
            addr: addr,
            ssl: Some(config),
        })
    }

    /// Builds a new server that listens on the specified address.
    pub fn new<A>(config: ServerConfig<A>) -> Result<Server, Box<Error + Send + Sync + 'static>>
        where A: ToSocketAddrs
    {
        // building the "close" variable
        let close_trigger = Arc::new(AtomicBool::new(false));

        // building the TcpListener
        let (server, local_addr) = {
            let listener = try!(net::TcpListener::bind(config.addr));
            let local_addr = try!(listener.local_addr());
            (listener, local_addr)
        };

        // building the SSL capabilities
        #[cfg(feature = "ssl")]
        type SslContext = openssl::ssl::SslContext;
        #[cfg(not(feature = "ssl"))]
        type SslContext = ();
        let ssl: Option<SslContext> = match config.ssl {
            #[cfg(feature = "ssl")]
            Some(mut config) => {
                use std::io::Cursor;
                use openssl::ssl;
                use openssl::x509::X509;
                use openssl::crypto::pkey::PKey;
                use openssl::ssl::SSL_VERIFY_PEER;

                let mut ctxt = try!(SslContext::new(ssl::SslMethod::Sslv23));
                try!(ctxt.set_cipher_list("DEFAULT"));
                let certificate = try!(X509::from_pem(&mut Cursor::new(&config.certificate)));
                try!(ctxt.set_certificate(&certificate));
                let private_key = try!(PKey::private_key_from_pem(&mut Cursor::new(&config.private_key)));
                try!(ctxt.set_private_key(&private_key));
                //ctxt.set_verify(SSL_VERIFY_PEER, None);
                try!(ctxt.check_private_key());

                // let's wipe the certificate and private key from memory, because we're
                // better safe than sorry
                for b in &mut config.certificate { *b = 0; }
                for b in &mut config.private_key { *b = 0; }

                Some(ctxt)
            },
            #[cfg(not(feature = "ssl"))]
            Some(_) => return Err("Building a server with SSL requires enabling the `ssl` feature \
                                   in tiny-http".to_owned().into()),
            None => None,
        };

        // creating a task where server.accept() is continuously called
        // and ClientConnection objects are pushed in the messages queue
        let messages = MessagesQueue::with_capacity(8);

        let inside_close_trigger = close_trigger.clone();
        let inside_messages = messages.clone();
        thread::spawn(move || {
            // a tasks pool is used to dispatch the connections into threads
            let tasks_pool = util::TaskPool::new();

            loop {
                let new_client = match server.accept() {
                    Ok((sock, _)) => {
                        use util::RefinedTcpStream;

                        let (read_closable, write_closable) = match ssl {
                            None => {
                                RefinedTcpStream::new(sock)
                            },
                            #[cfg(feature = "ssl")]
                            Some(ref ssl) => {
                                // trying to apply SSL over the connection
                                // if an error occurs, we just close the socket and resume listening
                                let sock = match openssl::ssl::SslStream::accept(ssl, sock) {
                                    Ok(s) => s,
                                    Err(_) => continue
                                };

                                RefinedTcpStream::new(sock)
                            },
                            #[cfg(not(feature = "ssl"))]
                            Some(_) => unreachable!(),
                        };

                        Ok(ClientConnection::new(write_closable, read_closable))
                    },
                    Err(e) => Err(e),
                };

                match new_client {
                    Ok(client) => {
                        let messages = inside_messages.clone();
                        let mut client = Some(client);
                        tasks_pool.spawn(Box::new(move || {
                            if let Some(client) = client.take() {
                                for rq in client {
                                    messages.push(rq.into());
                                }
                            }
                        }));
                    },

                    Err(e) => {
                        inside_messages.push(e.into());
                        break;
                    }
                }
            }
        });

        // result
        Ok(Server {
            messages: messages,
            close: close_trigger,
            listening_addr: local_addr,
        })
    }

    /// Returns an iterator for all the incoming requests.
    ///
    /// The iterator will return `None` if the server socket is shutdown.
    #[inline]
    pub fn incoming_requests(&self) -> IncomingRequests {
        IncomingRequests { server: self }
    }

    /// Returns the address the server is listening to.
    #[inline]
    pub fn server_addr(&self) -> net::SocketAddr {
        self.listening_addr.clone()
    }

    /// Returns the number of clients currently connected to the server.
    pub fn num_connections(&self) -> usize {
        unimplemented!()
        //self.requests_receiver.lock().len()
    }

    /// Blocks until an HTTP request has been submitted and returns it.
    pub fn recv(&self) -> IoResult<Request> {
        loop {
            match self.messages.pop() {
                Message::Error(err) => return Err(err),
                Message::NewRequest(rq) => return Ok(rq),
            }
        }
    }

    /// Same as `recv()` but doesn't block.
    pub fn try_recv(&self) -> IoResult<Option<Request>> {
        loop {
            match self.messages.try_pop() {
                Some(Message::Error(err)) => return Err(err),
                Some(Message::NewRequest(rq)) => return Ok(Some(rq)),
                None => return Ok(None)
            }
        }
    }
}

impl<'a> Iterator for IncomingRequests<'a> {
    type Item = Request;
    fn next(&mut self) -> Option<Request> {
        self.server.recv().ok()
    }
}

impl Drop for Server {
    fn drop(&mut self) {
        use std::sync::atomic::Ordering::Relaxed;
        self.close.store(true, Relaxed);
    }
}
<|endoftext|>


<commit_before>// Copyright 2014 The Servo Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution.
//
// 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.

#![crate_name = "string_cache"]
#![crate_type = "rlib"]

#![cfg_attr(test, deny(warnings))]
#![cfg_attr(all(test, feature = "unstable"), feature(test))]

#[cfg(all(test, feature = "unstable"))] extern crate test;
#[cfg(all(test, feature = "unstable"))] extern crate rand;
#[macro_use] extern crate lazy_static;
#[macro_use] extern crate debug_unreachable;
extern crate phf_shared;
extern crate precomputed_hash;
extern crate serde;
extern crate string_cache_shared as shared;

pub use atom::{Atom, StaticAtomSet, PhfStrSet, EmptyStaticAtomSet, DefaultAtom};

#[cfg(feature = "log-events")]
#[macro_use]
pub mod event;

pub mod atom;

// Make test_atom! macro work in this crate.
// `$crate` would not be appropriate for other crates creating such macros
mod string_cache {
    pub use {Atom, StaticAtomSet, PhfStrSet};
}
<commit_msg>Added some module-level docs<commit_after>// Copyright 2014 The Servo Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution.
//
// 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.

//!
//! A library for interning things that are `AsRef<str>`.
//!
//! Some strings may be interned at compile time using the `string-cache-codegen` crate, or the
//! `EmptyStaticAtomSet` may be used that has no comiple-time interned strings. An `Atom` is an
//! interned string for a given set (either `EmptyStaticAtomSet` or a generated `StaticAtomSet`).
//!
//! Generated `Atom`s will have assocated macros to intern static strings at compile-time.
//!
//! # Examples
//!
//! Here are two examples, one with compile-time `Atom`s, and one without.
//!
//! ## With compile-time atoms
//!
//! In `Cargo.toml`:
//! ```toml
//! [dependencies]
//! string_cache = "0.7"
//!
//! [dev-dependencies]
//! string_cache_codegen = "0.4"
//! ```
//!
//! In `build.rs`:
//! ```rust
//! extern crate string_cache_codegen;
//!
//! use std::env;
//! use std::path::Path;
//!
//! fn main() {
//!     string_cache_codegen::AtomType::new("foo::FooAtom", "foo_atom!")
//!         .atoms(&["foo", "bar"])
//!         .write_to_file(&Path::new(&env::var("OUT_DIR").unwrap()).join("foo_atom.rs"))
//!         .unwrap()
//! }
//! ```
//!
//! In `lib.rs`:
//! ```rust
//! extern crate string_cache;
//!
//! mod foo {
//!     include!(concat!(env!("OUT_DIR"), "/foo_atom.rs"));
//! }
//!
//! fn use_the_atom(t: &str) {
//!     match *t {
//!         foo_atom!("foo") => println!("Found foo!"),
//!         foo_atom!("bar") => println!("Found bar!"),
//!         // foo_atom!("baz") => println!("Found baz!"), - would be a compile time error
//!         _ => {
//!             println!("String not interned");
//!             // We can intern strings at runtime as well
//!             foo::FooAtom::from(t)
//!         }
//!     }
//! }
//! ```
//!
//! ## No compile-time atoms
//!
//! ```rust
//! extern crate string_cache;
//!
//!
//! let mut interned_stuff = Vec::new();
//! let text = "here is a sentence of text that will be tokenised and
//!             interned and some repeated tokens is of text and";
//! for word in text.split_whitespace() {
//!     let seen_before = interned_stuff.iter()
//!         // We can use impl PartialEq<T> where T is anything string-like
//!         // to compare to interned strings to either other interned strings,
//!         // or actual strings  Comparing two interned strings is very fast
//!         // (normally a single cpu operation).
//!         .filter(|interned_word| interned_word == &word)
//!         .count();
//!     if seen_before > 0 {
//!         println!(r#"Seen the word "{}" {} times"#, word, seen_before);
//!     } else {
//!         println!(r#"Not seen the word "{}" before"#, word);
//!     }
//!     // We use the impl From<(Cow<'a, str>, or &'a str, or String)> for
//!     // Atom<Static> to intern a new string.
//!     interned_stuff.push(DefaultAtom::from(word));
//! }
//! ```
//!

#![crate_name = "string_cache"]
#![crate_type = "rlib"]

#![cfg_attr(test, deny(warnings))]
#![cfg_attr(all(test, feature = "unstable"), feature(test))]

#[cfg(all(test, feature = "unstable"))] extern crate test;
#[cfg(all(test, feature = "unstable"))] extern crate rand;
#[macro_use] extern crate lazy_static;
#[macro_use] extern crate debug_unreachable;
extern crate phf_shared;
extern crate precomputed_hash;
extern crate serde;
extern crate string_cache_shared as shared;

pub use atom::{Atom, StaticAtomSet, PhfStrSet, EmptyStaticAtomSet, DefaultAtom};

#[cfg(feature = "log-events")]
#[macro_use]
pub mod event;

pub mod atom;

// Make test_atom! macro work in this crate.
// `$crate` would not be appropriate for other crates creating such macros
mod string_cache {
    pub use {Atom, StaticAtomSet, PhfStrSet};
}
<|endoftext|>