<commit_before>// Copyright 2015 Nathan Sizemore <nathanrsizemore@gmail.com>
//
// This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
// If a copy of the MPL was not distributed with this file,
// You can obtain one at http://mozilla.org/MPL/2.0/.

extern crate libc;
extern crate simple_slab;
#[macro_use] extern crate bitflags;

use std::ops::Drop;
use std::sync::Mutex;
use std::io::{self, Error};
use std::os::unix::io::{RawFd, AsRawFd};
use std::time::{Duration, Instant};

use simple_slab::Slab;
pub use interest::Interest;

mod interest;

bitflags! {
    pub flags ControlOptions: i32 {
        /// Indicates an addition to the interest list.
        const EPOLL_CTL_ADD = libc::EPOLL_CTL_ADD,
        /// Indicates a modification of flags for an interest already in list.
        const EPOLL_CTL_MOD = libc::EPOLL_CTL_MOD,
        /// Indicates a removal of an interest from the list.
        const EPOLL_CTL_DEL = libc::EPOLL_CTL_DEL
    }
}

bitflags! {
    pub flags Events: u32 {
        /// Sets the Edge Triggered behavior for the associated file descriptor.
        ///
        /// The default behavior for epoll is Level Triggered.
        const EPOLLET      = libc::EPOLLET as u32,
        /// The associated file is available for read operations.
        const EPOLLIN      = libc::EPOLLIN as u32,
        /// Error condition happened on the associated file descriptor.
        ///
        /// `wait` will always wait for this event; is not necessary to set it in events.
        const EPOLLERR     = libc::EPOLLERR as u32,
        /// Hang up happened on the associated file descriptor.
        ///
        /// `wait` will always wait for this event; it is not necessary to set it in events.
        /// Note that when reading from a channel such as a pipe or a stream socket, this event
        /// merely indicates that the peer closed its end of the channel. Subsequent reads from
        /// the channel will return 0 (end of file) only after all outstanding data in the
        /// channel has been consumed.
        const EPOLLHUP     = libc::EPOLLHUP as u32,
        /// The associated file is available for write operations.
        const EPOLLOUT     = libc::EPOLLOUT as u32,
        /// There is urgent data available for read operations.
        const EPOLLPRI     = libc::EPOLLPRI as u32,
        /// Stream socket peer closed connection, or shut down writing half of connection.
        ///
        /// This flag is especially useful for writing simple code to detect peer shutdown when
        /// using Edge Triggered monitoring.
        const EPOLLRDHUP   = libc::EPOLLRDHUP as u32,
        /// If `EPOLLONESHOT` and `EPOLLET` are clear and the process has the `CAP_BLOCK_SUSPEND`
        /// capability, ensure that the system does not enter "suspend" or "hibernate" while this
        /// event is pending or being processed.
        ///
        /// The event is considered as being "processed" from the time when it is returned by
        /// a call to `wait` until the next call to `wait` on the same `EpollInstance`
        /// descriptor, the closure of that file descriptor, the removal of the event file
        /// descriptor with `EPOLL_CTL_DEL`, or the clearing of `EPOLLWAKEUP` for the event file
        /// descriptor with `EPOLL_CTL_MOD`.
        const EPOLLWAKEUP  = libc::EPOLLWAKEUP as u32,
        /// Sets the one-shot behavior for the associated file descriptor.
        ///
        /// This means that after an event is pulled out with `wait` the associated file
        /// descriptor is internally disabled and no other events will be reported by the epoll
        /// interface.  The user must call `ctl` with `EPOLL_CTL_MOD` to rearm the file
        /// descriptor with a new event mask.
        const EPOLLONESHOT = libc::EPOLLONESHOT as u32
    }
}

/// Thread safe abstraction, plus timers, around an epoll RawFd.
pub struct EpollInstance {
    fd: libc::c_int,
    interest_mutex: Mutex<Slab<Interest>>,
    events: u64,
    wait: Duration
}

impl EpollInstance {

    /// Creates a new `EpollInstance`.
    ///
    /// ## Notes
    /// * `FD_CLOEXEC` flag is set on the underlying fd returned.
    pub fn new() -> io::Result<EpollInstance> {
        Ok(EpollInstance {
            fd: try!(create(true)),
            interest_mutex: Mutex::new(Slab::<Interest>::new()),
            events: 0,
            wait: Duration::new(0, 0)
        })
    }

    /// Register an initial `Interest` with this instance.
    ///
    /// ## Panics
    ///
    /// Panics if the interior Mutex has been poisoned.
    pub fn add_interest(&mut self, interest: Interest) -> io::Result<()> {
        let mut event_mask = interest::int2event(&interest);

        try!(ctl(self.fd,
                 EPOLL_CTL_ADD,
                 interest.as_raw_fd(),
                 &mut event_mask as *mut libc::epoll_event));

        let mut list = self.interest_mutex.lock().unwrap();
        (*list).insert(interest);

        Ok(())
    }

    /// Modify the original `Interest`, identified by its `RawFd`, to the passed
    /// interest's events and data fields.
    ///
    /// ## Panics
    ///
    /// Panics if the interior Mutex has been poisoned.
    pub fn mod_interest(&mut self, interest: &Interest) -> io::Result<()> {
        let mut event_mask = interest::int2event(interest);

        try!(ctl(self.fd,
                 EPOLL_CTL_MOD,
                 interest.as_raw_fd(),
                 &mut event_mask as *mut libc::epoll_event));

        let mut list = self.interest_mutex.lock().unwrap();
        for ref mut _interest in (*list).iter_mut() {
            if _interest.as_raw_fd() == interest.as_raw_fd() {
                _interest.set_events(interest.events());
                _interest.set_data(interest.data());
                break;
            }
        }

        Ok(())
    }

    /// Remove the passed `Interest`, identified by its `RawFd`, from this instance.
    ///
    /// ## Panics
    ///
    /// Panics if the interior Mutex has been poisoned.
    pub fn del_interest(&mut self, interest: &Interest) -> io::Result<()> {
        // In kernel versions before 2.6.9, the EPOLL_CTL_DEL operation required a non-null
        // pointer in event, even though this argument is ignored.
        let mut event_mask = libc::epoll_event {
            events: 0u32,
            u64: 0u64
        };

        try!(ctl(self.fd,
                 EPOLL_CTL_DEL,
                 interest.as_raw_fd(),
                 &mut event_mask as *mut libc::epoll_event));

        let mut offset: usize = 0;
        let mut list = self.interest_mutex.lock().unwrap();
        for ref mut _interest in (*list).iter() {
            if _interest.as_raw_fd() == interest.as_raw_fd() {
                break;
            }
            offset += 1
        }
        (*list).remove(offset);

        Ok(())
    }

    /// Waits for events on this instance for at most `timeout` milliseconds and returns at most
    /// `max_returned` `Interests`.
    ///
    /// ## Notes
    ///
    /// * If `timeout` is negative, it will block until an event is received.
    /// * `max_returned` must be greater than zero.
    ///
    /// ## Panics
    ///
    /// Panics if the interior Mutex has been poisoned.
    pub fn wait(&mut self, timeout: i32, max_returned: usize) -> io::Result<Vec<Interest>> {
        let start = Instant::now();
        let buf = try!(wait(self.fd, timeout, max_returned));
        self.events += buf.len() as u64;
        self.wait += start.elapsed();

        let mut ret_buf = Vec::<Interest>::with_capacity(buf.len());
        let mut list = self.interest_mutex.lock().unwrap();
        for ref event in buf.iter() {
            for ref mut interest in (*list).iter_mut() {
                if interest.data() == event.u64 {
                    (*interest.events_mut()) = Events::from_bits(event.events).unwrap();
                    ret_buf.push(interest.clone());
                    break;
                }
            }
        }

        Ok(ret_buf)
    }

    /// Returns the total number of events reported.
    pub fn events(&self) -> u64 {
        self.events
    }

    /// Returns the total time spent in a blocked, waiting state.
    pub fn wait_time(&self) -> Duration {
        self.wait
    }
}

impl AsRawFd for EpollInstance {
    fn as_raw_fd(&self) -> RawFd { self.fd }
}

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

unsafe impl Send for EpollInstance {}
unsafe impl Sync for EpollInstance {}

/// Creates a new epoll file descriptor.
///
/// If `cloexec` is true, `FD_CLOEXEC` will be set on the returned file descriptor.
///
/// ## Notes
///
/// * `epoll_create(1)` is the underlying syscall.
pub fn create(cloexec: bool) -> io::Result<RawFd> {
    let epfd = unsafe {
        let fd = try!(cvt(libc::epoll_create(1)));

        if cloexec {
            let mut flags = try!(cvt(libc::fcntl(fd, libc::F_GETFD)));
            flags |= libc::FD_CLOEXEC;
            try!(cvt(libc::fcntl(fd, libc::F_SETFD, flags)));
        }
        fd
    };

    Ok(epfd)
}

/// Calls the `epoll_ctl` syscall with the passed arguments.
pub fn ctl(epfd: RawFd,
           op: ControlOptions,
           fd: RawFd,
           event: *mut libc::epoll_event)
           -> io::Result<()>
{
    unsafe { try!(cvt(libc::epoll_ctl(epfd, op.bits, fd, event))) };
    Ok(())
}

/// Calls the `epoll_wait` syscall with the passed arguments.
///
/// ## Notes
///
/// * If `timeout` is negative, it will block until an event is received.
/// * `max_returned` must be greater than zero.
pub fn wait(epfd: RawFd,
            timeout: i32,
            max_events: usize)
            -> io::Result<Vec<libc::epoll_event>>
{
    let timeout = if timeout < -1 { -1 } else { timeout };
    let mut buf = Vec::<libc::epoll_event>::with_capacity(max_events);

    unsafe {
        let num_events = try!(cvt(libc::epoll_wait(epfd,
                                                   buf.as_mut_ptr(),
                                                   max_events as i32,
                                                   timeout))) as usize;
        buf.set_len(num_events);
    };

    Ok(buf)
}

fn cvt(result: libc::c_int) -> io::Result<libc::c_int> {
    if result < 0 {
        Err(Error::last_os_error())
    } else {
        Ok(result)
    }
}
<commit_msg>Moved allocation to wait fn buffer to caller.<commit_after>// Copyright 2015 Nathan Sizemore <nathanrsizemore@gmail.com>
//
// This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
// If a copy of the MPL was not distributed with this file,
// You can obtain one at http://mozilla.org/MPL/2.0/.

