<commit_before>use std::result:: { Result };
use std::collections:: { HashMap };
use std::default::Default;
use lcov_parser:: {
    LCOVParser, LCOVRecord, LineData, FunctionData as FunctionDataRecord,
    BranchData as BranchDataRecord,
    FunctionName, ParseError, FromFile
};
use branch:: { BranchUnit };
use test:: { Test, TestSum };
use file:: { File, CheckSum, FunctionData };

/// Read the trace file of LCOV
///
/// # Examples
///
/// ```
/// use lcov_merge::parse_file;
///
/// let files = parse_file("tests/fixtures/fixture1.info").unwrap();
/// assert_eq!(files.keys().count(), 3);
///
/// let fixture = files.get("/home/vagrant/shared/lcov-merge/tests/fixtures/fixture.c").unwrap();
///
/// assert_eq!(fixture.sum().get_line_count(&4), Some(&1));
/// assert_eq!(fixture.sum().get_line_count(&6), Some(&1));
/// assert_eq!(fixture.sum().get_line_count(&7), Some(&1));
/// assert_eq!(fixture.sum().get_line_count(&8), Some(&1));
/// assert_eq!(fixture.sum().get_line_count(&1), None);
///
/// assert_eq!(fixture.get_test(&"example".to_string()).unwrap().get_line_count(&4), Some(&1));
/// ```
pub fn parse_file(file: &str) -> Result<HashMap<String, File>, ParseError> {
    let mut parse = ReportParser::new();
    parse.parse(file)
}

struct ReportParser {
    test_name: Option<String>,
    source_name: Option<String>,
    tests: HashMap<String, Test>,
    sum: TestSum,
    checksum: CheckSum,
    func: FunctionData,
    files: HashMap<String, File>
}

impl ReportParser {
    fn new() -> Self {
        ReportParser {
            test_name: None,
            source_name: None,
            tests: HashMap::new(),
            sum: TestSum::new(),
            checksum: HashMap::new(),
            func: HashMap::new(),
            files: HashMap::new()
        }
    }
    fn parse(&mut self, file: &str) -> Result<HashMap<String, File>, ParseError> {
        let mut parser = try!(LCOVParser::from_file(file));

        loop {
            let result = try!(parser.next());

            if result.is_none() {
                break;
            }
            let record = result.unwrap();

            match record {
                LCOVRecord::TestName(ref name) => self.on_test_name(name),
                LCOVRecord::SourceFile(ref name) => self.on_source_file(name),
                LCOVRecord::Data(ref data) => self.on_data(data),
                LCOVRecord::FunctionName(ref func_name) => self.on_func_name(func_name),
                LCOVRecord::FunctionData(ref func_data) => self.on_func_data(func_data),
                LCOVRecord::BranchData(ref branch_data) => self.on_branch_data(branch_data),
                LCOVRecord::EndOfRecord => self.on_end_of_record(),
                _ => { continue; }
            };
        }
        Ok(self.files.clone())
    }
    fn on_test_name(&mut self, test_name: &Option<String>) {
        self.test_name = test_name.clone().or( Some(String::new()) );
    }
    fn on_source_file(&mut self, source_name: &String) {
        self.source_name = Some(source_name.clone());

        let current_test_name = self.test_name.as_ref().unwrap();

        if !self.tests.contains_key(current_test_name) {
            self.tests.insert(current_test_name.to_string(), Test::default());
        }
    }
    fn on_data(&mut self, data: &LineData) {
        self.sum += data;

        if self.test_name.is_some() {
            let test_name = self.test_name.clone().unwrap();
            let mut test = self.tests.get_mut(&test_name).unwrap();

            *test += data;
        }

        if data.checksum.is_none() {
            return;
        }

        if !self.checksum.contains_key(&data.line) {
            let checksum_value = data.checksum.clone().unwrap();
            self.checksum.insert(data.line.clone(), checksum_value);
            return;
        }

        let checksum_value = data.checksum.clone().unwrap();
        let current_checksum = self.checksum.get(&data.line).unwrap();
        if current_checksum != &checksum_value {
            println!("{} {}", current_checksum, checksum_value);
        }
    }
    fn on_func_name(&mut self, func_name: &FunctionName) {
        let _ = self.func.entry(func_name.name.clone())
            .or_insert(func_name.line.clone());
    }
    fn on_func_data(&mut self, func_data: &FunctionDataRecord) {
        self.sum += func_data;

        if self.test_name.is_none() {
            return;
        }

        let test_name = self.test_name.clone().unwrap();
        let mut test = self.tests.get_mut(&test_name).unwrap();

        *test += func_data;
    }
    fn on_branch_data(&mut self, branch_data: &BranchDataRecord) {
        self.sum += branch_data;

        if self.test_name.is_some() {
            let ref test_name = self.test_name.clone().unwrap();
            let mut test = self.tests.get_mut(test_name).unwrap();

            *test += branch_data;
        }
    }
    fn on_end_of_record(&mut self) {
        let source_name = self.source_name.clone().unwrap();

        self.files.insert(source_name, File::new(
            self.sum.clone(),
            self.tests.clone(),
            self.checksum.clone(),
            self.func.clone()
        ));
    }
}
<commit_msg>change to as_ref<commit_after>use std::result:: { Result };
use std::collections:: { HashMap };
use std::default::Default;
use lcov_parser:: {
    LCOVParser, LCOVRecord, LineData, FunctionData as FunctionDataRecord,
    BranchData as BranchDataRecord,
    FunctionName, ParseError, FromFile
};
use branch:: { BranchUnit };
use test:: { Test, TestSum };
use file:: { File, CheckSum, FunctionData };

/// Read the trace file of LCOV
///
/// # Examples
///
/// ```
/// use lcov_merge::parse_file;
///
/// let files = parse_file("tests/fixtures/fixture1.info").unwrap();
/// assert_eq!(files.keys().count(), 3);
///
/// let fixture = files.get("/home/vagrant/shared/lcov-merge/tests/fixtures/fixture.c").unwrap();
///
/// assert_eq!(fixture.sum().get_line_count(&4), Some(&1));
/// assert_eq!(fixture.sum().get_line_count(&6), Some(&1));
/// assert_eq!(fixture.sum().get_line_count(&7), Some(&1));
/// assert_eq!(fixture.sum().get_line_count(&8), Some(&1));
/// assert_eq!(fixture.sum().get_line_count(&1), None);
///
/// assert_eq!(fixture.get_test(&"example".to_string()).unwrap().get_line_count(&4), Some(&1));
/// ```
pub fn parse_file(file: &str) -> Result<HashMap<String, File>, ParseError> {
    let mut parse = ReportParser::new();
    parse.parse(file)
}

struct ReportParser {
    test_name: Option<String>,
    source_name: Option<String>,
    tests: HashMap<String, Test>,
    sum: TestSum,
    checksum: CheckSum,
    func: FunctionData,
    files: HashMap<String, File>
}

impl ReportParser {
    fn new() -> Self {
        ReportParser {
            test_name: None,
            source_name: None,
            tests: HashMap::new(),
            sum: TestSum::new(),
            checksum: HashMap::new(),
            func: HashMap::new(),
            files: HashMap::new()
        }
    }
    fn parse(&mut self, file: &str) -> Result<HashMap<String, File>, ParseError> {
        let mut parser = try!(LCOVParser::from_file(file));

        loop {
            let result = try!(parser.next());

            if result.is_none() {
                break;
            }
            let record = result.unwrap();

            match record {
                LCOVRecord::TestName(ref name) => self.on_test_name(name),
                LCOVRecord::SourceFile(ref name) => self.on_source_file(name),
                LCOVRecord::Data(ref data) => self.on_data(data),
                LCOVRecord::FunctionName(ref func_name) => self.on_func_name(func_name),
                LCOVRecord::FunctionData(ref func_data) => self.on_func_data(func_data),
                LCOVRecord::BranchData(ref branch_data) => self.on_branch_data(branch_data),
                LCOVRecord::EndOfRecord => self.on_end_of_record(),
                _ => { continue; }
            };
        }
        Ok(self.files.clone())
    }
    fn on_test_name(&mut self, test_name: &Option<String>) {
        self.test_name = match test_name {
            &Some(ref name) => Some(name.clone()),
            &None => Some(String::new())
        };
    }
    fn on_source_file(&mut self, source_name: &String) {
        self.source_name = Some(source_name.clone());

        let current_test_name = self.test_name.as_ref().unwrap();

        if !self.tests.contains_key(current_test_name) {
            self.tests.insert(current_test_name.to_string(), Test::default());
        }
    }
    fn on_data(&mut self, data: &LineData) {
        self.sum += data;

        if self.test_name.is_some() {
            let test_name = self.test_name.as_ref().unwrap();
            let mut test = self.tests.get_mut(test_name).unwrap();

            *test += data;
        }

        if data.checksum.is_none() {
            return;
        }

        if !self.checksum.contains_key(&data.line) {
            let checksum_value = data.checksum.clone().unwrap();
            self.checksum.insert(data.line.clone(), checksum_value);
            return;
        }

        let checksum_value = data.checksum.clone().unwrap();
        let current_checksum = self.checksum.get(&data.line).unwrap();
        if current_checksum != &checksum_value {
            println!("{} {}", current_checksum, checksum_value);
        }
    }
    fn on_func_name(&mut self, func_name: &FunctionName) {
        if self.func.contains_key(&func_name.name) {
            return;
        }
        self.func.insert(func_name.name.clone(), func_name.line.clone());
    }
    fn on_func_data(&mut self, func_data: &FunctionDataRecord) {
        self.sum += func_data;

        if self.test_name.is_none() {
            return;
        }

        let test_name = self.test_name.as_ref().unwrap();
        let mut test = self.tests.get_mut(test_name).unwrap();

        *test += func_data;
    }
    fn on_branch_data(&mut self, branch_data: &BranchDataRecord) {
        self.sum += branch_data;

        if self.test_name.is_none() {
            return;
        }

        let test_name = self.test_name.as_ref().unwrap();
        let mut test = self.tests.get_mut(test_name).unwrap();

        *test += branch_data;
    }
    fn on_end_of_record(&mut self) {
        let source_name = self.source_name.clone().unwrap();

        self.files.insert(source_name, File::new(
            self.sum.clone(),
            self.tests.clone(),
            self.checksum.clone(),
            self.func.clone()
        ));
    }
}
<|endoftext|>


<commit_before>use crate::exception::Exception;
use alloc::boxed::Box;
use alloc::string::{String, ToString};
use core::fmt::Display;
use core::ptr::{self, NonNull};
use core::result::Result as StdResult;
use core::slice;
use core::str;

#[repr(C)]
#[derive(Copy, Clone)]
struct PtrLen {
    ptr: NonNull<u8>,
    len: usize,
}

#[repr(C)]
pub union Result {
    err: PtrLen,
    ok: *const u8, // null
}

pub unsafe fn r#try<T, E>(ret: *mut T, result: StdResult<T, E>) -> Result
where
    E: Display,
{
    match result {
        Ok(ok) => {
            ptr::write(ret, ok);
            Result { ok: ptr::null() }
        }
        Err(err) => to_c_error(err.to_string()),
    }
}