extern crate libc;
extern crate simple_slab;
#[macro_use] extern crate bitflags;

use std::ops::Drop;
use std::sync::Mutex;
use std::io::{self, Error};
use std::os::unix::io::{RawFd, AsRawFd};
use std::time::{Duration, Instant};

use simple_slab::Slab;
pub use interest::Interest;

mod interest;

bitflags! {
    pub flags ControlOptions: i32 {
        /// Indicates an addition to the interest list.
        const EPOLL_CTL_ADD = libc::EPOLL_CTL_ADD,
        /// Indicates a modification of flags for an interest already in list.
        const EPOLL_CTL_MOD = libc::EPOLL_CTL_MOD,
        /// Indicates a removal of an interest from the list.
        const EPOLL_CTL_DEL = libc::EPOLL_CTL_DEL
    }
}

bitflags! {
    pub flags Events: u32 {
        /// Sets the Edge Triggered behavior for the associated file descriptor.
        ///
        /// The default behavior for epoll is Level Triggered.
        const EPOLLET      = libc::EPOLLET as u32,
        /// The associated file is available for read operations.
        const EPOLLIN      = libc::EPOLLIN as u32,
        /// Error condition happened on the associated file descriptor.
        ///
        /// `wait` will always wait for this event; is not necessary to set it in events.
        const EPOLLERR     = libc::EPOLLERR as u32,
        /// Hang up happened on the associated file descriptor.
        ///
        /// `wait` will always wait for this event; it is not necessary to set it in events.
        /// Note that when reading from a channel such as a pipe or a stream socket, this event
        /// merely indicates that the peer closed its end of the channel. Subsequent reads from
        /// the channel will return 0 (end of file) only after all outstanding data in the
        /// channel has been consumed.
        const EPOLLHUP     = libc::EPOLLHUP as u32,
        /// The associated file is available for write operations.
        const EPOLLOUT     = libc::EPOLLOUT as u32,
        /// There is urgent data available for read operations.
        const EPOLLPRI     = libc::EPOLLPRI as u32,
        /// Stream socket peer closed connection, or shut down writing half of connection.
        ///
        /// This flag is especially useful for writing simple code to detect peer shutdown when
        /// using Edge Triggered monitoring.
        const EPOLLRDHUP   = libc::EPOLLRDHUP as u32,
        /// If `EPOLLONESHOT` and `EPOLLET` are clear and the process has the `CAP_BLOCK_SUSPEND`
        /// capability, ensure that the system does not enter "suspend" or "hibernate" while this
        /// event is pending or being processed.
        ///
        /// The event is considered as being "processed" from the time when it is returned by
        /// a call to `wait` until the next call to `wait` on the same `EpollInstance`
        /// descriptor, the closure of that file descriptor, the removal of the event file
        /// descriptor with `EPOLL_CTL_DEL`, or the clearing of `EPOLLWAKEUP` for the event file
        /// descriptor with `EPOLL_CTL_MOD`.
        const EPOLLWAKEUP  = libc::EPOLLWAKEUP as u32,
        /// Sets the one-shot behavior for the associated file descriptor.
        ///
        /// This means that after an event is pulled out with `wait` the associated file
        /// descriptor is internally disabled and no other events will be reported by the epoll
        /// interface.  The user must call `ctl` with `EPOLL_CTL_MOD` to rearm the file
        /// descriptor with a new event mask.
        const EPOLLONESHOT = libc::EPOLLONESHOT as u32
    }
}

/// Thread safe abstraction, plus timers, around an epoll RawFd.
pub struct EpollInstance {
    fd: libc::c_int,
    interest_mutex: Mutex<Slab<Interest>>,
    events: u64,
    wait: Duration
}

impl EpollInstance {

    /// Creates a new `EpollInstance`.
    ///
    /// ## Notes
    /// * `FD_CLOEXEC` flag is set on the underlying fd returned.
    pub fn new() -> io::Result<EpollInstance> {
        Ok(EpollInstance {
            fd: try!(create(true)),
            interest_mutex: Mutex::new(Slab::<Interest>::new()),
            events: 0,
            wait: Duration::new(0, 0)
        })
    }

    /// Register an initial `Interest` with this instance.
    ///
    /// ## Panics
    ///
    /// Panics if the interior Mutex has been poisoned.
    pub fn add_interest(&mut self, interest: Interest) -> io::Result<()> {
        let mut event_mask = interest::int2event(&interest);

        try!(ctl(self.fd,
                 EPOLL_CTL_ADD,
                 interest.as_raw_fd(),
                 &mut event_mask as *mut libc::epoll_event));

        let mut list = self.interest_mutex.lock().unwrap();
        (*list).insert(interest);

        Ok(())
    }

    /// Modify the original `Interest`, identified by its `RawFd`, to the passed
    /// interest's events and data fields.
    ///
    /// ## Panics
    ///
    /// Panics if the interior Mutex has been poisoned.
    pub fn mod_interest(&mut self, interest: &Interest) -> io::Result<()> {
        let mut event_mask = interest::int2event(interest);

        try!(ctl(self.fd,
                 EPOLL_CTL_MOD,
                 interest.as_raw_fd(),
                 &mut event_mask as *mut libc::epoll_event));

        let mut list = self.interest_mutex.lock().unwrap();
        for ref mut _interest in (*list).iter_mut() {
            if _interest.as_raw_fd() == interest.as_raw_fd() {
                _interest.set_events(interest.events());
                _interest.set_data(interest.data());
                break;
            }
        }

        Ok(())
    }

    /// Remove the passed `Interest`, identified by its `RawFd`, from this instance.
    ///
    /// ## Panics
    ///
    /// Panics if the interior Mutex has been poisoned.
    pub fn del_interest(&mut self, interest: &Interest) -> io::Result<()> {
        // In kernel versions before 2.6.9, the EPOLL_CTL_DEL operation required a non-null
        // pointer in event, even though this argument is ignored.
        let mut event_mask = libc::epoll_event {
            events: 0u32,
            u64: 0u64
        };

        try!(ctl(self.fd,
                 EPOLL_CTL_DEL,
                 interest.as_raw_fd(),
                 &mut event_mask as *mut libc::epoll_event));

        let mut offset: usize = 0;
        let mut list = self.interest_mutex.lock().unwrap();
        for ref mut _interest in (*list).iter() {
            if _interest.as_raw_fd() == interest.as_raw_fd() {
                break;
            }
            offset += 1
        }
        (*list).remove(offset);

        Ok(())
    }

    /// Waits for events on this instance for at most `timeout` milliseconds and returns at most
    /// `max_returned` `Interests`.
    ///
    /// ## Notes
    ///
    /// * If `timeout` is negative, it will block until an event is received.
    /// * `max_returned` must be greater than zero.
    ///
    /// ## Panics
    ///
    /// Panics if the interior Mutex has been poisoned.
    pub fn wait(&mut self, timeout: i32, max_returned: usize) -> io::Result<Vec<Interest>> {
        let mut buf = Vec::<libc::epoll_event>::with_capacity(max_returned);
        unsafe { buf.set_len(max_returned); }

        let start = Instant::now();
        let num_events = try!(wait(self.fd, timeout, &mut buf));
        unsafe { buf.set_len(num_events) }

        self.events += buf.len() as u64;
        self.wait += start.elapsed();

        let mut ret_buf = Vec::<Interest>::with_capacity(buf.len());
        let mut list = self.interest_mutex.lock().unwrap();
        for ref event in buf.iter() {
            for ref mut interest in (*list).iter_mut() {
                if interest.data() == event.u64 {
                    (*interest.events_mut()) = Events::from_bits(event.events).unwrap();
                    ret_buf.push(interest.clone());
                    break;
                }
            }
        }

        Ok(ret_buf)
    }

    /// Returns the total number of events reported.
    pub fn events(&self) -> u64 {
        self.events
    }

    /// Returns the total time spent in a blocked, waiting state.
    pub fn wait_time(&self) -> Duration {
        self.wait
    }
}

impl AsRawFd for EpollInstance {
    fn as_raw_fd(&self) -> RawFd { self.fd }
}

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

unsafe impl Send for EpollInstance {}
unsafe impl Sync for EpollInstance {}

/// Creates a new epoll file descriptor.
///
/// If `cloexec` is true, `FD_CLOEXEC` will be set on the returned file descriptor.
///
/// ## Notes
///
/// * `epoll_create(1)` is the underlying syscall.
pub fn create(cloexec: bool) -> io::Result<RawFd> {
    let epfd = unsafe {
        let fd = try!(cvt(libc::epoll_create(1)));

        if cloexec {
            let mut flags = try!(cvt(libc::fcntl(fd, libc::F_GETFD)));
            flags |= libc::FD_CLOEXEC;
            try!(cvt(libc::fcntl(fd, libc::F_SETFD, flags)));
        }
        fd
    };

    Ok(epfd)
}

/// Calls the `epoll_ctl` syscall with the passed arguments.
pub fn ctl(epfd: RawFd,
           op: ControlOptions,
           fd: RawFd,
           event: *mut libc::epoll_event)
           -> io::Result<()>
{
    unsafe { try!(cvt(libc::epoll_ctl(epfd, op.bits, fd, event))) };
    Ok(())
}

/// Calls the `epoll_wait` syscall with the passed arguments.
///
/// ## Notes
///
/// * If `timeout` is negative, it will block until an event is received.
pub fn wait(epfd: RawFd,
            timeout: i32,
            buf: &mut [libc::epoll_event])
            -> io::Result<usize>
{
    let timeout = if timeout < -1 { -1 } else { timeout };
    let num_events = unsafe {
        try!(cvt(libc::epoll_wait(epfd,
                                  buf.as_mut_ptr(),
                                  buf.len() as i32,
                                  timeout))) as usize
    };

    Ok(num_events)
}

fn cvt(result: libc::c_int) -> io::Result<libc::c_int> {
    if result < 0 {
        Err(Error::last_os_error())
    } else {
        Ok(result)
    }
}
<|endoftext|>


<commit_before>#![deny(missing_docs,
        missing_debug_implementations, missing_copy_implementations,
        trivial_casts, trivial_numeric_casts,
        unsafe_code,
        unstable_features,
        unused_import_braces, unused_qualifications)]
//! documentation for pokemon
//! Yep.
extern crate rustc_serialize;
extern crate csv;
extern crate rand;

pub mod pokemon {
    //! documentation for pokemon
    //! Yep.
    use std::fs::File;
    use std::path::Path;
    use rand::{thread_rng, Rng};
    use csv;

    /// The struct for `Pokemon`
    ///
    /// # Example
    /// ```
    /// Pokemon {
    ///    species: 1,
    ///    language: 3,
    ///    name: "Bulbasaur".to_string(),
    ///    genus: Some("seed".to_string())
    /// ```
    #[derive(RustcDecodable, RustcEncodable, Clone, Debug)]
    pub struct Pokemon {
        species: i32,
        language: i32,
        name: String,
        genus: Option<String>,
    }

    fn search<P: AsRef<Path>>(file_path: P) -> Vec<Pokemon> {
        let file = File::open(file_path).unwrap();
        let mut rdr = csv::Reader::from_reader(file).has_headers(true);
        let rows:Vec<Pokemon> = rdr.decode().collect::<csv::Result<Vec<Pokemon>>>().unwrap();
        rows
    }

    fn search_one<P: AsRef<Path>>(file_path: P, index: usize, lang_id: i32) -> Pokemon {
        let file = File::open(file_path).unwrap();
        let mut rdr = csv::Reader::from_reader(file).has_headers(true);

        let rows:Vec<Pokemon> = rdr.decode().collect::<csv::Result<Vec<Pokemon>>>().unwrap();

        let mut pokey:Pokemon = Pokemon {
            species: 1,
            language: 1,
            name: "Bulbasaur".to_string(),
            genus: Some("seed".to_string()),
        };

        for poke in &rows {
            if poke.species == index as i32 && poke.language == lang_id {
                //println!("{:?}", poke);
                pokey = poke.clone();
            }
        }

        pokey

    }

    /// Returns all the Pokemon, in each language
    #[allow(dead_code)]
    pub fn get_all() -> Vec<Pokemon> {
        search("data/pokemon.csv")
    }

    /// Returns a single Pokemon based on specified id and language
    /// MB: English is 9
    #[allow(dead_code)]
    pub fn get_pokemon(id: usize, lang_id: i32) -> Pokemon {
        search_one("data/pokemon.csv", id, lang_id)
    }

    /// Returns a random Pokemon in English
    #[allow(dead_code)]
    pub fn get_random() -> Pokemon {
        let mut rng = thread_rng();
        search_one("data/pokemon.csv", rng.gen_range::<usize>(1, 802), 9)
    }

    /// Returns a random pokemon with the specified language
    #[allow(dead_code)]
    pub fn get_random_with_lang(lang_id: i32) -> Pokemon {
        let mut rng = thread_rng();
        search_one("data/pokemon.csv", rng.gen_range::<usize>(1, 802), lang_id)
    }

    /// Returns the name of the specified id
    /// # Example
    /// ```
    /// get_name(9)
    /// ```
    /// The above would return "Blastoise"
    #[allow(dead_code, unused_variables)]
    pub fn get_name(id: usize) -> String {
        search_one("data/pokemon.csv", id, 9).name
    }

    /// Same as get_name(), but allows you to specify the language
    #[allow(dead_code)]
    pub fn get_name_with_lang(id: usize, lang_id: i32) -> String {
        search_one("data/pokemon.csv", id, lang_id).name
    }

}
<commit_msg>remove documentation code that was preventing passing builds<commit_after>#![deny(missing_docs,
        missing_debug_implementations, missing_copy_implementations,
        trivial_casts, trivial_numeric_casts,
        unsafe_code,
        unstable_features,
        unused_import_braces, unused_qualifications)]
//! documentation for pokemon
//! Yep.
extern crate rustc_serialize;
extern crate csv;
extern crate rand;

pub mod pokemon {
    //! documentation for pokemon
    //! Yep.
    use std::fs::File;
    use std::path::Path;
    use rand::{thread_rng, Rng};
    use csv;

    /// The struct for `Pokemon`
    #[derive(RustcDecodable, RustcEncodable, Clone, Debug)]
    pub struct Pokemon {
        species: i32,
        language: i32,
        name: String,
        genus: Option<String>,
    }

    fn search<P: AsRef<Path>>(file_path: P) -> Vec<Pokemon> {
        let file = File::open(file_path).unwrap();
        let mut rdr = csv::Reader::from_reader(file).has_headers(true);
        let rows:Vec<Pokemon> = rdr.decode().collect::<csv::Result<Vec<Pokemon>>>().unwrap();
        rows
    }

    fn search_one<P: AsRef<Path>>(file_path: P, index: usize, lang_id: i32) -> Pokemon {
        let file = File::open(file_path).unwrap();
        let mut rdr = csv::Reader::from_reader(file).has_headers(true);

        let rows:Vec<Pokemon> = rdr.decode().collect::<csv::Result<Vec<Pokemon>>>().unwrap();

        let mut pokey:Pokemon = Pokemon {
            species: 1,
            language: 1,
            name: "Bulbasaur".to_string(),
            genus: Some("seed".to_string()),
        };

        for poke in &rows {
            if poke.species == index as i32 && poke.language == lang_id {
                //println!("{:?}", poke);
                pokey = poke.clone();
            }
        }

        pokey

    }

    /// Returns all the Pokemon, in each language
    #[allow(dead_code)]
    pub fn get_all() -> Vec<Pokemon> {
        search("data/pokemon.csv")
    }

    /// Returns a single Pokemon based on specified id and language
    /// MB: English is 9
    #[allow(dead_code)]
    pub fn get_pokemon(id: usize, lang_id: i32) -> Pokemon {
        search_one("data/pokemon.csv", id, lang_id)
    }

    /// Returns a random Pokemon in English
    #[allow(dead_code)]
    pub fn get_random() -> Pokemon {
        let mut rng = thread_rng();
        search_one("data/pokemon.csv", rng.gen_range::<usize>(1, 802), 9)
    }

    /// Returns a random pokemon with the specified language
    #[allow(dead_code)]
    pub fn get_random_with_lang(lang_id: i32) -> Pokemon {
        let mut rng = thread_rng();
        search_one("data/pokemon.csv", rng.gen_range::<usize>(1, 802), lang_id)
    }

    /// Returns the name of the specified id
    /// Using 9 for example, would return "Blastoise"
    #[allow(dead_code, unused_variables)]
    pub fn get_name(id: usize) -> String {
        search_one("data/pokemon.csv", id, 9).name
    }

    /// Same as get_name(), but allows you to specify the language
    #[allow(dead_code)]
    pub fn get_name_with_lang(id: usize, lang_id: i32) -> String {
        search_one("data/pokemon.csv", id, lang_id).name
    }

}
<|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::new()`.

The `new()` 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::ServerBuilder::new().build().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::ServerBuilder::new().build().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::ServerBuilder::new().build().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.get_method()` and `request.get_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::ServerBuilder::new().build().unwrap();
# let request = server.recv().unwrap();
# let response = tiny_http::Response::from_file(File::open(&Path::new("image.png")).unwrap());
request.respond(response)
```
*/
#![feature(std_misc)]
#![crate_name = "tiny_http"]
#![crate_type = "lib"]

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

use std::sync::mpsc::{Sender, Receiver};
use std::io::Result as IoResult;
use std::sync::mpsc::Select;
use std::sync::mpsc::channel;
use std::sync::{Arc, Mutex};
use std::sync::atomic::AtomicBool;
use std::thread;
use std::net;
use client::ClientConnection;

pub use common::{Header, HeaderField, HTTPVersion, Method, StatusCode};
pub use request::Request;
pub use response::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 {
    // tasks where the client connections are dispatched
    tasks_pool: util::TaskPool,

    // receiver for client connections
    connections_receiver: Mutex<Receiver<IoResult<ClientConnection>>>,

    // 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>,

    // the sender linked to requests_receiver
    // cloned each time a client connection is created
    requests_sender: Mutex<Sender<Request>>,

    // channel to receive requests from
    requests_receiver: Mutex<Receiver<Request>>,

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

// 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
}

/// Object which allows you to build a server.
pub struct ServerBuilder {
    // the address to listen to
    address: net::SocketAddrV4,

    // number of milliseconds before client timeout
    client_timeout_ms: u32,

    // maximum number of clients before 503
    // TODO:
    //max_clients: usize,
}

impl ServerBuilder {
    /// Creates a new builder.
    pub fn new() -> ServerBuilder {
        ServerBuilder {
            address: net::SocketAddrV4::new(net::Ipv4Addr::new(0, 0, 0, 0), 80),
            client_timeout_ms: 60 * 1000,
            //max_clients: { use std::num::Bounded; Bounded::max_value() },
        }
    }

    /// The server will use a precise port.
    pub fn with_port(mut self, port: u16) -> ServerBuilder {
        let addr = self.address.ip().clone();
        self.address = net::SocketAddrV4::new(addr, port);
        self
    }

    /// The server will use a random port.
    ///
    /// Call `server.get_server_addr()` to retreive it once the server is created.
    pub fn with_random_port(mut self) -> ServerBuilder {
        let addr = self.address.ip().clone();
        self.address = net::SocketAddrV4::new(addr, 0);
        self
    }

    /// The server will use a precise port.
    pub fn with_client_connections_timeout(mut self, milliseconds: u32) -> ServerBuilder {
        self.client_timeout_ms = milliseconds;
        self
    }

    /// Builds the server with the given configuration.
    pub fn build(self) -> IoResult<Server> {
        Server::new(self)
    }
}

impl Server {
    /// Builds a new server that listens on the specified address.
    fn new(config: ServerBuilder) -> IoResult<Server> {
        // 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(net::SocketAddr::V4(config.address)));
            let local_addr = try!(listener.local_addr());
            (listener, local_addr)
        };

        // creating a task where server.accept() is continuously called
        // and ClientConnection objects are returned in the receiver
        let (tx_incoming, rx_incoming) = channel();