unsafe fn to_c_error(msg: String) -> Result {
    let mut msg = msg;
    msg.as_mut_vec().push(b'\0');
    let ptr = msg.as_ptr();
    let len = msg.len();

    extern "C" {
        #[link_name = "cxxbridge1$error"]
        fn error(ptr: *const u8, len: usize) -> *const u8;
    }

    let copy = error(ptr, len);
    let err = PtrLen {
        ptr: NonNull::new_unchecked(copy as *mut u8),
        len,
    };
    Result { err }
}

impl Result {
    pub unsafe fn exception(self) -> StdResult<(), Exception> {
        if self.ok.is_null() {
            Ok(())
        } else {
            let err = self.err;
            let slice = slice::from_raw_parts_mut(err.ptr.as_ptr(), err.len);
            let s = str::from_utf8_unchecked_mut(slice);
            Err(Exception {
                what: Box::from_raw(s),
            })
        }
    }
}
<commit_msg>Simplify to_c_error by using NonNull inline<commit_after>use crate::exception::Exception;
use alloc::boxed::Box;
use alloc::string::{String, ToString};
use core::fmt::Display;
use core::ptr::{self, NonNull};
use core::result::Result as StdResult;
use core::slice;
use core::str;

#[repr(C)]
#[derive(Copy, Clone)]
struct PtrLen {
    ptr: NonNull<u8>,
    len: usize,
}

#[repr(C)]
pub union Result {
    err: PtrLen,
    ok: *const u8, // null
}

pub unsafe fn r#try<T, E>(ret: *mut T, result: StdResult<T, E>) -> Result
where
    E: Display,
{
    match result {
        Ok(ok) => {
            ptr::write(ret, ok);
            Result { ok: ptr::null() }
        }
        Err(err) => to_c_error(err.to_string()),
    }
}

unsafe fn to_c_error(msg: String) -> Result {
    let mut msg = msg;
    msg.as_mut_vec().push(b'\0');
    let ptr = msg.as_ptr();
    let len = msg.len();

    extern "C" {
        #[link_name = "cxxbridge1$error"]
        fn error(ptr: *const u8, len: usize) -> NonNull<u8>;
    }

    let copy = error(ptr, len);
    let err = PtrLen { ptr: copy, len };
    Result { err }
}

impl Result {
    pub unsafe fn exception(self) -> StdResult<(), Exception> {
        if self.ok.is_null() {
            Ok(())
        } else {
            let err = self.err;
            let slice = slice::from_raw_parts_mut(err.ptr.as_ptr(), err.len);
            let s = str::from_utf8_unchecked_mut(slice);
            Err(Exception {
                what: Box::from_raw(s),
            })
        }
    }
}
<|endoftext|>


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

//! Structs and methods for searching for tweets.
//!
//! Since there are several optional parameters for searches, egg-mode handles it with a builder
//! pattern. To begin, call `search` with your requested search term. Additional parameters can be
//! added onto the `SearchBuilder` struct that is returned. When you're ready to load the first
//! page of results, hand your tokens to `call`.
//!
//! ```rust,no_run
//! # let token = egg_mode::Token::Access {
//! #     consumer: egg_mode::KeyPair::new("", ""),
//! #     access: egg_mode::KeyPair::new("", ""),
//! # };
//! use egg_mode::search::{self, ResultType};
//!
//! let search = search::search("rustlang")
//!                     .result_type(ResultType::Recent)
//!                     .call(&token)
//!                     .unwrap();
//!
//! for tweet in &search.statuses {
//!     println!("(@{}) {}", tweet.user.as_ref().unwrap().screen_name, tweet.text);
//! }
//! ```
//!
//! Once you have your `SearchResult`, you can navigate the search results by calling `older` and
//! `newer` to get the next and previous pages, respsectively. In addition, you can see your
//! original query in the search result struct as well, so you can categorize multiple searches by
//! their query. While this is given as a regular field, note that modifying `query` will not
//! change what is searched for when you call `older` or `newer`; the `SearchResult` keeps its
//! search arguments in a separate private field.
//!
//! The search parameter given in the initial call to `search` has several options itself. A full
//! reference is available in [Twitter's Search API documentation][search-doc]. This listing by
//! itself does not include the search by Place ID, as mentioned on [a separate Tweets by Place
//! page][search-place]. A future version of egg-mode might break these options into further
//! methods on `SearchBuilder`.
//!
//! [search-doc]: https://dev.twitter.com/rest/public/search
//! [search-place]: https://dev.twitter.com/rest/public/search-by-place

use std::collections::HashMap;
use std::fmt;

use rustc_serialize::json;

use auth;
use error;
use error::Error::{InvalidResponse, MissingValue};
use links;
use tweet::Tweet;
use common::*;

///Begin setting up a tweet search with the given query.
pub fn search<'a>(query: &'a str) -> SearchBuilder<'a> {
    SearchBuilder {
        query: query,
        lang: None,
        result_type: None,
        count: None,
        until: None,
        geocode: None,
        since_id: None,
        max_id: None,
    }
}

///Represents what kind of tweets should be included in search results.
#[derive(Debug, Copy, Clone)]
pub enum ResultType {
    ///Return only the most recent tweets in the response.
    Recent,
    ///Return only the most popular tweets in the response.
    Popular,
    ///Include both popular and real-time results in the response.
    Mixed,
}

///Display impl that turns the variants into strings that can be used as search parameters.
impl fmt::Display for ResultType {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            ResultType::Recent => write!(f, "recent"),
            ResultType::Popular => write!(f, "popular"),
            ResultType::Mixed => write!(f, "mixed"),
        }
    }
}

///Represents a radius around a given location to return search results for.
pub enum Distance {
    ///A radius given in miles.
    Miles(u32),
    ///A radius given in kilometers.
    Kilometers(u32),
}

///Represents a tweet search query before being sent.
#[must_use = "SearchBuilder is lazy and won't do anything unless `call`ed"]
pub struct SearchBuilder<'a> {
    ///The text to search for.
    query: &'a str,
    lang: Option<&'a str>,
    result_type: Option<ResultType>,
    count: Option<u32>,
    until: Option<(u32, u32, u32)>,
    geocode: Option<(f32, f32, Distance)>,
    since_id: Option<u64>,
    max_id: Option<u64>,
}

impl<'a> SearchBuilder<'a> {
    ///Restrict search results to those that have been machine-parsed as the given two-letter
    ///language code.
    pub fn lang(self, lang: &'a str) -> Self {
        SearchBuilder {
            lang: Some(lang),
            ..self
        }
    }

    ///Specify the type of search results to include. The default is `Recent`.
    pub fn result_type(self, result_type: ResultType) -> Self {
        SearchBuilder {
            result_type: Some(result_type),
            ..self
        }
    }

    ///Set the number of tweets to return per-page, up to a maximum of 100. The default is 15.
    pub fn count(self, count: u32) -> Self {
        SearchBuilder {
            count: Some(count),
            ..self
        }
    }

    ///Returns tweets created before the given date. Keep in mind that search is limited to the
    ///last 7 days of results, so giving a date here that's older than a week will return no
    ///results.
    pub fn until(self, year: u32, month: u32, day: u32) -> Self {
        SearchBuilder {
            until: Some((year, month, day)),
            ..self
        }
    }

    ///Restricts results to users located within the given radius of the given coordinate. This is
    ///preferably populated from location-tagged tweets, but can be filled in from the user's
    ///profile as a fallback.
    pub fn geocode(self, latitude: f32, longitude: f32, radius: Distance) -> Self {
        SearchBuilder {
            geocode: Some((latitude, longitude, radius)),
            ..self
        }
    }

    ///Restricts results to those with higher IDs than (i.e. that were posted after) the given
    ///tweet ID.
    pub fn since_tweet(self, since_id: u64) -> Self {
        SearchBuilder {
            since_id: Some(since_id),
            ..self
        }
    }

    ///Restricts results to those with IDs no higher than (i.e. were posted earlier than) the given
    ///tweet ID. Will include the given tweet in search results.
    pub fn max_tweet(self, max_id: u64) -> Self {
        SearchBuilder {
            max_id: Some(max_id),
            ..self
        }
    }

    ///Finalize the search terms and return the first page of responses.
    pub fn call(self, token: &auth::Token) -> WebResponse<SearchResult<'a>> {
        let mut params = HashMap::new();

        add_param(&mut params, "q", self.query);

        if let Some(lang) = self.lang {
            add_param(&mut params, "lang", lang);
        }

        if let Some(result_type) = self.result_type {
            add_param(&mut params, "result_type", result_type.to_string());
        }

        if let Some(count) = self.count {
            add_param(&mut params, "count", count.to_string());
        }

        if let Some((year, month, day)) = self.until {
            add_param(&mut params, "until", format!("{}-{}-{}", year, month, day));
        }

        if let Some((lat, lon, radius)) = self.geocode {
            match radius {
                Distance::Miles(r) => add_param(&mut params, "geocode", format!("{:.6},{:.6},{}mi", lat, lon, r)),
                Distance::Kilometers(r) => add_param(&mut params, "geocode", format!("{:.6},{:.6},{}km", lat, lon, r)),
            };
        }

        if let Some(since_id) = self.since_id {
            add_param(&mut params, "since_id", since_id.to_string());
        }

        if let Some(max_id) = self.max_id {
            add_param(&mut params, "max_id", max_id.to_string());
        }

        let mut resp = try!(auth::get(links::statuses::SEARCH, token, Some(&params)));

        let mut ret: Response<SearchResult> = try!(parse_response(&mut resp));
        ret.params = Some(params);
        Ok(ret)
    }
}

///Represents a page of search results, along with metadata to request the next or previous page.
#[derive(Debug)]
pub struct SearchResult<'a> {
    ///The list of statuses in this page of results.
    pub statuses: Vec<Tweet>,
    ///The query used to generate this page of results. Note that changing this will not affect the
    ///`next_page` method.
    pub query: String,
    max_id: u64,
    since_id: u64,
    params: Option<ParamList<'a>>,
}

impl<'a> FromJson for SearchResult<'a> {
    fn from_json(input: &json::Json) -> Result<Self, error::Error> {
        if !input.is_object() {
            return Err(InvalidResponse("SearchResult received json that wasn't an object", Some(input.to_string())));
        }

        let metadata = try!(input.find("search_metadata").ok_or(MissingValue("search_metadata")));

        Ok(SearchResult {
            statuses: try!(field(input, "statuses")),
            query: try!(field(metadata, "query")),
            max_id: try!(field(metadata, "max_id")),
            since_id: try!(field(metadata, "since_id")),
            params: None,
        })
    }
}

impl<'a> SearchResult<'a> {
    ///Load the next page of search results for the same query.
    pub fn older(&self, token: &auth::Token) -> WebResponse<SearchResult> {
        let mut params = self.params.as_ref().cloned().unwrap_or_default();
        params.remove("since_id");

        if let Some(min_id) = self.statuses.iter().map(|t| t.id).min() {
            add_param(&mut params, "max_id", (min_id - 1).to_string());
        }
        else {
            params.remove("max_id");
        }

        let mut resp = try!(auth::get(links::statuses::SEARCH, token, Some(&params)));

        let mut ret: Response<SearchResult> = try!(parse_response(&mut resp));
        ret.params = Some(params);
        Ok(ret)
    }