        let inside_close_trigger = close_trigger.clone();
        thread::spawn(move || {
            loop {
                let new_client = server.accept().map(|(sock, _)| {
                    use util::ClosableTcpStream;

                    let read_closable = ClosableTcpStream::new(sock.try_clone().unwrap(), true, false);
                    let write_closable = ClosableTcpStream::new(sock, false, true);

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

                if tx_incoming.send(new_client).is_err() {
                    break;
                }
            }
        });

        //
        let (tx_requests, rx_requests) = channel();

        // result
        Ok(Server {
            tasks_pool: util::TaskPool::new(),
            connections_receiver: Mutex::new(rx_incoming),
            close: close_trigger,
            requests_sender: Mutex::new(tx_requests),
            requests_receiver: Mutex::new(rx_requests),
            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 get_server_addr(&self) -> net::SocketAddr {
        self.listening_addr.clone()
    }

    /// Returns the number of clients currently connected to the server.
    pub fn get_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> {
        let connections_receiver = self.connections_receiver.lock().unwrap();
        let requests_receiver = self.requests_receiver.lock().unwrap();

        // TODO: the select! macro doesn't seem to be usable without moving
        //       out of self, so we use Select directly

        let select = Select::new();

        let mut request_handle = select.handle(&*requests_receiver);
        unsafe { request_handle.add() };

        let mut connect_handle = select.handle(&*connections_receiver);
        unsafe { connect_handle.add() };

        loop {
            let id = select.wait();

            if id == request_handle.id() {
                let request = request_handle.recv().unwrap();

                unsafe { request_handle.remove() };
                unsafe { connect_handle.remove() };

                return Ok(request);
            }

            if id == connect_handle.id() {
                let client = connect_handle.recv();

                match client {
                    Ok(Ok(client)) => {
                        self.add_client(client);
                        continue
                    },
                    Ok(Err(err)) => {
                        unsafe { request_handle.remove() };
                        unsafe { connect_handle.remove() };

                        return Err(err)
                    },
                    Err(_) => {
                        unsafe { request_handle.remove() };
                        unsafe { connect_handle.remove() };

                        panic!() // FIXME: return Err(old_io::standard_error(old_io::Closed));
                    }
                }
            }

            unreachable!()
        }
    }

    /// Same as `recv()` but doesn't block.
    pub fn try_recv(&self) -> IoResult<Option<Request>> {
        let connections_receiver = self.connections_receiver.lock().unwrap();
        let requests_receiver = self.requests_receiver.lock().unwrap();

        // processing all new clients
        loop {
            match connections_receiver.try_recv() {
                Ok(client) => self.add_client(try!(client)),
                Err(_) => break
            }
        }

        // reading the next request
        Ok(requests_receiver.try_recv().ok())
    }

    /// Adds a new client to the list.
    fn add_client(&self, client: ClientConnection) {
        let requests_sender = self.requests_sender.lock().unwrap().clone();

        let mut client = Some(client);

        self.tasks_pool.spawn(Box::new(move || {
            if let Some(client) = client.take() {
                for rq in client {
                    if let Err(_) = requests_sender.send(rq) {
                        break;
                    }
                }
            }
        }));
    }
}

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>Remove the usage of Select<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::new()`.

The `new()` 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::ServerBuilder::new().build().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::ServerBuilder::new().build().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::ServerBuilder::new().build().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.get_method()` and `request.get_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::ServerBuilder::new().build().unwrap();
# let request = server.recv().unwrap();
# let response = tiny_http::Response::from_file(File::open(&Path::new("image.png")).unwrap());
request.respond(response)
```
*/
#![feature(std_misc)]
#![crate_name = "tiny_http"]
#![crate_type = "lib"]

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

use std::sync::mpsc::{Sender, Receiver};
use std::io::Error as IoError;
use std::io::Result as IoResult;
use std::io::ErrorKind;
use std::sync::mpsc::{channel, TryRecvError};
use std::sync::{Arc, Mutex};
use std::sync::atomic::AtomicBool;
use std::thread;
use std::net;
use client::ClientConnection;

pub use common::{Header, HeaderField, HTTPVersion, Method, StatusCode};
pub use request::Request;
pub use response::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 {
    // tasks where the client connections are dispatched
    tasks_pool: util::TaskPool,

    // receiver for client connections
    connections_receiver: Mutex<Receiver<IoResult<ClientConnection>>>,

    // 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>,

    // the sender linked to requests_receiver
    // cloned each time a client connection is created
    requests_sender: Mutex<Sender<Request>>,

    // channel to receive requests from
    requests_receiver: Mutex<Receiver<Request>>,

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

// 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
}

/// Object which allows you to build a server.
pub struct ServerBuilder {
    // the address to listen to
    address: net::SocketAddrV4,

    // number of milliseconds before client timeout
    client_timeout_ms: u32,

    // maximum number of clients before 503
    // TODO:
    //max_clients: usize,
}

impl ServerBuilder {
    /// Creates a new builder.
    pub fn new() -> ServerBuilder {
        ServerBuilder {
            address: net::SocketAddrV4::new(net::Ipv4Addr::new(0, 0, 0, 0), 80),
            client_timeout_ms: 60 * 1000,
            //max_clients: { use std::num::Bounded; Bounded::max_value() },
        }
    }

    /// The server will use a precise port.
    pub fn with_port(mut self, port: u16) -> ServerBuilder {
        let addr = self.address.ip().clone();
        self.address = net::SocketAddrV4::new(addr, port);
        self
    }

    /// The server will use a random port.
    ///
    /// Call `server.get_server_addr()` to retreive it once the server is created.
    pub fn with_random_port(mut self) -> ServerBuilder {
        let addr = self.address.ip().clone();
        self.address = net::SocketAddrV4::new(addr, 0);
        self
    }

    /// The server will use a precise port.
    pub fn with_client_connections_timeout(mut self, milliseconds: u32) -> ServerBuilder {
        self.client_timeout_ms = milliseconds;
        self
    }

    /// Builds the server with the given configuration.
    pub fn build(self) -> IoResult<Server> {
        Server::new(self)
    }
}

impl Server {
    /// Builds a new server that listens on the specified address.
    fn new(config: ServerBuilder) -> IoResult<Server> {
        // 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(net::SocketAddr::V4(config.address)));
            let local_addr = try!(listener.local_addr());
            (listener, local_addr)
        };

        // creating a task where server.accept() is continuously called
        // and ClientConnection objects are returned in the receiver
        let (tx_incoming, rx_incoming) = channel();

        let inside_close_trigger = close_trigger.clone();
        thread::spawn(move || {
            loop {
                let new_client = server.accept().map(|(sock, _)| {
                    use util::ClosableTcpStream;

                    let read_closable = ClosableTcpStream::new(sock.try_clone().unwrap(), true, false);
                    let write_closable = ClosableTcpStream::new(sock, false, true);

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

                if tx_incoming.send(new_client).is_err() {
                    break;
                }
            }
        });

        //
        let (tx_requests, rx_requests) = channel();

        // result
        Ok(Server {
            tasks_pool: util::TaskPool::new(),
            connections_receiver: Mutex::new(rx_incoming),
            close: close_trigger,
            requests_sender: Mutex::new(tx_requests),
            requests_receiver: Mutex::new(rx_requests),
            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 get_server_addr(&self) -> net::SocketAddr {
        self.listening_addr.clone()
    }

    /// Returns the number of clients currently connected to the server.
    pub fn get_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> {
        let connections_receiver = self.connections_receiver.lock().unwrap();
        let requests_receiver = self.requests_receiver.lock().unwrap();

        loop {
            loop {
                match connections_receiver.try_recv() {
                    Ok(Ok(client)) => self.add_client(client),
                    Ok(Err(err)) => return Err(err),
                    Err(TryRecvError::Empty) => break,
                    Err(TryRecvError::Disconnected) => {
                        return Err(IoError::new(ErrorKind::ConnectionAborted,
                                                "Server socket has closed unexpectedly"));
                    },
                }
            }

            match requests_receiver.try_recv() {
                Ok(request) => return Ok(request),
                Err(TryRecvError::Empty) => (),

                // we keep a `Sender` alive inside the `Server`, so it's not possible to be
                // disconnected here
                Err(TryRecvError::Disconnected) => unreachable!(),
            }

            thread::sleep_ms(2);
        }
    }

    /// Same as `recv()` but doesn't block.
    pub fn try_recv(&self) -> IoResult<Option<Request>> {
        let connections_receiver = self.connections_receiver.lock().unwrap();
        let requests_receiver = self.requests_receiver.lock().unwrap();

        // processing all new clients
        loop {
            match connections_receiver.try_recv() {
                Ok(client) => self.add_client(try!(client)),
                Err(_) => break
            }
        }

        // reading the next request
        Ok(requests_receiver.try_recv().ok())
    }

    /// Adds a new client to the list.
    fn add_client(&self, client: ClientConnection) {
        let requests_sender = self.requests_sender.lock().unwrap().clone();

        let mut client = Some(client);

        self.tasks_pool.spawn(Box::new(move || {
            if let Some(client) = client.take() {
                for rq in client {
                    if let Err(_) = requests_sender.send(rq) {
                        break;
                    }
                }
            }
        }));
    }
}

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>// The following was originally taken and adapated from exa source
// repo: https://github.com/ogham/exa
// commit: b9eb364823d0d4f9085eb220233c704a13d0f611
// license: MIT - Copyright (c) 2014 Benjamin Sago

//! System calls for getting the terminal size.
//!
//! Getting the terminal size is performed using an ioctl command that takes
//! the file handle to the terminal -- which in this case, is stdout -- and
//! populates a structure containing the values.
//!
//! The size is needed when the user wants the output formatted into columns:
//! the default grid view, or the hybrid grid-details view.

#[cfg(not(target_os = "windows"))]
extern crate libc;
#[cfg(target_os = "windows")]
extern crate kernel32;
#[cfg(target_os = "windows")]
extern crate winapi;

#[cfg(target_os = "windows")]
use kernel32::{GetConsoleScreenBufferInfo, GetStdHandle};
#[cfg(target_os = "windows")]
use winapi::{CONSOLE_SCREEN_BUFFER_INFO, COORD, SMALL_RECT, STD_OUTPUT_HANDLE};

#[cfg(not(target_os = "windows"))]
use std::mem::zeroed;
#[cfg(not(target_os = "windows"))]
use libc::{STDOUT_FILENO, c_int, c_ulong, winsize};

// Unfortunately the actual command is not standardised...
#[cfg(any(target_os = "linux", target_os = "android"))]
static TIOCGWINSZ: c_ulong = 0x5413;

#[cfg(any(target_os = "macos",
          target_os = "ios",
          target_os = "bitrig",
          target_os = "dragonfly",
          target_os = "freebsd",
          target_os = "netbsd",
          target_os = "openbsd"))]
static TIOCGWINSZ: c_ulong = 0x40087468;

#[cfg(target_os = "solaris")]
static TIOCGWINSZ: c_ulong = 0x5468;

extern "C" {
#[cfg(not(target_os = "windows"))]
    pub fn ioctl(fd: c_int, request: c_ulong, ...) -> c_int;
}

/// Runs the ioctl command. Returns (0, 0) if output is not to a terminal, or
/// there is an error. (0, 0) is an invalid size to have anyway, which is why
/// it can be used as a nil value.
#[cfg(not(target_os = "windows"))]
unsafe fn get_dimensions() -> winsize {
    let mut window: winsize = zeroed();
    let result = ioctl(STDOUT_FILENO, TIOCGWINSZ, &mut window);

    if result == -1 {
        zeroed()
    } else {
        window
    }
}

/// Query the current processes's output, returning its width and height as a
/// number of characters. Returns `None` if the output isn't to a terminal.
#[cfg(not(target_os = "windows"))]
pub fn dimensions() -> Option<(usize, usize)> {
    let w = unsafe { get_dimensions() };

    if w.ws_col == 0 || w.ws_row == 0 {
        None
    } else {
        Some((w.ws_col as usize, w.ws_row as usize))
    }
}

#[cfg(target_os = "windows")]
pub fn dimensions() -> Option<(usize, usize)> {
        let null_coord = COORD{
            X: 0,
            Y: 0,
        };
        let null_smallrect = SMALL_RECT{
            Left: 0,
            Top: 0,
            Right: 0,
            Bottom: 0,
        };

        let stdout_h = unsafe { GetStdHandle(STD_OUTPUT_HANDLE) };
        let mut console_data = CONSOLE_SCREEN_BUFFER_INFO{
            dwSize: null_coord,
            dwCursorPosition: null_coord,
            wAttributes: 0,
            srWindow: null_smallrect,
            dwMaximumWindowSize: null_coord,
        };

        if unsafe { GetConsoleScreenBufferInfo(stdout_h, &mut console_data) } != 0 {
            Some(((console_data.srWindow.Right - console_data.srWindow.Left) as usize, (console_data.srWindow.Bottom - console_data.srWindow.Top) as usize))
        } else {
            None
        }
}
<commit_msg>Don't expose ioctl()<commit_after>// The following was originally taken and adapated from exa source
// repo: https://github.com/ogham/exa
// commit: b9eb364823d0d4f9085eb220233c704a13d0f611
// license: MIT - Copyright (c) 2014 Benjamin Sago

//! System calls for getting the terminal size.
//!
//! Getting the terminal size is performed using an ioctl command that takes
//! the file handle to the terminal -- which in this case, is stdout -- and
//! populates a structure containing the values.
//!
//! The size is needed when the user wants the output formatted into columns:
//! the default grid view, or the hybrid grid-details view.

#[cfg(not(target_os = "windows"))]
extern crate libc;
#[cfg(target_os = "windows")]
extern crate kernel32;
#[cfg(target_os = "windows")]
extern crate winapi;

#[cfg(target_os = "windows")]
use kernel32::{GetConsoleScreenBufferInfo, GetStdHandle};
#[cfg(target_os = "windows")]
use winapi::{CONSOLE_SCREEN_BUFFER_INFO, COORD, SMALL_RECT, STD_OUTPUT_HANDLE};

#[cfg(not(target_os = "windows"))]
use std::mem::zeroed;
#[cfg(not(target_os = "windows"))]
use libc::{STDOUT_FILENO, c_int, c_ulong, winsize};

// Unfortunately the actual command is not standardised...
#[cfg(any(target_os = "linux", target_os = "android"))]
static TIOCGWINSZ: c_ulong = 0x5413;

#[cfg(any(target_os = "macos",
          target_os = "ios",
          target_os = "bitrig",
          target_os = "dragonfly",
          target_os = "freebsd",
          target_os = "netbsd",
          target_os = "openbsd"))]
static TIOCGWINSZ: c_ulong = 0x40087468;

#[cfg(target_os = "solaris")]
static TIOCGWINSZ: c_ulong = 0x5468;

extern "C" {
#[cfg(not(target_os = "windows"))]
    fn ioctl(fd: c_int, request: c_ulong, ...) -> c_int;
}

/// Runs the ioctl command. Returns (0, 0) if output is not to a terminal, or
/// there is an error. (0, 0) is an invalid size to have anyway, which is why
/// it can be used as a nil value.
#[cfg(not(target_os = "windows"))]
unsafe fn get_dimensions() -> winsize {
    let mut window: winsize = zeroed();
    let result = ioctl(STDOUT_FILENO, TIOCGWINSZ, &mut window);

    if result == -1 {
        zeroed()
    } else {
        window
    }
}

/// Query the current processes's output, returning its width and height as a
/// number of characters. Returns `None` if the output isn't to a terminal.
#[cfg(not(target_os = "windows"))]
pub fn dimensions() -> Option<(usize, usize)> {
    let w = unsafe { get_dimensions() };

    if w.ws_col == 0 || w.ws_row == 0 {
        None
    } else {
        Some((w.ws_col as usize, w.ws_row as usize))
    }
}

#[cfg(target_os = "windows")]
pub fn dimensions() -> Option<(usize, usize)> {
        let null_coord = COORD{
            X: 0,
            Y: 0,
        };
        let null_smallrect = SMALL_RECT{
            Left: 0,
            Top: 0,
            Right: 0,
            Bottom: 0,
        };

        let stdout_h = unsafe { GetStdHandle(STD_OUTPUT_HANDLE) };
        let mut console_data = CONSOLE_SCREEN_BUFFER_INFO{
            dwSize: null_coord,
            dwCursorPosition: null_coord,
            wAttributes: 0,
            srWindow: null_smallrect,
            dwMaximumWindowSize: null_coord,
        };

        if unsafe { GetConsoleScreenBufferInfo(stdout_h, &mut console_data) } != 0 {
            Some(((console_data.srWindow.Right - console_data.srWindow.Left) as usize, (console_data.srWindow.Bottom - console_data.srWindow.Top) as usize))
        } else {
            None
        }
}
<|endoftext|>


<commit_before>#![crate_type = "lib"]
#![feature(proc_macro)]
#![feature(plugin)]
#![feature(asm)]
#![plugin(bifrost_plugins)]
#![feature(conservative_impl_trait)]
#![feature(exact_size_is_empty)]

#[macro_use]
extern crate log;
#[macro_use]
extern crate lazy_static;
#[macro_use]
extern crate bifrost;
extern crate bifrost_hasher;
#[macro_use]
extern crate dovahkiin;
#[macro_use]
extern crate serde_derive;

extern crate bincode;
extern crate serde;
extern crate parking_lot;
extern crate core;
extern crate rand;
extern crate futures;
extern crate linked_hash_map;
extern crate libc;
extern crate chashmap;

pub mod utils;
#[macro_use]
pub mod ram;
pub mod server;
pub mod client;<commit_msg>expose inner dovahkiin lib<commit_after>#![crate_type = "lib"]
#![feature(proc_macro)]
#![feature(plugin)]
#![feature(asm)]
#![plugin(bifrost_plugins)]
#![feature(conservative_impl_trait)]
#![feature(exact_size_is_empty)]

#[macro_use]
extern crate log;
#[macro_use]
extern crate lazy_static;
#[macro_use]
extern crate bifrost;
extern crate bifrost_hasher;
#[macro_use]
extern crate dovahkiin;
#[macro_use]
extern crate serde_derive;

extern crate bincode;
extern crate serde;
extern crate parking_lot;
extern crate core;
extern crate rand;
extern crate futures;
extern crate linked_hash_map;
extern crate libc;
extern crate chashmap;

pub use dovahkiin;

pub mod utils;
#[macro_use]
pub mod ram;
pub mod server;
pub mod client;<|endoftext|>


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

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

extern crate time;
extern crate conduit;
extern crate middleware = "conduit-middleware";

use std::fmt::Show;

use conduit::{Request, Response};
use middleware::Middleware;

pub struct LogRequests(pub u32);

struct LogStart(u64);

impl Middleware for LogRequests {
    fn before(&self, req: &mut Request) -> Result<(), Box<Show>> {
        req.mut_extensions().insert(LogStart(time::precise_time_ns()));
        Ok(())
    }

    fn after(&self, req: &mut Request,
             resp: Result<Response, Box<Show>>) -> Result<Response, Box<Show>> {
        let LogStart(start) = *req.mut_extensions().find::<LogStart>().unwrap();

        match resp {
            Ok(ref resp) => self.log_message(req, start, resp.status.val0(),
                                             None),
            Err(ref e) => {
                let msg: &Show = *e;
                self.log_message(req, start, 500, Some(msg))
            }
        }
        resp
    }

}

impl LogRequests {
    fn log_message(&self, req: &mut Request, start: u64, status: uint,
                   msg: Option<&Show>) {
        let LogRequests(level) = *self;
        log!(level, "{} [{}] {} {} - {}ms {}{}",
             req.remote_ip(),
             time::now().rfc3339(),
             req.method(),
             req.path(),
             (time::precise_time_ns() - start) / 1000000,
             status,
             match msg {
                 None => String::new(),
                 Some(s) => format!(": {}", s),
             })
    }
}

#[cfg(test)]
mod tests {
    extern crate test = "conduit-test";

    use {LogRequests};

    use std;
    use log;
    use conduit;
    use middleware;

    use std::io::{ChanWriter, ChanReader};
    use log::{Logger, LogRecord};
    use conduit::{Request, Response, Handler};

    struct MyWriter(ChanWriter);

    impl Logger for MyWriter {
        fn log(&mut self, record: &LogRecord) {
            let MyWriter(ref mut inner) = *self;
            (write!(inner, "{}", record.args)).unwrap();
        }
    }

    #[test]
    fn test_log() {
        let (sender, receiver) = channel();
        let mut reader = ChanReader::new(receiver);

        let mut builder = middleware::MiddlewareBuilder::new(handler);
        builder.add(LogRequests(log::ERROR));

        task(builder, sender);

        let result = reader.read_to_string().ok().expect("No response");
        let parts = result.as_slice().split(' ').map(|s| s.to_string()).collect::<Vec<String>>();

        assert_eq!(parts.get(0).as_slice(), "127.0.0.1");
        assert!(parts.get(1).as_slice().len() == "[2014-07-01T22:34:06-07:00]".len());
        assert_eq!(parts.get(2).as_slice(), "Get");
        assert_eq!(parts.get(3).as_slice(), "/foo");
    }

    fn task<H: Handler + 'static + Send>(handler: H, sender: Sender<Vec<u8>>) {
        spawn(proc() {
            log::set_logger(box MyWriter(ChanWriter::new(sender)));
            let mut request = test::MockRequest::new(conduit::Get, "/foo");
            let _ = handler.call(&mut request);
        });
    }

    fn handler(_: &mut Request) -> Result<Response, ()> {
        Ok(Response {
            status: (200, "OK"),
            headers: std::collections::HashMap::new(),
            body: box std::io::util::NullReader
        })
    }
}
<commit_msg>Update to master again<commit_after>#![feature(globs)]
#![feature(phase)]

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

extern crate time;
extern crate conduit;
extern crate middleware = "conduit-middleware";

use std::fmt::Show;

use conduit::{Request, Response};
use middleware::Middleware;

pub struct LogRequests(pub u32);

struct LogStart(u64);

impl Middleware for LogRequests {
    fn before(&self, req: &mut Request) -> Result<(), Box<Show + 'static>> {
        req.mut_extensions().insert(LogStart(time::precise_time_ns()));
        Ok(())
    }