    ///Load the previous page of search results for the same query.
    pub fn newer(&self, token: &auth::Token) -> WebResponse<SearchResult> {
        let mut params = self.params.as_ref().cloned().unwrap_or_default();
        params.remove("max_id");

        if let Some(max_id) = self.statuses.iter().map(|t| t.id).max() {
            add_param(&mut params, "since_id", max_id.to_string());
        }
        else {
            params.remove("since_id");
        }

        let mut resp = try!(auth::get(links::statuses::SEARCH, token, Some(&params)));

        let mut ret: Response<SearchResult> = try!(parse_response(&mut resp));
        ret.params = Some(params);
        Ok(ret)
    }
}
<commit_msg>Fix improper lifetime on SearchResult methods<commit_after>// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.

//! Structs and methods for searching for tweets.
//!
//! Since there are several optional parameters for searches, egg-mode handles it with a builder
//! pattern. To begin, call `search` with your requested search term. Additional parameters can be
//! added onto the `SearchBuilder` struct that is returned. When you're ready to load the first
//! page of results, hand your tokens to `call`.
//!
//! ```rust,no_run
//! # let token = egg_mode::Token::Access {
//! #     consumer: egg_mode::KeyPair::new("", ""),
//! #     access: egg_mode::KeyPair::new("", ""),
//! # };
//! use egg_mode::search::{self, ResultType};
//!
//! let search = search::search("rustlang")
//!                     .result_type(ResultType::Recent)
//!                     .call(&token)
//!                     .unwrap();
//!
//! for tweet in &search.statuses {
//!     println!("(@{}) {}", tweet.user.as_ref().unwrap().screen_name, tweet.text);
//! }
//! ```
//!
//! Once you have your `SearchResult`, you can navigate the search results by calling `older` and
//! `newer` to get the next and previous pages, respsectively. In addition, you can see your
//! original query in the search result struct as well, so you can categorize multiple searches by
//! their query. While this is given as a regular field, note that modifying `query` will not
//! change what is searched for when you call `older` or `newer`; the `SearchResult` keeps its
//! search arguments in a separate private field.
//!
//! The search parameter given in the initial call to `search` has several options itself. A full
//! reference is available in [Twitter's Search API documentation][search-doc]. This listing by
//! itself does not include the search by Place ID, as mentioned on [a separate Tweets by Place
//! page][search-place]. A future version of egg-mode might break these options into further
//! methods on `SearchBuilder`.
//!
//! [search-doc]: https://dev.twitter.com/rest/public/search
//! [search-place]: https://dev.twitter.com/rest/public/search-by-place

use std::collections::HashMap;
use std::fmt;

use rustc_serialize::json;

use auth;
use error;
use error::Error::{InvalidResponse, MissingValue};
use links;
use tweet::Tweet;
use common::*;

///Begin setting up a tweet search with the given query.
pub fn search<'a>(query: &'a str) -> SearchBuilder<'a> {
    SearchBuilder {
        query: query,
        lang: None,
        result_type: None,
        count: None,
        until: None,
        geocode: None,
        since_id: None,
        max_id: None,
    }
}

///Represents what kind of tweets should be included in search results.
#[derive(Debug, Copy, Clone)]
pub enum ResultType {
    ///Return only the most recent tweets in the response.
    Recent,
    ///Return only the most popular tweets in the response.
    Popular,
    ///Include both popular and real-time results in the response.
    Mixed,
}

///Display impl that turns the variants into strings that can be used as search parameters.
impl fmt::Display for ResultType {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            ResultType::Recent => write!(f, "recent"),
            ResultType::Popular => write!(f, "popular"),
            ResultType::Mixed => write!(f, "mixed"),
        }
    }
}

///Represents a radius around a given location to return search results for.
pub enum Distance {
    ///A radius given in miles.
    Miles(u32),
    ///A radius given in kilometers.
    Kilometers(u32),
}

///Represents a tweet search query before being sent.
#[must_use = "SearchBuilder is lazy and won't do anything unless `call`ed"]
pub struct SearchBuilder<'a> {
    ///The text to search for.
    query: &'a str,
    lang: Option<&'a str>,
    result_type: Option<ResultType>,
    count: Option<u32>,
    until: Option<(u32, u32, u32)>,
    geocode: Option<(f32, f32, Distance)>,
    since_id: Option<u64>,
    max_id: Option<u64>,
}

impl<'a> SearchBuilder<'a> {
    ///Restrict search results to those that have been machine-parsed as the given two-letter
    ///language code.
    pub fn lang(self, lang: &'a str) -> Self {
        SearchBuilder {
            lang: Some(lang),
            ..self
        }
    }

    ///Specify the type of search results to include. The default is `Recent`.
    pub fn result_type(self, result_type: ResultType) -> Self {
        SearchBuilder {
            result_type: Some(result_type),
            ..self
        }
    }

    ///Set the number of tweets to return per-page, up to a maximum of 100. The default is 15.
    pub fn count(self, count: u32) -> Self {
        SearchBuilder {
            count: Some(count),
            ..self
        }
    }

    ///Returns tweets created before the given date. Keep in mind that search is limited to the
    ///last 7 days of results, so giving a date here that's older than a week will return no
    ///results.
    pub fn until(self, year: u32, month: u32, day: u32) -> Self {
        SearchBuilder {
            until: Some((year, month, day)),
            ..self
        }
    }

    ///Restricts results to users located within the given radius of the given coordinate. This is
    ///preferably populated from location-tagged tweets, but can be filled in from the user's
    ///profile as a fallback.
    pub fn geocode(self, latitude: f32, longitude: f32, radius: Distance) -> Self {
        SearchBuilder {
            geocode: Some((latitude, longitude, radius)),
            ..self
        }
    }

    ///Restricts results to those with higher IDs than (i.e. that were posted after) the given
    ///tweet ID.
    pub fn since_tweet(self, since_id: u64) -> Self {
        SearchBuilder {
            since_id: Some(since_id),
            ..self
        }
    }

    ///Restricts results to those with IDs no higher than (i.e. were posted earlier than) the given
    ///tweet ID. Will include the given tweet in search results.
    pub fn max_tweet(self, max_id: u64) -> Self {
        SearchBuilder {
            max_id: Some(max_id),
            ..self
        }
    }

    ///Finalize the search terms and return the first page of responses.
    pub fn call(self, token: &auth::Token) -> WebResponse<SearchResult<'a>> {
        let mut params = HashMap::new();

        add_param(&mut params, "q", self.query);

        if let Some(lang) = self.lang {
            add_param(&mut params, "lang", lang);
        }

        if let Some(result_type) = self.result_type {
            add_param(&mut params, "result_type", result_type.to_string());
        }

        if let Some(count) = self.count {
            add_param(&mut params, "count", count.to_string());
        }

        if let Some((year, month, day)) = self.until {
            add_param(&mut params, "until", format!("{}-{}-{}", year, month, day));
        }

        if let Some((lat, lon, radius)) = self.geocode {
            match radius {
                Distance::Miles(r) => add_param(&mut params, "geocode", format!("{:.6},{:.6},{}mi", lat, lon, r)),
                Distance::Kilometers(r) => add_param(&mut params, "geocode", format!("{:.6},{:.6},{}km", lat, lon, r)),
            };
        }

        if let Some(since_id) = self.since_id {
            add_param(&mut params, "since_id", since_id.to_string());
        }

        if let Some(max_id) = self.max_id {
            add_param(&mut params, "max_id", max_id.to_string());
        }

        let mut resp = try!(auth::get(links::statuses::SEARCH, token, Some(&params)));

        let mut ret: Response<SearchResult> = try!(parse_response(&mut resp));
        ret.params = Some(params);
        Ok(ret)
    }
}

///Represents a page of search results, along with metadata to request the next or previous page.
#[derive(Debug)]
pub struct SearchResult<'a> {
    ///The list of statuses in this page of results.
    pub statuses: Vec<Tweet>,
    ///The query used to generate this page of results. Note that changing this will not affect the
    ///`next_page` method.
    pub query: String,
    max_id: u64,
    since_id: u64,
    params: Option<ParamList<'a>>,
}

impl<'a> FromJson for SearchResult<'a> {
    fn from_json(input: &json::Json) -> Result<Self, error::Error> {
        if !input.is_object() {
            return Err(InvalidResponse("SearchResult received json that wasn't an object", Some(input.to_string())));
        }

        let metadata = try!(input.find("search_metadata").ok_or(MissingValue("search_metadata")));

        Ok(SearchResult {
            statuses: try!(field(input, "statuses")),
            query: try!(field(metadata, "query")),
            max_id: try!(field(metadata, "max_id")),
            since_id: try!(field(metadata, "since_id")),
            params: None,
        })
    }
}

impl<'a> SearchResult<'a> {
    ///Load the next page of search results for the same query.
    pub fn older(&self, token: &auth::Token) -> WebResponse<SearchResult<'a>> {
        let mut params = self.params.as_ref().cloned().unwrap_or_default();
        params.remove("since_id");

        if let Some(min_id) = self.statuses.iter().map(|t| t.id).min() {
            add_param(&mut params, "max_id", (min_id - 1).to_string());
        }
        else {
            params.remove("max_id");
        }

        let mut resp = try!(auth::get(links::statuses::SEARCH, token, Some(&params)));

        let mut ret: Response<SearchResult> = try!(parse_response(&mut resp));
        ret.params = Some(params);
        Ok(ret)
    }

    ///Load the previous page of search results for the same query.
    pub fn newer(&self, token: &auth::Token) -> WebResponse<SearchResult<'a>> {
        let mut params = self.params.as_ref().cloned().unwrap_or_default();
        params.remove("max_id");

        if let Some(max_id) = self.statuses.iter().map(|t| t.id).max() {
            add_param(&mut params, "since_id", max_id.to_string());
        }
        else {
            params.remove("since_id");
        }

        let mut resp = try!(auth::get(links::statuses::SEARCH, token, Some(&params)));

        let mut ret: Response<SearchResult> = try!(parse_response(&mut resp));
        ret.params = Some(params);
        Ok(ret)
    }
}
<|endoftext|>


<commit_before>use std::io::Write;
use std::net::TcpStream;
use std::sync::mpsc::Sender;

use message::Message;
use roommap::{Room, RoomMap};
use usermap::UserMap;

pub struct Server {
    users: UserMap,
    rooms: RoomMap,
}

impl Server {
    pub fn new() -> Self {
        Server {
            users: UserMap::new(),
            rooms: RoomMap::new(),
        }
    }

    pub fn welcome_user(stream: TcpStream) {
        let mut stream = stream;
        let welcome_msg = "Please enter a username:\n".to_string();
        stream.write(&welcome_msg.into_bytes()).expect("Error writing to stream");
    }

    pub fn display_instructions(stream: TcpStream) {
        let mut stream = stream;
        let instructions = "Instructions: This will be filled in later\n".to_string();
        stream.write(&instructions.into_bytes()).expect("Error writing to stream");
    }

    /// Add user to server
    /// Fails if a user with the same name already exists
    /// Return boolean indicating success/failure
    pub fn add_user(&mut self, name: String) -> bool {
        if !self.users.contains_key(&name) {
            self.users.insert(name, 0);
            return true;
        }
        return false;
    }

    /// Send message to all users in the room that the sender is in
    pub fn send_message(&self, msg: Message) {
        if let Some(room) = self.rooms.get(&msg.room_id()) {
            let members = room.members();
            let output = msg.from().to_string() + ": " + msg.content() + "\n";
            for (name, sndr) in members {
                if name != msg.from() {
                    sndr.send(output.to_string()).unwrap();
                }
            }
        }
    }

    /// Add a user to a chatroom
    /// Fails if room_id is invalid
    /// Return boolean indicating success/failure
    pub fn join_room(&mut self, room_id: usize, user: String, sndr: Sender<String>) -> bool {
        if !self.rooms.contains_key(&room_id) {
            return false;
        }
        self.rooms.get_mut(&room_id).unwrap().add_member(user.to_string(), sndr);
        let room_name  = &self.rooms.get(&room_id).unwrap().name();
        let join_msg = user.to_string() + " has joined " + room_name;
        let msg = Message::new("Server".to_string(), room_id, join_msg);
        self.send_message(msg);
        true
    }

    /// Create a new chatroom
    /// Return room_id
    pub fn create_room(&mut self, room_name: String) -> usize {
        let room_id = self.rooms.len() + 1;
        self.rooms.insert(room_id, Room::new(room_name));
        room_id
    }

    /// Remove a user from a chatroom
    pub fn leave_room(&mut self, room_id: usize, user: String) {
        if let Some(room) = self.rooms.get_mut(&room_id) {
            room.remove_member(user);
        }
    }

    /// Write a list of the available chatrooms to a stream
    pub fn display_rooms(&self, stream: TcpStream) {
        let mut stream = stream;
        for (room_id, room) in &self.rooms {
            write!(stream, "{}: {}", room_id, room.name()).unwrap();
        }
    }
}<commit_msg>Better remove_member<commit_after>use std::io::Write;
use std::net::TcpStream;
use std::sync::mpsc::Sender;

use message::Message;
use roommap::{Room, RoomMap};
use usermap::UserMap;

pub struct Server {
    users: UserMap,
    rooms: RoomMap,
}

impl Server {
    pub fn new() -> Self {
        Server {
            users: UserMap::new(),
            rooms: RoomMap::new(),
        }
    }

    pub fn welcome_user(stream: TcpStream) {
        let mut stream = stream;
        let welcome_msg = "Please enter a username:\n".to_string();
        stream.write(&welcome_msg.into_bytes()).expect("Error writing to stream");
    }

    pub fn display_instructions(stream: TcpStream) {
        let mut stream = stream;
        let instructions = "Instructions: This will be filled in later\n".to_string();
        stream.write(&instructions.into_bytes()).expect("Error writing to stream");
    }

    /// Add user to server
    /// Fails if a user with the same name already exists
    /// Return boolean indicating success/failure
    pub fn add_user(&mut self, name: String) -> bool {
        if !self.users.contains_key(&name) {
            self.users.insert(name, 0);
            return true;
        }
        return false;
    }

    /// Send message to all users in the room that the sender is in
    pub fn send_message(&self, msg: Message) {
        if let Some(room) = self.rooms.get(&msg.room_id()) {
            let members = room.members();
            let output = msg.from().to_string() + ": " + msg.content() + "\n";
            for (name, sndr) in members {
                if name != msg.from() {
                    sndr.send(output.to_string()).unwrap();
                }
            }
        }
    }

    /// Create a new chatroom
    /// Return room_id
    pub fn create_room(&mut self, room_name: String) -> usize {
        let room_id = self.rooms.len() + 1;
        self.rooms.insert(room_id, Room::new(room_name));
        room_id
    }

    /// Add a user to a chatroom
    /// Fails if room_id is invalid
    /// Return boolean indicating success/failure
    pub fn join_room(&mut self, room_id: usize, user: String, sndr: Sender<String>) -> bool {
        if !self.rooms.contains_key(&room_id) {
            return false;
        }
        self.rooms.get_mut(&room_id).unwrap().add_member(user.to_string(), sndr);
        let room_name  = &self.rooms.get(&room_id).unwrap().name();
        let join_msg = user + " has joined " + room_name;
        let msg = Message::new("Server".to_string(), room_id, join_msg);
        self.send_message(msg);
        true
    }

    /// Remove a user from a chatroom
    pub fn leave_room(&mut self, room_id: usize, user: String) {
        if !self.rooms.contains_key(&room_id) {
            return;
        }
        self.rooms.get_mut(&room_id).unwrap().remove_member(user.to_string());
        let room_name  = &self.rooms.get(&room_id).unwrap().name();
        let leave_msg = user + " has left " + room_name;
        let msg = Message::new("Server".to_string(), room_id, leave_msg);
        self.send_message(msg);
    }

    /// Write a list of the available chatrooms to a stream
    pub fn display_rooms(&self, stream: TcpStream) {
        let mut stream = stream;
        for (room_id, room) in &self.rooms {
            write!(stream, "{}: {}", room_id, room.name()).unwrap();
        }
    }
}<|endoftext|>


<commit_before>// TODO: Implement a reader and writer from the client / server relationship.
// Then try and get clients to talk to everyone -> specific clients.
// Once that's done, move on to formatting messages via tokio::Encode / Decode.
// Example TCP

#[allow(unused_imports)]
use std::net::SocketAddr;
use std::io::{
    Error,
    ErrorKind,
    Write,
    Read
};
use std::str::{from_utf8};
use std::collections::{HashMap};
use std::rc::Rc;
use std::cell::RefCell;
use std::result::Result;

use futures::{
    Future,
};
use futures::stream::{Stream};
use futures::sync::*;

use tokio_core::io::{Io, ReadHalf, WriteHalf};
use tokio_core::net::{TcpListener, TcpStream};
use tokio_core::reactor::{Core, Handle};
// tokio::channel is deprecated

use client::TctClient;
use data::{Data, DataParser, UserID};

pub struct TctServer {
    clients: Rc<RefCell<HashMap<UserID, mpsc::UnboundedSender<Data>>>>,
    channel: (mpsc::UnboundedSender<Data>, mpsc::UnboundedReceiver<Data>),
    core: Core,
    addr: SocketAddr,
}

// Ixnay on the private client, defeats the purpose and actually breaks the design
// in the first place lulz.

impl TctServer {
    /// Creates a new TctServer to be run.
    pub fn new(addr: SocketAddr) -> TctServer {
        let core = Core::new().unwrap();
        TctServer {
            // Odd way of doing this but yeah, core needs to be defined after
            // channel.
            channel: mpsc::unbounded(),
            core: core,
            addr: addr,
            clients: Rc::new(RefCell::new(HashMap::new()))
        }
    }

    /// Execute the server, runs in foreground for any application...
    /// This is a temporary design to get something off the ground.
    pub fn run(&mut self) {
        let socket =
            TcpListener::bind(&self.addr, &self.core.handle().clone()).unwrap();
        let handle = self.core.handle();

        // For each incoming client connection at address 'addr'
        socket.incoming().for_each(|(stream, addr)| {

            let server_sender = self.channel.0.clone();

            let socket = TctClient::new(stream, addr).framed(DataParser);
            let (sender, receiver) = mpsc::unbounded();

            self.clients.borrow_mut().insert(addr.clone(), sender);

            let clients_inner = self.clients.clone();

            // Now this is a bit funky, but it's really just piping.
            // Messages get sent to online user, if user not found, sent to
            // server to be handled (check DB, if no -> send error).
            let socket = socket.for_each(|msg: Data| {
                let clients = clients_inner.clone();
                // How about just taking a random client for testing?
                // TODO: Unit test for the 'socket.for_each' functionality.
                if let Some(id) = msg.id() {
                    let mut clients = clients.borrow_mut();
                    clients.get(&id)
                                 .unwrap_or(&server_sender).send(msg); // panic?
                } else {
                    panic!("What do for error from client?");
                }
                Ok(())
            });
            // TODO what to do?

            Ok(())
        });
    }
}

<commit_msg>Readability for bug :/<commit_after>// TODO: Implement a reader and writer from the client / server relationship.
// Then try and get clients to talk to everyone -> specific clients.
// Once that's done, move on to formatting messages via tokio::Encode / Decode.
// Example TCP

#[allow(unused_imports)]
use std::net::SocketAddr;
use std::io::{
    Error,
    ErrorKind,
    Write,
    Read
};
use std::str::{from_utf8};
use std::collections::{HashMap};
use std::rc::Rc;
use std::cell::RefCell;
use std::result::Result;

use futures::{
    Future,
};
use futures::stream::{Stream};
use futures::sync::*;

use tokio_core::io::{Io, ReadHalf, WriteHalf};
use tokio_core::net::{TcpListener, TcpStream};
use tokio_core::reactor::{Core, Handle};
// tokio::channel is deprecated

use client::TctClient;
use data::{Data, DataParser, UserID};

pub struct TctServer {
    clients: Rc<RefCell<HashMap<UserID, mpsc::UnboundedSender<Data>>>>,
    channel: (mpsc::UnboundedSender<Data>, mpsc::UnboundedReceiver<Data>),
    core: Core,
    addr: SocketAddr,
}

// Ixnay on the private client, defeats the purpose and actually breaks the design
// in the first place lulz.

impl TctServer {
    /// Creates a new TctServer to be run.
    pub fn new(addr: SocketAddr) -> TctServer {
        let core = Core::new().unwrap();
        TctServer {
            // Odd way of doing this but yeah, core needs to be defined after
            // channel.
            channel: mpsc::unbounded(),
            core: core,
            addr: addr,
            clients: Rc::new(RefCell::new(HashMap::new()))
        }
    }

    /// Execute the server, runs in foreground for any application...
    /// This is a temporary design to get something off the ground.
    pub fn run(&mut self) {
        let socket =
            TcpListener::bind(&self.addr, &self.core.handle().clone()).unwrap();
        let handle = self.core.handle();

        // For each incoming client connection at address 'addr'
        socket.incoming().for_each(|(stream, addr)| {

            let server_sender = self.channel.0.clone();

            let socket = TctClient::new(stream, addr).framed(DataParser);
            let (sender, receiver) = mpsc::unbounded();

            self.clients.borrow_mut().insert(addr.clone(), sender);

            let clients_inner = self.clients.clone();

            // Now this is a bit funky, but it's really just piping.
            // Messages get sent to online user, if user not found, sent to
            // server to be handled (check DB, if no -> send error).
            let socket = socket.for_each(|msg: Data| {
                let clients = clients_inner.clone();
                // How about just taking a random client for testing?
                // TODO: Unit test for the 'socket.for_each' functionality.
                if let Some(id) = msg.id() {
                    clients.borrow().get(&id)
                                 .unwrap_or(&server_sender).send(msg); // panic?
                } else {
                    panic!("What do for error from client?");
                }
                Ok(())
            });
            // TODO what to do?

            Ok(())
        });
    }
}

<|endoftext|>


<commit_before>use cgmath::*;

pub const MATRIX_PROJ_VIEW_WORLD: usize = 0;
pub const MATRIX_WORLD: usize = 1;

pub const IN_VS_VEC_POS: usize = 0;
pub const IN_VS_VEC_NORM: usize = 4;
pub const IN_VS_VEC_NEG_LIGHT: usize = 8;