    fn after(&self, req: &mut Request, resp: Result<Response, Box<Show + 'static>>)
             -> Result<Response, Box<Show + 'static>> {
        let LogStart(start) = *req.mut_extensions().find::<LogStart>().unwrap();

        match resp {
            Ok(ref resp) => self.log_message(req, start, resp.status.val0(),
                                             None),
            Err(ref e) => {
                let msg: &Show = *e;
                self.log_message(req, start, 500, Some(msg))
            }
        }
        resp
    }

}

impl LogRequests {
    fn log_message(&self, req: &mut Request, start: u64, status: uint,
                   msg: Option<&Show>) {
        let LogRequests(level) = *self;
        log!(level, "{} [{}] {} {} - {}ms {}{}",
             req.remote_ip(),
             time::now().rfc3339(),
             req.method(),
             req.path(),
             (time::precise_time_ns() - start) / 1000000,
             status,
             match msg {
                 None => String::new(),
                 Some(s) => format!(": {}", s),
             })
    }
}

#[cfg(test)]
mod tests {
    extern crate test = "conduit-test";

    use {LogRequests};

    use std;
    use log;
    use conduit;
    use middleware;

    use std::io::{ChanWriter, ChanReader};
    use log::{Logger, LogRecord};
    use conduit::{Request, Response, Handler};

    struct MyWriter(ChanWriter);

    impl Logger for MyWriter {
        fn log(&mut self, record: &LogRecord) {
            let MyWriter(ref mut inner) = *self;
            (write!(inner, "{}", record.args)).unwrap();
        }
    }

    #[test]
    fn test_log() {
        let (sender, receiver) = channel();
        let mut reader = ChanReader::new(receiver);

        let mut builder = middleware::MiddlewareBuilder::new(handler);
        builder.add(LogRequests(log::ERROR));

        task(builder, sender);

        let result = reader.read_to_string().ok().expect("No response");
        let parts = result.as_slice().split(' ').map(|s| s.to_string()).collect::<Vec<String>>();

        assert_eq!(parts.get(0).as_slice(), "127.0.0.1");
        assert!(parts.get(1).as_slice().len() == "[2014-07-01T22:34:06-07:00]".len());
        assert_eq!(parts.get(2).as_slice(), "Get");
        assert_eq!(parts.get(3).as_slice(), "/foo");
    }

    fn task<H: Handler + 'static + Send>(handler: H, sender: Sender<Vec<u8>>) {
        spawn(proc() {
            log::set_logger(box MyWriter(ChanWriter::new(sender)));
            let mut request = test::MockRequest::new(conduit::Get, "/foo");
            let _ = handler.call(&mut request);
        });
    }

    fn handler(_: &mut Request) -> Result<Response, ()> {
        Ok(Response {
            status: (200, "OK"),
            headers: std::collections::HashMap::new(),
            body: box std::io::util::NullReader
        })
    }
}
<|endoftext|>


<commit_before>//! Parser for bitmap fonts

mod char;
mod config_parse_error;
mod error;
mod kerning_value;
mod page;
mod rect;
mod sections;
mod string_parse_error;
mod utils;

pub use self::config_parse_error::ConfigParseError;
pub use self::error::Error;
pub use self::rect::Rect;
pub use self::string_parse_error::StringParseError;

use self::char::Char;
use self::kerning_value::KerningValue;
use self::page::Page;
use self::sections::Sections;
use std::io::Read;
use std::iter::Peekable;
use std::str::Chars;

/// Alias of either [`Result<Vec<CharPosition>, StringParseError>`] _or_ [`Vec<CharPosition>`],
/// returned by [`BMFont::parse()`].
///
/// The output type depends on the value of the `parse-error` package feature.
///
/// **_NOTE:_** This documentation was generated _with_ the `parse-error` feature.
#[cfg(feature = "parse-error")]
pub type Parse<'a> = Result<ParseIter<'a>, StringParseError>;

/// Alias of either [`Result<Vec<CharPosition>, StringParseError>`] _or_ [`Vec<CharPosition>`],
/// returned by [`BMFont::parse()`].
///
/// The output type depends on the value of the `parse-error` package feature.
///
/// **_NOTE:_** This documentation was generated _without_ the `parse-error` feature.
#[cfg(not(feature = "parse-error"))]
pub type Parse<'a> = ParseIter<'a>;

#[cfg(feature = "parse-error")]
type ParseLines<'a> = Result<LineIter<'a>, StringParseError>;

#[cfg(not(feature = "parse-error"))]
type ParseLines<'a> = LineIter<'a>;

#[derive(Clone, Debug)]
pub struct CharPosition {
    pub page_rect: Rect,
    pub screen_rect: Rect,
    pub page_index: u32,
}

#[derive(Clone, Debug)]
pub enum OrdinateOrientation {
    BottomToTop,
    TopToBottom,
}

/// Holds a decoded bitmap font defintion, including all character advance and kerning values.
#[derive(Clone, Debug)]
pub struct BMFont {
    base_height: u32,
    line_height: u32,
    characters: Vec<Char>,
    kerning_values: Vec<KerningValue>,
    pages: Vec<Page>,
    ordinate_orientation: OrdinateOrientation,
}

impl BMFont {
    /// Constructs a new [BMFont].
    ///
    /// ## Examples
    ///
    /// From a file:
    ///
    /// ```rust
    /// # use bmfont::*;
    /// # fn main() -> Result<(), Error> {
    /// let file = std::fs::File::open("font.fnt")?;
    /// let font = BMFont::new(file, OrdinateOrientation::TopToBottom)?;
    /// assert_eq!(font.line_height(), 80);
    /// #     Ok(())
    /// # }
    /// ```
    ///
    /// From a slice of bytes:
    ///
    /// ```rust
    /// # use bmfont::*;
    /// # fn main() -> Result<(), Error> {
    /// # let my_font_bytes = std::fs::read("font.fnt")?;
    /// let data = std::io::Cursor::new(my_font_bytes);
    /// let font = BMFont::new(data, OrdinateOrientation::TopToBottom)?;
    /// assert_eq!(font.line_height(), 80);
    /// #     Ok(())
    /// # }
    /// ```
    pub fn new<R>(source: R, ordinate_orientation: OrdinateOrientation) -> Result<BMFont, Error>
    where
        R: Read,
    {
        let sections = Sections::new(source)?;

        let base_height;
        let line_height;
        {
            let mut components = sections.common_section.split_whitespace();
            components.next();
            line_height =
                utils::extract_component_value(components.next(), "common", "lineHeight")?;
            base_height = utils::extract_component_value(components.next(), "common", "base")?;
        }

        let mut pages = Vec::with_capacity(sections.page_sections.len());
        for page_section in &sections.page_sections {
            pages.push(Page::new(page_section)?);
        }

        // Sort the characters while loading them so that lookup can be faster during parse
        let mut characters: Vec<Char> = Vec::with_capacity(sections.char_sections.len());
        for char_section in &sections.char_sections {
            let char = Char::new(char_section)?;
            if let Err(idx) = characters.binary_search_by(|probe| probe.id.cmp(&char.id)) {
                characters.insert(idx, char);
            }
        }

        // Also sort kerning values for the same reason, but we allow duplicates
        let mut kerning_values: Vec<KerningValue> =
            Vec::with_capacity(sections.kerning_sections.len());
        for kerning_section in &sections.kerning_sections {
            let kerning = KerningValue::new(kerning_section)?;

            match kerning_values
                .binary_search_by(|probe| probe.first_char_id.cmp(&kerning.first_char_id))
            {
                Err(idx) | Ok(idx) => kerning_values.insert(idx, kerning),
            }
        }

        Ok(BMFont {
            base_height,
            line_height,
            characters,
            kerning_values,
            pages,
            ordinate_orientation,
        })
    }

    /// Returns the height of a `EM` in pixels.
    pub fn base_height(&self) -> u32 {
        self.base_height
    }

    pub fn line_height(&self) -> u32 {
        self.line_height
    }

    /// Returns an `Iterator` of font page bitmap filenames.
    ///
    /// ## Examples
    ///
    /// ```rust
    /// # use bmfont::*;
    /// # fn main() -> Result<(), Error> {
    /// let file = std::fs::File::open("font.fnt")?;
    /// let font = BMFont::new(file, OrdinateOrientation::TopToBottom)?;
    /// assert_eq!(font.pages().next(), Some("font.png"));
    /// #     Ok(())
    /// # }
    /// ```
    pub fn pages(&self) -> PageIter {
        PageIter::new(&self.pages)
    }

    pub fn parse<'s>(&'s self, s: &'s str) -> Parse<'s> {
        let lines = self.parse_lines(s);

        #[cfg(feature = "parse-error")]
        let lines = lines?;

        let char_positions = ParseIter::new(self, lines);

        #[cfg(feature = "parse-error")]
        {
            Ok(char_positions)
        }

        #[cfg(not(feature = "parse-error"))]
        {
            char_positions
        }
    }