pub struct Shader {
    pub matrix_arr: [Matrix4<f32>; 2], // see MATRIX_*
    pub in_vertex_data: Vec<f32>,      // see IN_VS_*
    pub out_vertex_data: Vec<f32>,
    pub in_pixel_data: Vec<f32>,
    pub color: Vector3<f32>,           // {r, g, b}
    pub ambient_intensity: f32,        // [0; 1]
}

impl Shader {
    pub fn new(color: Vector3<f32>, ambient_intensity: f32) -> Shader {
        Shader {
            matrix_arr: [Matrix4::<f32>::zero(); 2],
            in_vertex_data: vec![0.0_f32; 12],
            out_vertex_data: vec![0.0_f32; 12],
            in_pixel_data: vec![0.0_f32; 12],
            color: color,
            ambient_intensity: ambient_intensity,
        }
    }

    pub fn set_matrix(&mut self, ind: usize, matrix: Matrix4<f32>) -> &mut Shader {
        self.matrix_arr[ind] = matrix;
        self
    }

    pub fn set_vec4(&mut self, sm: usize, vector: Vector4<f32>) -> &mut Shader {
        self.in_vertex_data[sm + 0] = vector.x;
        self.in_vertex_data[sm + 1] = vector.y;
        self.in_vertex_data[sm + 2] = vector.z;
        self.in_vertex_data[sm + 3] = vector.w;

        self
    }

    fn read_vec4(&self, sm: usize) -> Vector4<f32> {
        // Vector4::from_fixed_ref(self.in_vertex_data.slice(sm, sm+4))
        Vector4::new(self.in_vertex_data[sm + 0],
                     self.in_vertex_data[sm + 1],
                     self.in_vertex_data[sm + 2],
                     self.in_vertex_data[sm + 3])
    }

    // 0 - f32 cos_nl
    pub fn vertex(&mut self) -> (Vector4<f32>, usize) {
        let mut sm: usize = 0;
        let pos = self.matrix_arr[MATRIX_PROJ_VIEW_WORLD].mul_v(&self.read_vec4(IN_VS_VEC_POS));
        let norm = self.matrix_arr[MATRIX_WORLD].mul_v(&self.read_vec4(IN_VS_VEC_NORM)).normalize();

        self.out_vertex_data[sm] = norm.dot(&self.read_vec4(IN_VS_VEC_NEG_LIGHT));
        sm += 1;

        (pos, sm)
    }

    // 0 - f32 cos_nl
    pub fn pixel(&self) -> Vector3<f32> {
        let cos_nl = self.in_pixel_data[0];
        let color = self.color.mul_s(cos_nl.max(self.ambient_intensity));

        color
    }
}
<commit_msg>add phong-blinn shader<commit_after>use cgmath::*;

pub const MATRIX_PROJ_VIEW_WORLD: usize = 0;
pub const MATRIX_WORLD: usize = 1;

pub const IN_VS_VEC_POS: usize = 0;
pub const IN_VS_VEC_NORM: usize = 4;
pub const IN_VS_VEC_NEG_LIGHT: usize = 8;
pub const IN_VS_VEC_EYE_POS: usize = 12;

pub struct Shader {
    pub matrix_arr: [Matrix4<f32>; 2], // see MATRIX_*
    pub in_vertex_data: Vec<f32>,      // see IN_VS_*
    pub out_vertex_data: Vec<f32>,
    pub in_pixel_data: Vec<f32>,
    pub color: Vector3<f32>,           // {r, g, b}
    pub ambient_intensity: f32,        // [0; 1]
    pub vertex_out_len: usize,
    pub vertex_func: fn(&mut Shader) -> Vector4<f32>,
    pub pixel_func: fn(&Shader) -> Vector3<f32>,
}

impl Shader {
    pub fn new(color: Vector3<f32>, ambient_intensity: f32) -> Shader {
        Shader {
            matrix_arr: [Matrix4::<f32>::zero(); 2],
            in_vertex_data: vec![0.0_f32; 16],
            out_vertex_data: vec![0.0_f32; 16],
            in_pixel_data: vec![0.0_f32; 12],
            color: color,
            ambient_intensity: ambient_intensity,
            vertex_out_len: 0,
            vertex_func: Shader::vertex_def,
            pixel_func: Shader::pixel_def,
        }
    }

    pub fn reset(&mut self, position: Vector4<f32>, normal: Vector4<f32>) {
        self.vertex_out_len = 0;
        self.set_vec4(IN_VS_VEC_POS, position);
        self.set_vec4(IN_VS_VEC_NORM, normal);
    }

    pub fn set_shaders(&mut self,
                       vertex_func: fn(&mut Shader) -> Vector4<f32>,
                       pixel_func: fn(&Shader) -> Vector3<f32>) {
        self.vertex_func = vertex_func;
        self.pixel_func = pixel_func;
    }

    pub fn set_matrix(&mut self, ind: usize, matrix: Matrix4<f32>) {
        self.matrix_arr[ind] = matrix;
    }

    pub fn set_vec4(&mut self, sm: usize, vector: Vector4<f32>) {
        self.in_vertex_data[sm + 0] = vector.x;
        self.in_vertex_data[sm + 1] = vector.y;
        self.in_vertex_data[sm + 2] = vector.z;
        self.in_vertex_data[sm + 3] = vector.w;
    }

    fn read_vec4(&self, sm: usize) -> Vector4<f32> {
        // Vector4::from_fixed_ref(self.in_vertex_data.slice(sm, sm+4))
        Vector4::new(self.in_vertex_data[sm + 0],
                     self.in_vertex_data[sm + 1],
                     self.in_vertex_data[sm + 2],
                     self.in_vertex_data[sm + 3])
    }

    fn out_vec3(&mut self, val: &Vector3<f32>) {
        self.out_vertex_data[self.vertex_out_len + 0] = val.x;
        self.out_vertex_data[self.vertex_out_len + 1] = val.y;
        self.out_vertex_data[self.vertex_out_len + 2] = val.z;
        self.vertex_out_len += 3;
    }

    fn out_f32(&mut self, val: f32) {
        self.out_vertex_data[self.vertex_out_len] = val;
        self.vertex_out_len += 1;
    }

    // out:
    // 0 - Vector3 normal
    #[allow(dead_code)]
    pub fn vertex_normals(&mut self) -> Vector4<f32> {
        let pos = self.matrix_arr[MATRIX_PROJ_VIEW_WORLD].mul_v(&self.read_vec4(IN_VS_VEC_POS));
        let norm = self.matrix_arr[MATRIX_WORLD].mul_v(&self.read_vec4(IN_VS_VEC_NORM)).normalize();

        self.out_vec3(&Vector3::new(norm.x, norm.y, norm.z));
        pos
    }

    // in:
    // 0 - Vector3 normal
    #[allow(dead_code)]
    pub fn pixel_normals(&self) -> Vector3<f32> {
        let color = Vector3::new(self.in_pixel_data[0], self.in_pixel_data[1], self.in_pixel_data[2]).add_s(1.0_f32).mul_s(128.0_f32);

        color
    }

    // out:
    // 0 - f32 cos_nl
    #[allow(dead_code)]
    pub fn vertex_lambert(&mut self) -> Vector4<f32> {
        let pos = self.matrix_arr[MATRIX_PROJ_VIEW_WORLD].mul_v(&self.read_vec4(IN_VS_VEC_POS));
        let norm = self.matrix_arr[MATRIX_WORLD].mul_v(&self.read_vec4(IN_VS_VEC_NORM)).normalize();
        let cos_nl = norm.dot(&self.read_vec4(IN_VS_VEC_NEG_LIGHT));

        self.out_f32(cos_nl);
        pos
    }

    // in:
    // 0 - f32 cos_nl
    #[allow(dead_code)]
    pub fn pixel_lambert(&self) -> Vector3<f32> {
        let cos_nl = self.in_pixel_data[0];
        let color = self.color.mul_s(cos_nl.max(0.0_f32));

        color
    }

    // out:
    // 0 - Vector3 eye_vec
    // 3 - Vector3 norm
    #[allow(dead_code)]
    pub fn vertex_phong_blinn(&mut self) -> Vector4<f32> {
        let pos_pvw = self.matrix_arr[MATRIX_PROJ_VIEW_WORLD].mul_v(&self.read_vec4(IN_VS_VEC_POS));
        let pos_w = self.matrix_arr[MATRIX_WORLD].mul_v(&self.read_vec4(IN_VS_VEC_POS));
        let norm = self.matrix_arr[MATRIX_WORLD].mul_v(&self.read_vec4(IN_VS_VEC_NORM)).normalize();
        let eye_vec = self.read_vec4(IN_VS_VEC_EYE_POS).sub_v(&pos_w).normalize();

        self.out_vec3(&Vector3::new(eye_vec.x, eye_vec.y, eye_vec.z));
        self.out_vec3(&Vector3::new(norm.x, norm.y, norm.z));
        pos_pvw
    }

    // in:
    // 0 - Vector3 eye_vec
    // 3 - Vector3 norm
    #[allow(dead_code)]
    pub fn pixel_phong_blinn(&self) -> Vector3<f32> {
        let eye_vec = Vector3::new(self.in_pixel_data[0], self.in_pixel_data[1], self.in_pixel_data[2]).normalize();
        let norm = Vector3::new(self.in_pixel_data[3], self.in_pixel_data[4], self.in_pixel_data[5]).normalize();
        let light4 = self.read_vec4(IN_VS_VEC_NEG_LIGHT);
        let light = Vector3::new(light4.x, light4.y, light4.z);
        let half = eye_vec.add_v(&light).normalize();
        let cos_nh = norm.dot(&half);
        let cos_nl = norm.dot(&light);

        let spec_power = 50.0_f32;

        let diff = self.color.mul_s(cos_nl.max(0.0_f32));
        let spec = Vector3::new(255.0_f32, 255.0_f32, 255.0_f32).mul_s(cos_nh.max(0.0_f32).powf(spec_power) * 20.0_f32);

        diff + spec
    }

    // out:
    // 0 - f32 cos_nl
    pub fn vertex_def(&mut self) -> Vector4<f32> {
        let pos = self.matrix_arr[MATRIX_PROJ_VIEW_WORLD].mul_v(&self.read_vec4(IN_VS_VEC_POS));
        let norm = self.matrix_arr[MATRIX_WORLD].mul_v(&self.read_vec4(IN_VS_VEC_NORM)).normalize();
        let cos_nl = norm.dot(&self.read_vec4(IN_VS_VEC_NEG_LIGHT));

        self.out_f32(cos_nl);
        pos
    }

    // in:
    // 0 - f32 cos_nl
    pub fn pixel_def(&self) -> Vector3<f32> {
        let cos_nl = self.in_pixel_data[0];
        let color = self.color.mul_s(cos_nl.max(self.ambient_intensity));

        color
    }
}
<|endoftext|>


<commit_before>use std::ptr::null;
use std::num::zero;
use std::time::duration::Duration;
use std::default::Default;
use std::io::process::Process;
use libc::types::os::common::posix01::timespec;
use time::{Timespec, get_time};

pub use libc::consts::os::posix88::{SIGTERM, SIGINT, SIGQUIT};
use libc::{c_int, pid_t};