    fn find_kerning_values(&self, first_char_id: u32) -> KerningIter {
        let needle = (first_char_id << 1) - 1;
        let idx = self
            .kerning_values
            .binary_search_by(|probe| (probe.first_char_id << 1).cmp(&needle))
            .unwrap_err();

        KerningIter {
            first_char_id,
            idx,
            values: &self.kerning_values,
        }
    }

    fn parse_lines<'a>(&'a self, s: &'a str) -> ParseLines<'a> {
        #[cfg(feature = "parse-error")]
        {
            let mut temp = [0u16; 2];
            let mut missing_characters: Option<Vec<char>> = None;
            let mut unsupported_characters: Option<Vec<char>> = None;

            for c in s.chars() {
                if c == '\n' {
                    continue;
                } else if c.len_utf16() != 1 {
                    if let Some(vec) = unsupported_characters.as_mut() {
                        vec.push(c);
                    } else {
                        unsupported_characters = Some(vec![c]);
                    }

                    continue;
                }

                c.encode_utf16(&mut temp);
                let char_id = temp[0] as u32;

                if self
                    .characters
                    .binary_search_by(|probe| probe.id.cmp(&char_id))
                    .is_ok()
                {
                    continue;
                }

                if let Some(vec) = missing_characters.as_mut() {
                    vec.push(c);
                } else {
                    missing_characters = Some(vec![c]);
                }
            }

            if missing_characters.is_some() || unsupported_characters.is_some() {
                return Err(StringParseError {
                    missing_characters: missing_characters.unwrap_or_default(),
                    unsupported_characters: unsupported_characters.unwrap_or_default(),
                });
            }
        }

        let lines = LineIter {
            characters: &self.characters,
            text: Some(s.chars().peekable()),
        };

        #[cfg(feature = "parse-error")]
        {
            Ok(lines)
        }

        #[cfg(not(feature = "parse-error"))]
        lines
    }
}

struct CharIter<'a> {
    characters: &'a Vec<Char>,
    text: Peekable<Chars<'a>>,
}

impl<'a> Iterator for CharIter<'a> {
    type Item = &'a Char;

    fn next(&mut self) -> Option<Self::Item> {
        loop {
            return match self.text.next() {
                None | Some('\n') => None,
                Some(chr) if chr.len_utf16() != 1 => continue,
                Some(chr) => {
                    let mut temp = [0u16; 2];
                    chr.encode_utf16(&mut temp);
                    let char_id = temp[0] as u32;
                    let char_idx = self
                        .characters
                        .binary_search_by(|probe| probe.id.cmp(&char_id));

                    #[cfg(not(feature = "parse-error"))]
                    if char_idx.is_err() {
                        continue;
                    }

                    let char_idx = char_idx.unwrap();
                    Some(&self.characters[char_idx])
                }
            };
        }
    }
}

struct KerningIter<'a> {
    first_char_id: u32,
    idx: usize,
    values: &'a Vec<KerningValue>,
}

impl<'a> KerningIter<'a> {
    fn empty(values: &'a Vec<KerningValue>) -> Self {
        Self {
            first_char_id: 0,
            idx: values.len(),
            values,
        }
    }
}

impl<'a> Iterator for KerningIter<'a> {
    type Item = &'a KerningValue;

    fn next(&mut self) -> Option<Self::Item> {
        if let Some(value) = self.values.get(self.idx) {
            if value.first_char_id == self.first_char_id {
                self.idx += 1;

                return Some(value);
            }
        }
        None
    }
}

struct LineIter<'a> {
    characters: &'a Vec<Char>,
    text: Option<Peekable<Chars<'a>>>,
}

impl<'a> Iterator for LineIter<'a> {
    type Item = CharIter<'a>;

    fn next(&mut self) -> Option<Self::Item> {
        match self.text.as_mut().unwrap().peek() {
            Some(_) => Some(CharIter {
                characters: &self.characters,
                text: self.text.take().unwrap(),
            }),
            _ => None,
        }
    }
}

#[derive(Clone, Debug)]
pub struct PageIter<'a> {
    idx: usize,
    pages: &'a Vec<Page>,
}

impl<'a> PageIter<'a> {
    fn new(pages: &'a Vec<Page>) -> Self {
        Self { idx: 0, pages }
    }
}

impl<'a> Iterator for PageIter<'a> {
    type Item = &'a str;

    fn next(&mut self) -> Option<Self::Item> {
        if let Some(page) = self.pages.get(self.idx) {
            self.idx += 1;
            Some(page.file.as_str())
        } else {
            None
        }
    }
}

pub struct ParseIter<'a> {
    font: &'a BMFont,
    line: Option<ParseLineIter<'a>>,
    lines: LineIter<'a>,
    y: i32,
}

impl<'a> ParseIter<'a> {
    fn new(font: &'a BMFont, lines: LineIter<'a>) -> Self {
        Self {
            font,
            line: None,
            lines,
            y: 0,
        }
    }
}

impl<'a> Iterator for ParseIter<'a> {
    type Item = CharPosition;

    fn next(&mut self) -> Option<Self::Item> {
        loop {
            if self.line.is_none() {
                if let Some(chars) = self.lines.next() {
                    self.line = Some(ParseLineIter::new(&self.font, chars, self.y));
                } else {
                    return None;
                }
            }

            let line = self.line.as_mut().unwrap();
            if let Some(char_position) = line.next() {
                return Some(char_position);
            }

            self.lines
                .text
                .replace(self.line.take().unwrap().chars.text);
            match self.font.ordinate_orientation {
                OrdinateOrientation::TopToBottom => self.y += self.font.line_height as i32,
                OrdinateOrientation::BottomToTop => self.y -= self.font.line_height as i32,
            }
        }
    }
}

struct ParseLineIter<'a> {
    font: &'a BMFont,
    chars: CharIter<'a>,
    kerning_values: KerningIter<'a>,
    x: i32,
    y: i32,
}

impl<'a> ParseLineIter<'a> {
    fn new(font: &'a BMFont, chars: CharIter<'a>, y: i32) -> Self {
        Self {
            font,
            chars,
            kerning_values: KerningIter::empty(&font.kerning_values),
            x: 0,
            y,
        }
    }
}

impl<'a> Iterator for ParseLineIter<'a> {
    type Item = CharPosition;

    fn next(&mut self) -> Option<Self::Item> {
        match self.chars.next() {
            Some(char) => {
                let kerning_value = self
                    .kerning_values
                    .find(|k| k.second_char_id == char.id)
                    .map(|k| k.value)
                    .unwrap_or(0);
                let page_rect = Rect {
                    x: char.x as i32,
                    y: char.y as i32,
                    width: char.width,
                    height: char.height,
                };
                let screen_x = self.x + char.xoffset + kerning_value;
                let screen_y = match self.font.ordinate_orientation {
                    OrdinateOrientation::BottomToTop => {
                        self.y + self.font.base_height as i32 - char.yoffset - char.height as i32
                    }
                    OrdinateOrientation::TopToBottom => self.y + char.yoffset,
                };
                let screen_rect = Rect {
                    x: screen_x,
                    y: screen_y,
                    width: char.width,
                    height: char.height,
                };
                let char_position = CharPosition {
                    page_rect,
                    screen_rect,
                    page_index: char.page_index,
                };
                self.x += char.xadvance + kerning_value;
                self.kerning_values = self.font.find_kerning_values(char.id);

                Some(char_position)
            }
            _ => None,
        }
    }
}
<commit_msg>Doc update<commit_after>//! Parser for bitmap fonts

mod char;
mod config_parse_error;
mod error;
mod kerning_value;
mod page;
mod rect;
mod sections;
mod string_parse_error;
mod utils;

pub use self::config_parse_error::ConfigParseError;
pub use self::error::Error;
pub use self::rect::Rect;
pub use self::string_parse_error::StringParseError;

use self::char::Char;
use self::kerning_value::KerningValue;
use self::page::Page;
use self::sections::Sections;
use std::io::Read;
use std::iter::Peekable;
use std::str::Chars;

/// Alias of either [`Result<Vec<CharPosition>, StringParseError>`] _or_ [`Vec<CharPosition>`],
/// returned by [`BMFont::parse()`].
///
/// The output type depends on the value of the `parse-error` package feature.
///
/// **_NOTE:_** This documentation was generated _with_ the `parse-error` feature.
#[cfg(feature = "parse-error")]
pub type Parse<'a> = Result<ParseIter<'a>, StringParseError>;

/// Alias of either [`Result<Vec<CharPosition>, StringParseError>`] _or_ [`Vec<CharPosition>`],
/// returned by [`BMFont::parse()`].
///
/// The output type depends on the value of the `parse-error` package feature.
///
/// **_NOTE:_** This documentation was generated _without_ the `parse-error` feature.
#[cfg(not(feature = "parse-error"))]
pub type Parse<'a> = ParseIter<'a>;

#[cfg(feature = "parse-error")]
type ParseLines<'a> = Result<LineIter<'a>, StringParseError>;

#[cfg(not(feature = "parse-error"))]
type ParseLines<'a> = LineIter<'a>;

#[derive(Clone, Debug)]
pub struct CharPosition {
    pub page_rect: Rect,
    pub screen_rect: Rect,
    pub page_index: u32,
}

#[derive(Clone, Debug)]
pub enum OrdinateOrientation {
    BottomToTop,
    TopToBottom,
}

/// Holds a decoded bitmap font defintion, including all character advance and kerning values.
#[derive(Clone, Debug)]
pub struct BMFont {
    base_height: u32,
    line_height: u32,
    characters: Vec<Char>,
    kerning_values: Vec<KerningValue>,
    pages: Vec<Page>,
    ordinate_orientation: OrdinateOrientation,
}

impl BMFont {
    /// Constructs a new [BMFont].
    ///
    /// # Examples
    ///
    /// From a file:
    ///
    /// ```rust
    /// # use bmfont::*;
    /// # fn main() -> Result<(), Error> {
    /// let file = std::fs::File::open("font.fnt")?;
    /// let font = BMFont::new(file, OrdinateOrientation::TopToBottom)?;
    /// assert_eq!(font.line_height(), 80);
    /// #     Ok(())
    /// # }
    /// ```
    ///
    /// From a slice of bytes:
    ///
    /// ```rust
    /// # use bmfont::*;
    /// # fn main() -> Result<(), Error> {
    /// # let my_font_bytes = std::fs::read("font.fnt")?;
    /// let data = std::io::Cursor::new(my_font_bytes);
    /// let font = BMFont::new(data, OrdinateOrientation::TopToBottom)?;
    /// assert_eq!(font.line_height(), 80);
    /// #     Ok(())
    /// # }
    /// ```
    pub fn new<R>(source: R, ordinate_orientation: OrdinateOrientation) -> Result<BMFont, Error>
    where
        R: Read,
    {
        let sections = Sections::new(source)?;

        let base_height;
        let line_height;
        {
            let mut components = sections.common_section.split_whitespace();
            components.next();
            line_height =
                utils::extract_component_value(components.next(), "common", "lineHeight")?;
            base_height = utils::extract_component_value(components.next(), "common", "base")?;
        }

        let mut pages = Vec::with_capacity(sections.page_sections.len());
        for page_section in &sections.page_sections {
            pages.push(Page::new(page_section)?);
        }

        // Sort the characters while loading them so that lookup can be faster during parse
        let mut characters: Vec<Char> = Vec::with_capacity(sections.char_sections.len());
        for char_section in &sections.char_sections {
            let char = Char::new(char_section)?;
            if let Err(idx) = characters.binary_search_by(|probe| probe.id.cmp(&char.id)) {
                characters.insert(idx, char);
            }
        }

        // Also sort kerning values for the same reason, but we allow duplicates
        let mut kerning_values: Vec<KerningValue> =
            Vec::with_capacity(sections.kerning_sections.len());
        for kerning_section in &sections.kerning_sections {
            let kerning = KerningValue::new(kerning_section)?;

            match kerning_values
                .binary_search_by(|probe| probe.first_char_id.cmp(&kerning.first_char_id))
            {
                Err(idx) | Ok(idx) => kerning_values.insert(idx, kerning),
            }
        }

        Ok(BMFont {
            base_height,
            line_height,
            characters,
            kerning_values,
            pages,
            ordinate_orientation,
        })
    }

    /// Returns the height of a `EM` in pixels.
    pub fn base_height(&self) -> u32 {
        self.base_height
    }

    pub fn line_height(&self) -> u32 {
        self.line_height
    }

    /// Returns an `Iterator` of font page bitmap filenames.
    ///
    /// # Examples
    ///
    /// ```rust
    /// # use bmfont::*;
    /// # fn main() -> Result<(), Error> {
    /// let file = std::fs::File::open("font.fnt")?;
    /// let font = BMFont::new(file, OrdinateOrientation::TopToBottom)?;
    /// assert_eq!(font.pages().next(), Some("font.png"));
    /// #     Ok(())
    /// # }
    /// ```
    pub fn pages(&self) -> PageIter {
        PageIter::new(&self.pages)
    }

    pub fn parse<'s>(&'s self, s: &'s str) -> Parse<'s> {
        let lines = self.parse_lines(s);

        #[cfg(feature = "parse-error")]
        let lines = lines?;

        let char_positions = ParseIter::new(self, lines);

        #[cfg(feature = "parse-error")]
        {
            Ok(char_positions)
        }

        #[cfg(not(feature = "parse-error"))]
        {
            char_positions
        }
    }

    fn find_kerning_values(&self, first_char_id: u32) -> KerningIter {
        let needle = (first_char_id << 1) - 1;
        let idx = self
            .kerning_values
            .binary_search_by(|probe| (probe.first_char_id << 1).cmp(&needle))
            .unwrap_err();

        KerningIter {
            first_char_id,
            idx,
            values: &self.kerning_values,
        }
    }

    fn parse_lines<'a>(&'a self, s: &'a str) -> ParseLines<'a> {
        #[cfg(feature = "parse-error")]
        {
            let mut temp = [0u16; 2];
            let mut missing_characters: Option<Vec<char>> = None;
            let mut unsupported_characters: Option<Vec<char>> = None;

            for c in s.chars() {
                if c == '\n' {
                    continue;
                } else if c.len_utf16() != 1 {
                    if let Some(vec) = unsupported_characters.as_mut() {
                        vec.push(c);
                    } else {
                        unsupported_characters = Some(vec![c]);
                    }

                    continue;
                }

                c.encode_utf16(&mut temp);
                let char_id = temp[0] as u32;

                if self
                    .characters
                    .binary_search_by(|probe| probe.id.cmp(&char_id))
                    .is_ok()
                {
                    continue;
                }

                if let Some(vec) = missing_characters.as_mut() {
                    vec.push(c);
                } else {
                    missing_characters = Some(vec![c]);
                }
            }

            if missing_characters.is_some() || unsupported_characters.is_some() {
                return Err(StringParseError {
                    missing_characters: missing_characters.unwrap_or_default(),
                    unsupported_characters: unsupported_characters.unwrap_or_default(),
                });
            }
        }

        let lines = LineIter {
            characters: &self.characters,
            text: Some(s.chars().peekable()),
        };

        #[cfg(feature = "parse-error")]
        {
            Ok(lines)
        }

        #[cfg(not(feature = "parse-error"))]
        lines
    }
}

struct CharIter<'a> {
    characters: &'a Vec<Char>,
    text: Peekable<Chars<'a>>,
}

impl<'a> Iterator for CharIter<'a> {
    type Item = &'a Char;

    fn next(&mut self) -> Option<Self::Item> {
        loop {
            return match self.text.next() {
                None | Some('\n') => None,
                Some(chr) if chr.len_utf16() != 1 => continue,
                Some(chr) => {
                    let mut temp = [0u16; 2];
                    chr.encode_utf16(&mut temp);
                    let char_id = temp[0] as u32;
                    let char_idx = self
                        .characters
                        .binary_search_by(|probe| probe.id.cmp(&char_id));

                    #[cfg(not(feature = "parse-error"))]
                    if char_idx.is_err() {
                        continue;
                    }

                    let char_idx = char_idx.unwrap();
                    Some(&self.characters[char_idx])
                }
            };
        }
    }
}

struct KerningIter<'a> {
    first_char_id: u32,
    idx: usize,
    values: &'a Vec<KerningValue>,
}

impl<'a> KerningIter<'a> {
    fn empty(values: &'a Vec<KerningValue>) -> Self {
        Self {
            first_char_id: 0,
            idx: values.len(),
            values,
        }
    }
}

impl<'a> Iterator for KerningIter<'a> {
    type Item = &'a KerningValue;

    fn next(&mut self) -> Option<Self::Item> {
        if let Some(value) = self.values.get(self.idx) {
            if value.first_char_id == self.first_char_id {
                self.idx += 1;

                return Some(value);
            }
        }
        None
    }
}

struct LineIter<'a> {
    characters: &'a Vec<Char>,
    text: Option<Peekable<Chars<'a>>>,
}

impl<'a> Iterator for LineIter<'a> {
    type Item = CharIter<'a>;

    fn next(&mut self) -> Option<Self::Item> {
        match self.text.as_mut().unwrap().peek() {
            Some(_) => Some(CharIter {
                characters: &self.characters,
                text: self.text.take().unwrap(),
            }),
            _ => None,
        }
    }
}

#[derive(Clone, Debug)]
pub struct PageIter<'a> {
    idx: usize,
    pages: &'a Vec<Page>,
}

impl<'a> PageIter<'a> {
    fn new(pages: &'a Vec<Page>) -> Self {
        Self { idx: 0, pages }
    }
}

impl<'a> Iterator for PageIter<'a> {
    type Item = &'a str;

    fn next(&mut self) -> Option<Self::Item> {
        if let Some(page) = self.pages.get(self.idx) {
            self.idx += 1;
            Some(page.file.as_str())
        } else {
            None
        }
    }
}

pub struct ParseIter<'a> {
    font: &'a BMFont,
    line: Option<ParseLineIter<'a>>,
    lines: LineIter<'a>,
    y: i32,
}

impl<'a> ParseIter<'a> {
    fn new(font: &'a BMFont, lines: LineIter<'a>) -> Self {
        Self {
            font,
            line: None,
            lines,
            y: 0,
        }
    }
}

impl<'a> Iterator for ParseIter<'a> {
    type Item = CharPosition;

    fn next(&mut self) -> Option<Self::Item> {
        loop {
            if self.line.is_none() {
                if let Some(chars) = self.lines.next() {
                    self.line = Some(ParseLineIter::new(&self.font, chars, self.y));
                } else {
                    return None;
                }
            }

            let line = self.line.as_mut().unwrap();
            if let Some(char_position) = line.next() {
                return Some(char_position);
            }

            self.lines
                .text
                .replace(self.line.take().unwrap().chars.text);
            match self.font.ordinate_orientation {
                OrdinateOrientation::TopToBottom => self.y += self.font.line_height as i32,
                OrdinateOrientation::BottomToTop => self.y -= self.font.line_height as i32,
            }
        }
    }
}

struct ParseLineIter<'a> {
    font: &'a BMFont,
    chars: CharIter<'a>,
    kerning_values: KerningIter<'a>,
    x: i32,
    y: i32,
}

impl<'a> ParseLineIter<'a> {
    fn new(font: &'a BMFont, chars: CharIter<'a>, y: i32) -> Self {
        Self {
            font,
            chars,
            kerning_values: KerningIter::empty(&font.kerning_values),
            x: 0,
            y,
        }
    }
}

impl<'a> Iterator for ParseLineIter<'a> {
    type Item = CharPosition;

    fn next(&mut self) -> Option<Self::Item> {
        match self.chars.next() {
            Some(char) => {
                let kerning_value = self
                    .kerning_values
                    .find(|k| k.second_char_id == char.id)
                    .map(|k| k.value)
                    .unwrap_or(0);
                let page_rect = Rect {
                    x: char.x as i32,
                    y: char.y as i32,
                    width: char.width,
                    height: char.height,
                };
                let screen_x = self.x + char.xoffset + kerning_value;
                let screen_y = match self.font.ordinate_orientation {
                    OrdinateOrientation::BottomToTop => {
                        self.y + self.font.base_height as i32 - char.yoffset - char.height as i32
                    }
                    OrdinateOrientation::TopToBottom => self.y + char.yoffset,
                };
                let screen_rect = Rect {
                    x: screen_x,
                    y: screen_y,
                    width: char.width,
                    height: char.height,
                };
                let char_position = CharPosition {
                    page_rect,
                    screen_rect,
                    page_index: char.page_index,
                };
                self.x += char.xadvance + kerning_value;
                self.kerning_values = self.font.find_kerning_values(char.id);

                Some(char_position)
            }
            _ => None,
        }
    }
}
<|endoftext|>