static SIGCHLD: c_int = 17;
static WNOHANG: c_int = 1;

#[deriving(Show)]
pub enum Signal {
    Terminate(int),  // Actual signal for termination: INT, TERM, QUIT...
    Child(pid_t, int),  //  pid and result code
    Reboot,
    Timeout,  // Not actually a OS signal, but it's a signal for our app
}

#[deriving(Default)]
#[repr(C)]
struct CSignalInfo {
    signo: c_int,
    pid: pid_t,
    status: c_int,
}

extern {
    fn block_all_signals();
    fn wait_any_signal(ptr: *mut CSignalInfo, timeout: *const timespec)
        -> c_int;
    fn waitpid(pid: pid_t, status: *mut c_int, options: c_int) -> pid_t;
}

pub fn block_all() {
    unsafe { block_all_signals() };
}

pub fn wait_next(reboot_supported: bool, timeout: Option<Timespec>) -> Signal {
    let mut status: i32 = 0;
    let pid = unsafe { waitpid(-1, &mut status, WNOHANG) };
    if pid > 0 {
        return Child(pid, status as int);
    }
    loop {
        let mut ptr = Default::default();
        let res = match timeout {
            Some(tm) => {
                let dur = tm - get_time();
                let c_dur = if dur < zero() {
                    timespec { tv_sec: 0, tv_nsec: 0 }
                } else {
                    timespec {
                        tv_sec: dur.num_seconds(),
                        tv_nsec: (dur - Duration::seconds(dur.num_seconds()))
                            .num_nanoseconds().unwrap(),
                    }
                };
                unsafe { wait_any_signal(&mut ptr, &c_dur) }
            }
            None => {
                unsafe { wait_any_signal(&mut ptr, null()) }
            }
        };
        if res != 0 {
            //  Any error is ok, because application should be always prepared
            //  for spurious timeouts
            //  only EAGAIN and EINTR expected
            return Timeout;
        }
        match ptr.signo {
            SIGCHLD => {
                unsafe { waitpid(ptr.pid, &mut status, WNOHANG) };
                assert_eq!(status, ptr.status);
                return Child(ptr.pid, ptr.status as int);
            }
            SIGQUIT if reboot_supported => {
                return Reboot;
            }
            sig@SIGTERM | sig@SIGINT | sig@SIGQUIT => {
                return Terminate(sig as int);
            }
            _ => continue,   // TODO(tailhook) improve logging
        }
    }
}

pub fn send_signal(pid: pid_t, sig: int) {
    Process::kill(pid, sig).ok();
}
<commit_msg>Fix status code conversions<commit_after>use std::ptr::null;
use std::num::zero;
use std::time::duration::Duration;
use std::default::Default;
use std::io::process::Process;
use libc::types::os::common::posix01::timespec;
use time::{Timespec, get_time};

pub use libc::consts::os::posix88::{SIGTERM, SIGINT, SIGQUIT, EINTR};
use libc::{c_int, pid_t};

static SIGCHLD: c_int = 17;
static WNOHANG: c_int = 1;

#[deriving(Show)]
pub enum Signal {
    Terminate(int),  // Actual signal for termination: INT, TERM, QUIT...
    Child(pid_t, int),  //  pid and result code
    Reboot,
    Timeout,  // Not actually a OS signal, but it's a signal for our app
}

#[deriving(Default)]
#[repr(C)]
struct CSignalInfo {
    signo: c_int,
    pid: pid_t,
    status: c_int,
}

extern {
    fn block_all_signals();
    fn wait_any_signal(ptr: *mut CSignalInfo, timeout: *const timespec)
        -> c_int;
    fn waitpid(pid: pid_t, status: *mut c_int, options: c_int) -> pid_t;
}

pub fn block_all() {
    unsafe { block_all_signals() };
}

fn _convert_status(status: i32) -> int {
    if status & 0xff == 0 {
        return ((status & 0xff00) >> 8) as int;
    }
    return (128 + (status & 0x7f)) as int;  // signal
}

pub fn wait_next(reboot_supported: bool, timeout: Option<Timespec>) -> Signal {
    let mut status: i32 = 0;
    let pid = unsafe { waitpid(-1, &mut status, WNOHANG) };
    if pid > 0 {
        return Child(pid, _convert_status(status));
    }
    loop {
        let mut ptr = Default::default();
        let res = match timeout {
            Some(tm) => {
                let dur = tm - get_time();
                let c_dur = if dur < zero() {
                    timespec { tv_sec: 0, tv_nsec: 0 }
                } else {
                    timespec {
                        tv_sec: dur.num_seconds(),
                        tv_nsec: (dur - Duration::seconds(dur.num_seconds()))
                            .num_nanoseconds().unwrap(),
                    }
                };
                unsafe { wait_any_signal(&mut ptr, &c_dur) }
            }
            None => {
                unsafe { wait_any_signal(&mut ptr, null()) }
            }
        };
        if res != 0 {
            //  Any error is ok, because application should be always prepared
            //  for spurious timeouts
            //  only EAGAIN and EINTR expected
            return Timeout;
        }
        match ptr.signo {
            SIGCHLD => {
                loop {
                    status = 0;
                    let rc = unsafe { waitpid(ptr.pid, &mut status, WNOHANG) };
                    if rc < 0 {
                        if rc == EINTR {
                            continue;
                        }
                        fail!("Failure {} not expected", rc);
                    }
                    assert_eq!(rc, ptr.pid);
                    break;
                }
                assert_eq!(_convert_status(status), ptr.status as int);
                return Child(ptr.pid, ptr.status as int);
            }
            SIGQUIT if reboot_supported => {
                return Reboot;
            }
            sig@SIGTERM | sig@SIGINT | sig@SIGQUIT => {
                return Terminate(sig as int);
            }
            _ => continue,   // TODO(tailhook) improve logging
        }
    }
}

pub fn send_signal(pid: pid_t, sig: int) {
    Process::kill(pid, sig).ok();
}
<|endoftext|>


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

#[macro_export]
macro_rules! connect {
    ($source:expr, $event:ident ( $($ident:pat),* ), $target:expr, $ty:ident :: $method:ident ( $($arg:expr),* )) => {
        let target = &mut *$target as *mut _;
        $source.$event(move |$($ident),*| {
            let target: &mut $ty = unsafe { &mut *target };
            target.$method($($arg),*)
        });
    };
    ($source:expr, $event:ident ( $($ident:pat),* ), $target:expr, $ty:ident :: $method:ident) => {
        let target = &mut *$target as *mut _;
        $source.$event(move |$($ident),*| {
            let target: &mut $ty = unsafe { &mut *target };
            target.$method()
        });
    };
    ($source:expr, $event:ident, $target:expr, $ty:ident :: $method:ident) => {
        let target = &mut *$target as *mut _;
        $source.$event(move || {
            let target: &mut $ty = unsafe { &mut *target };
            target.$method()
        });
    };
    ($source:expr, $event:ident ( $($ident:pat),* ), $target:expr, $method:ident ( $($arg:expr),* )) => {
        let target = &mut *$target as *mut _;
        $source.$event(move |$($ident),*| {
            let target: &mut Self = unsafe { &mut *target };
            target.$method($($arg),*)
        });
    };
    ($source:expr, $event:ident ( $($ident:pat),* ), $target:expr, $method:ident) => {
        let target = &mut *$target as *mut _;
        $source.$event(move |$($ident),*| {
            let target: &mut Self = unsafe { &mut *target };
            target.$method()
        });
    };
    ($source:expr, $event:ident, $target:expr, $method:ident) => {
        let target = &mut *$target as *mut _;
        $source.$event(move || {
            let target: &mut Self = unsafe { &mut *target };
            target.$method()
        });
    };
}
<commit_msg>Added additional parameter to the connect macro.<commit_after>/*
 * Copyright (c) 2016 Boucher, Antoni <bouanto@zoho.com>
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy of
 * this software and associated documentation files (the "Software"), to deal in
 * the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
 * the Software, and to permit persons to whom the Software is furnished to do so,
 * subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
 * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
 * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
 * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#[macro_export]
macro_rules! connect {
    ($source:expr, $event:ident $( [ $($param:expr),* ] )* ( $($ident:pat),* ), $target:expr, $ty:ident :: $method:ident ( $($arg:expr),* )) => {
        let target = &mut *$target as *mut _;
        $source.$event($($($param,)*)* move |$($ident),*| {
            let target: &mut $ty = unsafe { &mut *target };
            target.$method($($arg),*)
        });
    };
    ($source:expr, $event:ident $( [ $($param:expr),* ] )* ( $($ident:pat),* ), $target:expr, $ty:ident :: $method:ident) => {
        let target = &mut *$target as *mut _;
        $source.$event($($($param,)*)* move |$($ident),*| {
            let target: &mut $ty = unsafe { &mut *target };
            target.$method()
        });
    };
    ($source:expr, $event:ident $( [ $($param:expr),* ] )*, $target:expr, $ty:ident :: $method:ident) => {
        let target = &mut *$target as *mut _;
        $source.$event($($($param,)*)* move || {
            let target: &mut $ty = unsafe { &mut *target };
            target.$method()
        });
    };
    ($source:expr, $event:ident $( [ $($param:expr),* ] )* ( $($ident:pat),* ), $target:expr, $method:ident ( $($arg:expr),* )) => {
        let target = &mut *$target as *mut _;
        $source.$event($($($param,)*)* move |$($ident),*| {
            let target: &mut Self = unsafe { &mut *target };
            target.$method($($arg),*)
        });
    };
    ($source:expr, $event:ident $( [ $($param:expr),* ] )* ( $($ident:pat),* ), $target:expr, $method:ident) => {
        let target = &mut *$target as *mut _;
        $source.$event($($($param,)*)* move |$($ident),*| {
            let target: &mut Self = unsafe { &mut *target };
            target.$method()
        });
    };
    ($source:expr, $event:ident $( [ $($param:expr),* ] )*, $target:expr, $method:ident) => {
        let target = &mut *$target as *mut _;
        $source.$event($($($param,)*)* move || {
            let target: &mut Self = unsafe { &mut *target };
            target.$method()
        });
    };
}
<|endoftext|>


<commit_before>// Copyright 2013-2015, The Rust-GNOME Project Developers.
// See the COPYRIGHT file at the top-level directory of this distribution.
// Licensed under the MIT license, see the LICENSE file or <http://opensource.org/licenses/MIT>

//! Manages available sources of events for the main loop

use std::cell::RefCell;
use std::ops::DerefMut;
use std::mem::transmute;
use ffi::{gboolean, gpointer, g_idle_add_full, g_timeout_add_full, g_timeout_add_seconds_full};
use translate::ToGlib;

/// Return type of idle and timeout functions.
///
/// In the callback, return `Continue(true)` to continue scheduling the callback
/// in the main loop or `Continue(false)` to remove it from the main loop.
pub struct Continue(pub bool);

impl ToGlib for Continue {
    type GlibType = gboolean;

    #[inline]
    fn to_glib(&self) -> gboolean {
        self.0.to_glib()
    }
}

// Box::into_raw stability workaround
unsafe fn into_raw<T>(b: Box<T>) -> *mut T { transmute(b) }

extern "C" fn trampoline(func: &RefCell<Box<FnMut() -> Continue + 'static>>) -> gboolean {
    func.borrow_mut().deref_mut()().to_glib()
}

extern "C" fn destroy_closure(ptr: gpointer) {
    unsafe {
        // Box::from_raw API stability workaround
        let ptr = ptr as *mut RefCell<Box<FnMut() -> Continue + 'static>>;
        let _: Box<RefCell<Box<FnMut() -> Continue + 'static>>> = transmute(ptr);
    }
}

const PRIORITY_DEFAULT: i32 = 0;
const PRIORITY_DEFAULT_IDLE: i32 = 200;

/// Adds a function to be called whenever there are no higher priority events pending to the default main loop.
///
/// The function is given the default idle priority, `PRIORITY_DEFAULT_IDLE`.
/// If the function returns `Continue(false)` it is automatically removed from
/// the list of event sources and will not be called again.
///
/// # Examples
///
/// ```
/// let mut i = 0;
/// idle_add(move || {
///     println!("Idle: {}", i);
///     i += 1;
///     Continue(if i <= 10 { true } else { false })
/// });
/// ```
pub fn idle_add<F>(func: F) -> u32
    where F: FnMut() -> Continue + 'static {
    let f: Box<RefCell<Box<FnMut() -> Continue + 'static>>> = Box::new(RefCell::new(Box::new(func)));
    unsafe {
        g_idle_add_full(PRIORITY_DEFAULT_IDLE, transmute(trampoline),
            into_raw(f) as gpointer, destroy_closure)
    }
}

/// Sets a function to be called at regular intervals, with the default priority, `PRIORITY_DEFAULT`.
///
/// The function is called repeatedly until it returns `Continue(false)`, at which point the timeout is
/// automatically destroyed and the function will not be called again. The first call to the
/// function will be at the end of the first interval .
///
/// Note that timeout functions may be delayed, due to the processing of other event sources. Thus
/// they should not be relied on for precise timing. After each call to the timeout function, the
/// time of the next timeout is recalculated based on the current time and the given interval (it
/// does not try to 'catch up' time lost in delays).
///
/// If you want to have a timer in the "seconds" range and do not care about the exact time of the
/// first call of the timer, use the `timeout_add_seconds()` function; this function allows for more
/// optimizations and more efficient system power usage.
///
/// The interval given is in terms of monotonic time, not wall clock time.
/// See `g_get_monotonic_time()` in glib documentation.
///
/// # Examples
///
/// ```
/// timeout_add(3000, || {
///     println!("This prints once every 3 seconds");
///     Continue(true)
/// });
/// ```
pub fn timeout_add<F>(interval: u32, func: F) -> u32
    where F: FnMut() -> Continue + 'static {
    let f: Box<RefCell<Box<FnMut() -> Continue + 'static>>> = Box::new(RefCell::new(Box::new(func)));
    unsafe {
        g_timeout_add_full(PRIORITY_DEFAULT, interval, transmute(trampoline),
            into_raw(f) as gpointer, destroy_closure)
    }
}

/// Sets a function to be called at regular intervals with the default priority, `PRIORITY_DEFAULT`.
///
/// The function is called repeatedly until it returns `Continue(false)`, at which point the timeout
/// is automatically destroyed and the function will not be called again.
///
/// Note that the first call of the timer may not be precise for timeouts of one second. If you need
/// finer precision and have such a timeout, you may want to use `timeout_add()` instead.
///
/// The interval given is in terms of monotonic time, not wall clock time.
/// See `g_get_monotonic_time()` in glib documentation.
///
/// # Examples
///
/// ```
/// timeout_add_seconds(10, || {
///     println!("This prints once every 10 seconds");
///     Continue(true)
/// });
/// ```
pub fn timeout_add_seconds<F>(interval: u32, func: F) -> u32
    where F: FnMut() -> Continue + 'static {
    let f: Box<RefCell<Box<FnMut() -> Continue + 'static>>> = Box::new(RefCell::new(Box::new(func)));
    unsafe {
        g_timeout_add_seconds_full(PRIORITY_DEFAULT, interval, transmute(trampoline),
            into_raw(f) as gpointer, destroy_closure)
    }
}
<commit_msg>Source: Doc: ignore examples in test<commit_after>// Copyright 2013-2015, The Rust-GNOME Project Developers.
// See the COPYRIGHT file at the top-level directory of this distribution.
// Licensed under the MIT license, see the LICENSE file or <http://opensource.org/licenses/MIT>

//! Manages available sources of events for the main loop

use std::cell::RefCell;
use std::ops::DerefMut;
use std::mem::transmute;
use ffi::{gboolean, gpointer, g_idle_add_full, g_timeout_add_full, g_timeout_add_seconds_full};
use translate::ToGlib;

/// Return type of idle and timeout functions.
///
/// In the callback, return `Continue(true)` to continue scheduling the callback
/// in the main loop or `Continue(false)` to remove it from the main loop.
pub struct Continue(pub bool);

impl ToGlib for Continue {
    type GlibType = gboolean;

    #[inline]
    fn to_glib(&self) -> gboolean {
        self.0.to_glib()
    }
}

// Box::into_raw stability workaround
unsafe fn into_raw<T>(b: Box<T>) -> *mut T { transmute(b) }

extern "C" fn trampoline(func: &RefCell<Box<FnMut() -> Continue + 'static>>) -> gboolean {
    func.borrow_mut().deref_mut()().to_glib()
}

extern "C" fn destroy_closure(ptr: gpointer) {
    unsafe {
        // Box::from_raw API stability workaround
        let ptr = ptr as *mut RefCell<Box<FnMut() -> Continue + 'static>>;
        let _: Box<RefCell<Box<FnMut() -> Continue + 'static>>> = transmute(ptr);
    }
}

const PRIORITY_DEFAULT: i32 = 0;
const PRIORITY_DEFAULT_IDLE: i32 = 200;

/// Adds a function to be called whenever there are no higher priority events pending to the default main loop.
///
/// The function is given the default idle priority, `PRIORITY_DEFAULT_IDLE`.
/// If the function returns `Continue(false)` it is automatically removed from
/// the list of event sources and will not be called again.
///
/// # Examples
///
/// ```ignore
/// let mut i = 0;
/// idle_add(move || {
///     println!("Idle: {}", i);
///     i += 1;
///     Continue(if i <= 10 { true } else { false })
/// });
/// ```
pub fn idle_add<F>(func: F) -> u32
    where F: FnMut() -> Continue + 'static {
    let f: Box<RefCell<Box<FnMut() -> Continue + 'static>>> = Box::new(RefCell::new(Box::new(func)));
    unsafe {
        g_idle_add_full(PRIORITY_DEFAULT_IDLE, transmute(trampoline),
            into_raw(f) as gpointer, destroy_closure)
    }
}

/// Sets a function to be called at regular intervals, with the default priority, `PRIORITY_DEFAULT`.
///
/// The function is called repeatedly until it returns `Continue(false)`, at which point the timeout is
/// automatically destroyed and the function will not be called again. The first call to the
/// function will be at the end of the first interval .
///
/// Note that timeout functions may be delayed, due to the processing of other event sources. Thus
/// they should not be relied on for precise timing. After each call to the timeout function, the
/// time of the next timeout is recalculated based on the current time and the given interval (it
/// does not try to 'catch up' time lost in delays).
///
/// If you want to have a timer in the "seconds" range and do not care about the exact time of the
/// first call of the timer, use the `timeout_add_seconds()` function; this function allows for more
/// optimizations and more efficient system power usage.
///
/// The interval given is in terms of monotonic time, not wall clock time.
/// See `g_get_monotonic_time()` in glib documentation.
///
/// # Examples
///
/// ```ignore
/// timeout_add(3000, || {
///     println!("This prints once every 3 seconds");
///     Continue(true)
/// });
/// ```
pub fn timeout_add<F>(interval: u32, func: F) -> u32
    where F: FnMut() -> Continue + 'static {
    let f: Box<RefCell<Box<FnMut() -> Continue + 'static>>> = Box::new(RefCell::new(Box::new(func)));
    unsafe {
        g_timeout_add_full(PRIORITY_DEFAULT, interval, transmute(trampoline),
            into_raw(f) as gpointer, destroy_closure)
    }
}

/// Sets a function to be called at regular intervals with the default priority, `PRIORITY_DEFAULT`.
///
/// The function is called repeatedly until it returns `Continue(false)`, at which point the timeout
/// is automatically destroyed and the function will not be called again.
///
/// Note that the first call of the timer may not be precise for timeouts of one second. If you need
/// finer precision and have such a timeout, you may want to use `timeout_add()` instead.
///
/// The interval given is in terms of monotonic time, not wall clock time.
/// See `g_get_monotonic_time()` in glib documentation.
///
/// # Examples
///
/// ```ignore
/// timeout_add_seconds(10, || {
///     println!("This prints once every 10 seconds");
///     Continue(true)
/// });
/// ```
pub fn timeout_add_seconds<F>(interval: u32, func: F) -> u32
    where F: FnMut() -> Continue + 'static {
    let f: Box<RefCell<Box<FnMut() -> Continue + 'static>>> = Box::new(RefCell::new(Box::new(func)));
    unsafe {
        g_timeout_add_seconds_full(PRIORITY_DEFAULT, interval, transmute(trampoline),
            into_raw(f) as gpointer, destroy_closure)
    }
}
<|endoftext|>


<commit_before>extern crate libc;

use libc::{c_int, c_uchar};
use std::io::fs::PathExtensions;

#[link(name = "stb_truetype")]
extern { }

pub mod ffi {
    use libc::{c_int, c_uchar, c_float, c_void};
    use std::ptr;

    pub struct FontInfo {
       userdata: *const c_void,

       // pointer to .ttf file
       data: *const c_uchar,

       // offset of start of font
       fontstart: c_int,

       // number of glyphs, needed for range checking
       numGlyphs: c_int,

       // table locations as offset from start of .ttf
       loca: c_int,
       head: c_int,
       glyf: c_int,
       hhea: c_int,
       hmtx: c_int,
       kern: c_int,

       // a cmap mapping for our chosen character encoding
       index_map: c_int,

       // format needed to map from glyph index to glyph
       indexToLocFormat: c_int,
    }

    impl FontInfo {
        pub fn new() -> FontInfo {
            FontInfo {
                userdata: ptr::null(),
                data: ptr::null(),
                fontstart: 0,
                numGlyphs: 0,
                loca: 0,
                head: 0,
                glyf: 0,
                hhea: 0,
                hmtx: 0,
                kern: 0,
                index_map: 0,
                indexToLocFormat: 0,
            }
        }
    }

    extern {
        pub fn stbtt_GetFontOffsetForIndex(
            data: *const c_uchar,
            index: c_int,
        ) -> c_int;

        pub fn stbtt_InitFont(
            info: *mut FontInfo,
            data2: *const c_uchar,
            fontstart: c_int,
        );

        pub fn stbtt_GetFontVMetrics(
            info: *const FontInfo,
            ascent: *mut c_int,
            descent: *mut c_int,
            lineGap: *mut c_int,
        );

        pub fn stbtt_FindGlyphIndex(
            info: *const FontInfo,
            unicode_codepoint: c_int,
        ) -> c_int;

        pub fn stbtt_GetGlyphHMetrics(
            info: *const FontInfo,
            glyph_index: c_int,
            advanceWidth: *mut c_int,
            eftSideBearing: *mut c_int,
        );

        pub fn stbtt_GetGlyphBitmapBox(
            font: *const FontInfo,
            glyph: c_int,
            scale_x: c_float,
            scale_y: c_float,
            ix0: *mut c_int,
            iy0: *mut c_int,
            ix1: *mut c_int,
            iy1: *mut c_int,
        );

        pub fn stbtt_GetGlyphKernAdvance(
            info: *const FontInfo,
            glyph1: c_int,
            glyph2: c_int,
        );

        pub fn stbtt_MakeGlyphBitmap(
            info: *const FontInfo,
            output: *const c_uchar,
            out_w: c_int,
            out_h: c_int,
            out_stride: c_int,
            scale_x: c_float,
            scale_y: c_float,
            glyph: c_int,
        );

        pub fn stbtt_ScaleForPixelHeight(
            info: *const FontInfo,
            height: c_float,
        ) -> c_float;

        pub fn stbtt_GetGlyphBitmap(
            info: *const FontInfo,
            scale_x: c_float,
            scale_y: c_float,
            glyph: c_int,
            width: *mut c_int,
            height: *mut c_int,
            xoff: *mut c_int,
            yoff: *mut c_int,
        ) -> *const c_uchar;
    }
}

pub struct Font {
    font_info: ffi::FontInfo,
    data: Vec<c_uchar>,
    height: f32,
    scale: f32,
    ascent: i32,
    descent: i32,
    line_gap: i32,
}

impl Font {
    pub fn new(font_path: &Path, height: f32) -> Font {
        let data = {
            use std::io::{BufferedReader, File};
            if !font_path.exists() {
                fail!("Wrong font path: {}", font_path.display());
            }
            let file = File::open(font_path);
            let mut reader = BufferedReader::new(file);
            reader.read_to_end().unwrap()
        };
        let mut font_info = ffi::FontInfo::new();
        unsafe {
            let font_offset = ffi::stbtt_GetFontOffsetForIndex(&data[0] as *const u8, 0);
            ffi::stbtt_InitFont(&mut font_info, &data[0] as *const u8, font_offset);
        }
        let scale = unsafe {
            ffi::stbtt_ScaleForPixelHeight(&font_info, height)
        };
        let mut c_ascent: c_int = 0;
        let mut c_descent: c_int = 0;
        let mut c_line_gap: c_int = 0;
        unsafe {
            ffi::stbtt_GetFontVMetrics(&font_info,
                &mut c_ascent, &mut c_descent, &mut c_line_gap);
        }
        let ascent = (c_ascent as f32 * scale) as i32;
        let descent = (c_descent as f32 * scale) as i32;
        let line_gap = (c_line_gap as f32 * scale) as i32;
        Font {
            font_info: font_info,
            data: data,
            height: height,
            scale: scale,
            ascent: ascent,
            descent: descent,
            line_gap: line_gap,
        }
    }

    pub fn get_glyph(&self, glyph_index: i32) -> (Vec<c_uchar>, i32, i32, i32, i32) {
        use std::vec::raw::from_buf;
        let mut w = 0;
        let mut h = 0;
        let mut xoff = 0;
        let mut yoff = 0;
        let bitmap = unsafe {
            let scale_x = 0.0;
            let scale_y = self.scale;
            let buf = ffi::stbtt_GetGlyphBitmap(
                &self.font_info,
                scale_x,
                scale_y,
                glyph_index as c_int,
                &mut w,
                &mut h,
                &mut xoff,
                &mut yoff,
            );
            from_buf(buf, (w * h) as uint)
        };
        (bitmap, w as i32, h as i32, xoff as i32, yoff as i32)
    }

    pub fn find_glyph_index(&self, c: char) -> i32 {
        unsafe {
            ffi::stbtt_FindGlyphIndex(&self.font_info, c as c_int) as i32
        }
    }

    pub fn get_glyph_bitmap_box(&self, glyph_index: i32) -> (i32, i32, i32, i32) {
        let scale_x = 0.0;
        let scale_y = self.scale;
        let mut ix0 = 0;
        let mut iy0 = 0;
        let mut ix1 = 0;
        let mut iy1 = 0;
        unsafe {
            ffi::stbtt_GetGlyphBitmapBox(
                &self.font_info,
                glyph_index as c_int,
                scale_x,
                scale_y,
                &mut ix0,
                &mut iy0,
                &mut ix1,
                &mut iy1,
            );
        }
        (ix0 as i32, iy0 as i32, ix1 as i32, iy1 as i32)
    }
}

// vim: set tabstop=4 shiftwidth=4 softtabstop=4 expandtab:
<commit_msg>fail -> panic<commit_after>extern crate libc;

use libc::{c_int, c_uchar};
use std::io::fs::PathExtensions;

#[link(name = "stb_truetype")]
extern { }

pub mod ffi {
    use libc::{c_int, c_uchar, c_float, c_void};
    use std::ptr;

    pub struct FontInfo {
       userdata: *const c_void,

       // pointer to .ttf file
       data: *const c_uchar,

       // offset of start of font
       fontstart: c_int,

       // number of glyphs, needed for range checking
       numGlyphs: c_int,

       // table locations as offset from start of .ttf
       loca: c_int,
       head: c_int,
       glyf: c_int,
       hhea: c_int,
       hmtx: c_int,
       kern: c_int,

       // a cmap mapping for our chosen character encoding
       index_map: c_int,

       // format needed to map from glyph index to glyph
       indexToLocFormat: c_int,
    }

    impl FontInfo {
        pub fn new() -> FontInfo {
            FontInfo {
                userdata: ptr::null(),
                data: ptr::null(),
                fontstart: 0,
                numGlyphs: 0,
                loca: 0,
                head: 0,
                glyf: 0,
                hhea: 0,
                hmtx: 0,
                kern: 0,
                index_map: 0,
                indexToLocFormat: 0,
            }
        }
    }

    extern {
        pub fn stbtt_GetFontOffsetForIndex(
            data: *const c_uchar,
            index: c_int,
        ) -> c_int;

        pub fn stbtt_InitFont(
            info: *mut FontInfo,
            data2: *const c_uchar,
            fontstart: c_int,
        );

        pub fn stbtt_GetFontVMetrics(
            info: *const FontInfo,
            ascent: *mut c_int,
            descent: *mut c_int,
            lineGap: *mut c_int,
        );

        pub fn stbtt_FindGlyphIndex(
            info: *const FontInfo,
            unicode_codepoint: c_int,
        ) -> c_int;

        pub fn stbtt_GetGlyphHMetrics(
            info: *const FontInfo,
            glyph_index: c_int,
            advanceWidth: *mut c_int,
            eftSideBearing: *mut c_int,
        );

        pub fn stbtt_GetGlyphBitmapBox(
            font: *const FontInfo,
            glyph: c_int,
            scale_x: c_float,
            scale_y: c_float,
            ix0: *mut c_int,
            iy0: *mut c_int,
            ix1: *mut c_int,
            iy1: *mut c_int,
        );

        pub fn stbtt_GetGlyphKernAdvance(
            info: *const FontInfo,
            glyph1: c_int,
            glyph2: c_int,
        );

        pub fn stbtt_MakeGlyphBitmap(
            info: *const FontInfo,
            output: *const c_uchar,
            out_w: c_int,
            out_h: c_int,
            out_stride: c_int,
            scale_x: c_float,
            scale_y: c_float,
            glyph: c_int,
        );

        pub fn stbtt_ScaleForPixelHeight(
            info: *const FontInfo,
            height: c_float,
        ) -> c_float;

        pub fn stbtt_GetGlyphBitmap(
            info: *const FontInfo,
            scale_x: c_float,
            scale_y: c_float,
            glyph: c_int,
            width: *mut c_int,
            height: *mut c_int,
            xoff: *mut c_int,
            yoff: *mut c_int,
        ) -> *const c_uchar;
    }
}

pub struct Font {
    font_info: ffi::FontInfo,
    data: Vec<c_uchar>,
    height: f32,
    scale: f32,
    ascent: i32,
    descent: i32,
    line_gap: i32,
}

impl Font {
    pub fn new(font_path: &Path, height: f32) -> Font {
        let data = {
            use std::io::{BufferedReader, File};
            if !font_path.exists() {
                panic!("Wrong font path: {}", font_path.display());
            }
            let file = File::open(font_path);
            let mut reader = BufferedReader::new(file);
            reader.read_to_end().unwrap()
        };
        let mut font_info = ffi::FontInfo::new();
        unsafe {
            let font_offset = ffi::stbtt_GetFontOffsetForIndex(&data[0] as *const u8, 0);
            ffi::stbtt_InitFont(&mut font_info, &data[0] as *const u8, font_offset);
        }
        let scale = unsafe {
            ffi::stbtt_ScaleForPixelHeight(&font_info, height)
        };
        let mut c_ascent: c_int = 0;
        let mut c_descent: c_int = 0;
        let mut c_line_gap: c_int = 0;
        unsafe {
            ffi::stbtt_GetFontVMetrics(&font_info,
                &mut c_ascent, &mut c_descent, &mut c_line_gap);
        }
        let ascent = (c_ascent as f32 * scale) as i32;
        let descent = (c_descent as f32 * scale) as i32;
        let line_gap = (c_line_gap as f32 * scale) as i32;
        Font {
            font_info: font_info,
            data: data,
            height: height,
            scale: scale,
            ascent: ascent,
            descent: descent,
            line_gap: line_gap,
        }
    }

    pub fn get_glyph(&self, glyph_index: i32) -> (Vec<c_uchar>, i32, i32, i32, i32) {
        use std::vec::raw::from_buf;
        let mut w = 0;
        let mut h = 0;
        let mut xoff = 0;
        let mut yoff = 0;
        let bitmap = unsafe {
            let scale_x = 0.0;
            let scale_y = self.scale;
            let buf = ffi::stbtt_GetGlyphBitmap(
                &self.font_info,
                scale_x,
                scale_y,
                glyph_index as c_int,
                &mut w,
                &mut h,
                &mut xoff,
                &mut yoff,
            );
            from_buf(buf, (w * h) as uint)
        };
        (bitmap, w as i32, h as i32, xoff as i32, yoff as i32)
    }

    pub fn find_glyph_index(&self, c: char) -> i32 {
        unsafe {
            ffi::stbtt_FindGlyphIndex(&self.font_info, c as c_int) as i32
        }
    }

    pub fn get_glyph_bitmap_box(&self, glyph_index: i32) -> (i32, i32, i32, i32) {
        let scale_x = 0.0;
        let scale_y = self.scale;
        let mut ix0 = 0;
        let mut iy0 = 0;
        let mut ix1 = 0;
        let mut iy1 = 0;
        unsafe {
            ffi::stbtt_GetGlyphBitmapBox(
                &self.font_info,
                glyph_index as c_int,
                scale_x,
                scale_y,
                &mut ix0,
                &mut iy0,
                &mut ix1,
                &mut iy1,
            );
        }
        (ix0 as i32, iy0 as i32, ix1 as i32, iy1 as i32)
    }
}

// vim: set tabstop=4 shiftwidth=4 softtabstop=4 expandtab:
<|endoftext|>