<commit_before>use std::collections::HashMap;
use rustc_serialize::json;
use auth;
use user;
use error;
use error::Error::InvalidResponse;
use entities;
use common::*;

///Represents a single status update.
#[derive(Debug)]
pub struct Tweet {
    //If the user has contributors enabled, this will show which accounts contributed to this
    //tweet.
    //pub contributors: Option<Contributors>,
    //The location point attached to the tweet, if present.
    //pub coordinates: Option<Coordinates>,
    ///UTC timestamp showing when the tweet was posted, formatted like "Wed Aug 27 13:08:45 +0000
    ///2008".
    pub created_at: String,
    ///If the authenticated user has retweeted this tweet, contains the ID of the retweet.
    pub current_user_retweet: Option<i64>,
    ///Link, hashtag, and user mention information extracted from the tweet text.
    pub entities: TweetEntities,
    ///Extended media information attached to the tweet, if media is available.
    ///
    ///If a tweet has a photo, set of photos, gif, or video attached to it, this field will be
    ///present and contain the real media information. The information available in the `media`
    ///field of `entities` will only contain the first photo of a set, or a thumbnail of a gif or
    ///video.
    pub extended_entities: Option<ExtendedTweetEntities>,
    ///"Approximately" how many times this tweet has been liked by users.
    pub favorite_count: i32,
    ///Indicates whether the authenticated user has liked this tweet.
    pub favorited: Option<bool>,
    //Indicates the maximum `FilterLevel` parameter that can be applied to a stream and still show
    //this tweet.
    //pub filter_level: FilterLevel,
    ///Numeric ID for this tweet.
    pub id: i64,
    ///If the tweet is a reply, contains the ID of the user that was replied to.
    pub in_reply_to_user_id: Option<i64>,
    ///If the tweet is a reply, contains the screen name of the user that was replied to.
    pub in_reply_to_screen_name: Option<String>,
    ///If the tweet is a reply, contains the ID of the tweet that was replied to.
    pub in_reply_to_status_id: Option<i64>,
    ///Can contain a language ID indicating the machine-detected language of the text, or "und" if
    ///no language could be detected.
    pub lang: String,
    //TODO: Is this the user-entered location field?
    //When present, the `Place` that this tweet is associated with (but not necessarily where it
    //originated from).
    //pub place: Option<Place>,
    ///If the tweet has a link, indicates whether the link may contain content that could be
    ///identified as sensitive.
    pub possibly_sensitive: Option<bool>,
    ///If this tweet is quoting another by link, contains the ID of the quoted tweet.
    pub quoted_status_id: Option<i64>,
    ///If this tweet is quoting another by link, contains the quoted tweet.
    pub quoted_status: Option<Box<Tweet>>,
    //"A set of key-value pairs indicating the intended contextual delivery of the containing
    //Tweet. Currently used by Twitter’s Promoted Products."
    //pub scopes: Option<Scopes>,
    ///The number of times this tweet has been retweeted (with native retweets).
    pub retweet_count: i32,
    ///Indicates whether the authenticated user has retweeted this tweet.
    pub retweeted: Option<bool>,
    ///If this tweet is a retweet, then this field contains the original status information.
    ///
    ///The separation between retweet and original is so that retweets can be recalled by deleting
    ///the retweet, and so that liking a retweet results in an additional notification to the user
    ///who retweeted the status, as well as the original poster.
    pub retweeted_status: Option<Box<Tweet>>,
    ///The application used to post the tweet, as an HTML anchor tag containing the app's URL and
    ///name.
    pub source: String, //TODO: this is html, i want to parse this eventually
    ///The text of the tweet.
    pub text: String,
    ///The user who posted this tweet.
    pub user: Box<user::TwitterUser>,
    ///If present and `true`, indicates that this tweet has been withheld due to a DMCA complaint.
    pub withheld_copyright: bool,
    ///If present, contains two-letter country codes indicating where this tweet is being withheld.
    ///
    ///The following special codes exist:
    ///
    ///- `XX`: Withheld in all countries
    ///- `XY`: Withheld due to DMCA complaint.
    pub withheld_in_countries: Option<Vec<String>>,
    ///If present, indicates whether the content being withheld is the `status` or the `user`.
    pub withheld_scope: Option<String>,
}

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

        Ok(Tweet {
            //contributors: Option<Contributors>,
            //coordinates: Option<Coordinates>,
            created_at: try!(field(input, "created_at")),
            current_user_retweet: try!(current_user_retweet(input, "current_user_retweet")),
            entities: try!(field(input, "entities")),
            extended_entities: field(input, "extended_entities").ok(),
            favorite_count: field(input, "favorite_count").unwrap_or(0),
            favorited: field(input, "favorited").ok(),
            //filter_level: FilterLevel,
            id: try!(field(input, "id")),
            in_reply_to_user_id: field(input, "in_reply_to_user_id").ok(),
            in_reply_to_screen_name: field(input, "in_reply_to_screen_name").ok(),
            in_reply_to_status_id: field(input, "in_reply_to_status_id").ok(),
            lang: try!(field(input, "lang")),
            //place: Option<Place>,
            possibly_sensitive: field(input, "possibly_sensitive").ok(),
            quoted_status_id: field(input, "quoted_status_id").ok(),
            quoted_status: field(input, "quoted_status").map(Box::new).ok(),
            //scopes: Option<Scopes>,
            retweet_count: try!(field(input, "retweet_count")),
            retweeted: field(input, "retweeted").ok(),
            retweeted_status: field(input, "retweeted_status").map(Box::new).ok(),
            source: try!(field(input, "source")),
            text: try!(field(input, "text")),
            user: try!(field(input, "user").map(Box::new)),
            withheld_copyright: field(input, "withheld_copyright").unwrap_or(false),
            withheld_in_countries: field(input, "withheld_in_countries").ok(),
            withheld_scope: field(input, "withheld_scope").ok(),
        })
    }
}

fn current_user_retweet(input: &json::Json, field: &'static str) -> Result<Option<i64>, error::Error> {
    if let Some(obj) = input.find(field).and_then(|f| f.as_object()) {
        match obj.get("id").and_then(|o| o.as_i64()) {
            Some(id) => Ok(Some(id)),
            None => Err(InvalidResponse("invalid structure inside current_user_retweet", None)),
        }
    }
    else {
        Ok(None)
    }
}

///Container for URL, hashtag, mention, and media information associated with a tweet.
#[derive(Debug)]
pub struct TweetEntities {
    ///Collection of hashtags parsed from the tweet.
    pub hashtags: Vec<entities::HashtagEntity>,
    ///Collection of financial symbols, or "cashtags", parsed from the tweet.
    pub symbols: Vec<entities::HashtagEntity>,
    ///Collection of URLs parsed from the tweet.
    pub urls: Vec<entities::UrlEntity>,
    ///Collection of user mentions parsed from the tweet.
    pub user_mentions: Vec<entities::MentionEntity>,
    ///If the tweet contains any attached media, this contains a collection of media information
    ///from the tweet.
    pub media: Option<Vec<entities::MediaEntity>>,
}

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

        Ok(TweetEntities {
            hashtags: try!(field(input, "hashtags")),
            symbols: try!(field(input, "symbols")),
            urls: try!(field(input, "urls")),
            user_mentions: try!(field(input, "user_mentions")),
            media: field(input, "media").ok(),
        })
    }
}

///Container for extended media information for a tweet.
///
///If a tweet has a photo, set of photos, gif, or video attached to it, this field will be present
///and contain the real media information. The information available in the `media` field of
///`entities` will only contain the first photo of a set, or a thumbnail of a gif or video.
#[derive(Debug)]
pub struct ExtendedTweetEntities {
    ///Collection of extended media information attached to the tweet.
    pub media: Vec<entities::MediaEntity>,
}

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

        Ok(ExtendedTweetEntities {
            media: try!(field(input, "media")),
        })
    }
}

///Helper struct to navigate collections of tweets by requesting tweets older or newer than certain
///IDs.
pub struct Timeline<'a> {
    ///The URL to request tweets from.
    link: &'static str,
    ///The consumer token to authenticate requests with.
    con_token: &'a auth::Token<'a>,
    ///The access token to authenticate requests with.
    access_token: &'a auth::Token<'a>,
    ///The maximum number of tweets to return in a single call. Twitter doesn't guarantee returning
    ///exactly this number, as suspended or deleted content is removed after retrieving the initial
    ///collection of tweets.
    pub count: i32,
    ///The largest/most recent tweet ID returned in the last call to `start`, `older`, or `newer`.
    pub max_id: Option<i64>,
    ///The smalles/oldest tweet ID returned in the last call to `start`, `older`, or `newer`.
    pub min_id: Option<i64>,
}

impl<'a> Timeline<'a> {
    ///Clear the saved IDs on this timeline, and return the most recent set of tweets.
    pub fn start(&mut self) -> WebResponse<Vec<Tweet>> {
        self.max_id = None;
        self.min_id = None;

        self.older(None)
    }

    ///Return the set of tweets older than the last set pulled, optionally placing a minimum tweet
    ///ID to bound with.
    pub fn older(&mut self, since_id: Option<i64>) -> WebResponse<Vec<Tweet>> {
        let resp = try!(self.call(since_id, self.min_id.map(|id| id - 1)));

        self.map_ids(&resp.response);

        Ok(resp)
    }

    ///Return the set of tweets newer than the last set pulled, optionall placing a maximum tweet
    ///ID to bound with.
    pub fn newer(&mut self, max_id: Option<i64>) -> WebResponse<Vec<Tweet>> {
        let resp = try!(self.call(self.max_id, max_id));

        self.map_ids(&resp.response);

        Ok(resp)
    }

    ///Return the set of tweets between the IDs given.
    ///
    ///Note that the range is not fully inclusive; the tweet ID given by `since_id` will not be
    ///returned, but the tweet ID in `max_id` will be returned.
    ///
    ///If the range of tweets given by the IDs would return more than `self.count`, the newest set
    ///of tweets will be returned.
    pub fn call(&self, since_id: Option<i64>, max_id: Option<i64>) -> WebResponse<Vec<Tweet>> {
        let mut params = HashMap::new();
        add_param(&mut params, "count", self.count.to_string());

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

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

        let mut resp = try!(auth::get(self.link, self.con_token, self.access_token, Some(&params)));

        parse_response(&mut resp)
    }

    ///Helper builder function to set the page size.
    pub fn with_page_size(self, page_size: i32) -> Self {
        Timeline {
            link: self.link,
            con_token: self.con_token,
            access_token: self.access_token,
            count: page_size,
            max_id: self.max_id,
            min_id: self.min_id,
        }
    }

    ///With the returned slice of Tweets, set the min_id and max_id on self.
    fn map_ids(&mut self, resp: &[Tweet]) {
        self.max_id = resp.first().map(|status| status.id);
        self.min_id = resp.last().map(|status| status.id);
    }

    ///Create an instance of `Timeline` with the given link and tokens.
    pub fn new(link: &'static str, con_token: &'a auth::Token, access_token: &'a auth::Token) -> Self {
        Timeline {
            link: link,
            con_token: con_token,
            access_token: access_token,
            count: 20,
            max_id: None,
            min_id: None,
        }
    }
}
<commit_msg>typo fix<commit_after>use std::collections::HashMap;
use rustc_serialize::json;
use auth;
use user;
use error;
use error::Error::InvalidResponse;
use entities;
use common::*;

///Represents a single status update.
#[derive(Debug)]
pub struct Tweet {
    //If the user has contributors enabled, this will show which accounts contributed to this
    //tweet.
    //pub contributors: Option<Contributors>,
    //The location point attached to the tweet, if present.
    //pub coordinates: Option<Coordinates>,
    ///UTC timestamp showing when the tweet was posted, formatted like "Wed Aug 27 13:08:45 +0000
    ///2008".
    pub created_at: String,
    ///If the authenticated user has retweeted this tweet, contains the ID of the retweet.
    pub current_user_retweet: Option<i64>,
    ///Link, hashtag, and user mention information extracted from the tweet text.
    pub entities: TweetEntities,
    ///Extended media information attached to the tweet, if media is available.
    ///
    ///If a tweet has a photo, set of photos, gif, or video attached to it, this field will be
    ///present and contain the real media information. The information available in the `media`
    ///field of `entities` will only contain the first photo of a set, or a thumbnail of a gif or
    ///video.
    pub extended_entities: Option<ExtendedTweetEntities>,
    ///"Approximately" how many times this tweet has been liked by users.
    pub favorite_count: i32,
    ///Indicates whether the authenticated user has liked this tweet.
    pub favorited: Option<bool>,
    //Indicates the maximum `FilterLevel` parameter that can be applied to a stream and still show
    //this tweet.
    //pub filter_level: FilterLevel,
    ///Numeric ID for this tweet.
    pub id: i64,
    ///If the tweet is a reply, contains the ID of the user that was replied to.
    pub in_reply_to_user_id: Option<i64>,
    ///If the tweet is a reply, contains the screen name of the user that was replied to.
    pub in_reply_to_screen_name: Option<String>,
    ///If the tweet is a reply, contains the ID of the tweet that was replied to.
    pub in_reply_to_status_id: Option<i64>,
    ///Can contain a language ID indicating the machine-detected language of the text, or "und" if
    ///no language could be detected.
    pub lang: String,
    //TODO: Is this the user-entered location field?
    //When present, the `Place` that this tweet is associated with (but not necessarily where it
    //originated from).
    //pub place: Option<Place>,
    ///If the tweet has a link, indicates whether the link may contain content that could be
    ///identified as sensitive.
    pub possibly_sensitive: Option<bool>,
    ///If this tweet is quoting another by link, contains the ID of the quoted tweet.
    pub quoted_status_id: Option<i64>,
    ///If this tweet is quoting another by link, contains the quoted tweet.
    pub quoted_status: Option<Box<Tweet>>,
    //"A set of key-value pairs indicating the intended contextual delivery of the containing
    //Tweet. Currently used by Twitter’s Promoted Products."
    //pub scopes: Option<Scopes>,
    ///The number of times this tweet has been retweeted (with native retweets).
    pub retweet_count: i32,
    ///Indicates whether the authenticated user has retweeted this tweet.
    pub retweeted: Option<bool>,
    ///If this tweet is a retweet, then this field contains the original status information.
    ///
    ///The separation between retweet and original is so that retweets can be recalled by deleting
    ///the retweet, and so that liking a retweet results in an additional notification to the user
    ///who retweeted the status, as well as the original poster.
    pub retweeted_status: Option<Box<Tweet>>,
    ///The application used to post the tweet, as an HTML anchor tag containing the app's URL and
    ///name.
    pub source: String, //TODO: this is html, i want to parse this eventually
    ///The text of the tweet.
    pub text: String,
    ///The user who posted this tweet.
    pub user: Box<user::TwitterUser>,
    ///If present and `true`, indicates that this tweet has been withheld due to a DMCA complaint.
    pub withheld_copyright: bool,
    ///If present, contains two-letter country codes indicating where this tweet is being withheld.
    ///
    ///The following special codes exist:
    ///
    ///- `XX`: Withheld in all countries
    ///- `XY`: Withheld due to DMCA complaint.
    pub withheld_in_countries: Option<Vec<String>>,
    ///If present, indicates whether the content being withheld is the `status` or the `user`.
    pub withheld_scope: Option<String>,
}

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

        Ok(Tweet {
            //contributors: Option<Contributors>,
            //coordinates: Option<Coordinates>,
            created_at: try!(field(input, "created_at")),
            current_user_retweet: try!(current_user_retweet(input, "current_user_retweet")),
            entities: try!(field(input, "entities")),
            extended_entities: field(input, "extended_entities").ok(),
            favorite_count: field(input, "favorite_count").unwrap_or(0),
            favorited: field(input, "favorited").ok(),
            //filter_level: FilterLevel,
            id: try!(field(input, "id")),
            in_reply_to_user_id: field(input, "in_reply_to_user_id").ok(),
            in_reply_to_screen_name: field(input, "in_reply_to_screen_name").ok(),
            in_reply_to_status_id: field(input, "in_reply_to_status_id").ok(),
            lang: try!(field(input, "lang")),
            //place: Option<Place>,
            possibly_sensitive: field(input, "possibly_sensitive").ok(),
            quoted_status_id: field(input, "quoted_status_id").ok(),
            quoted_status: field(input, "quoted_status").map(Box::new).ok(),
            //scopes: Option<Scopes>,
            retweet_count: try!(field(input, "retweet_count")),
            retweeted: field(input, "retweeted").ok(),
            retweeted_status: field(input, "retweeted_status").map(Box::new).ok(),
            source: try!(field(input, "source")),
            text: try!(field(input, "text")),
            user: try!(field(input, "user").map(Box::new)),
            withheld_copyright: field(input, "withheld_copyright").unwrap_or(false),
            withheld_in_countries: field(input, "withheld_in_countries").ok(),
            withheld_scope: field(input, "withheld_scope").ok(),
        })
    }
}

fn current_user_retweet(input: &json::Json, field: &'static str) -> Result<Option<i64>, error::Error> {
    if let Some(obj) = input.find(field).and_then(|f| f.as_object()) {
        match obj.get("id").and_then(|o| o.as_i64()) {
            Some(id) => Ok(Some(id)),
            None => Err(InvalidResponse("invalid structure inside current_user_retweet", None)),
        }
    }
    else {
        Ok(None)
    }
}

///Container for URL, hashtag, mention, and media information associated with a tweet.
#[derive(Debug)]
pub struct TweetEntities {
    ///Collection of hashtags parsed from the tweet.
    pub hashtags: Vec<entities::HashtagEntity>,
    ///Collection of financial symbols, or "cashtags", parsed from the tweet.
    pub symbols: Vec<entities::HashtagEntity>,
    ///Collection of URLs parsed from the tweet.
    pub urls: Vec<entities::UrlEntity>,
    ///Collection of user mentions parsed from the tweet.
    pub user_mentions: Vec<entities::MentionEntity>,
    ///If the tweet contains any attached media, this contains a collection of media information
    ///from the tweet.
    pub media: Option<Vec<entities::MediaEntity>>,
}

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

        Ok(TweetEntities {
            hashtags: try!(field(input, "hashtags")),
            symbols: try!(field(input, "symbols")),
            urls: try!(field(input, "urls")),
            user_mentions: try!(field(input, "user_mentions")),
            media: field(input, "media").ok(),
        })
    }
}

///Container for extended media information for a tweet.
///
///If a tweet has a photo, set of photos, gif, or video attached to it, this field will be present
///and contain the real media information. The information available in the `media` field of
///`entities` will only contain the first photo of a set, or a thumbnail of a gif or video.
#[derive(Debug)]
pub struct ExtendedTweetEntities {
    ///Collection of extended media information attached to the tweet.
    pub media: Vec<entities::MediaEntity>,
}

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

        Ok(ExtendedTweetEntities {
            media: try!(field(input, "media")),
        })
    }
}

///Helper struct to navigate collections of tweets by requesting tweets older or newer than certain
///IDs.
pub struct Timeline<'a> {
    ///The URL to request tweets from.
    link: &'static str,
    ///The consumer token to authenticate requests with.
    con_token: &'a auth::Token<'a>,
    ///The access token to authenticate requests with.
    access_token: &'a auth::Token<'a>,
    ///The maximum number of tweets to return in a single call. Twitter doesn't guarantee returning
    ///exactly this number, as suspended or deleted content is removed after retrieving the initial
    ///collection of tweets.
    pub count: i32,
    ///The largest/most recent tweet ID returned in the last call to `start`, `older`, or `newer`.
    pub max_id: Option<i64>,
    ///The smallest/oldest tweet ID returned in the last call to `start`, `older`, or `newer`.
    pub min_id: Option<i64>,
}

impl<'a> Timeline<'a> {
    ///Clear the saved IDs on this timeline, and return the most recent set of tweets.
    pub fn start(&mut self) -> WebResponse<Vec<Tweet>> {
        self.max_id = None;
        self.min_id = None;

        self.older(None)
    }

    ///Return the set of tweets older than the last set pulled, optionally placing a minimum tweet
    ///ID to bound with.
    pub fn older(&mut self, since_id: Option<i64>) -> WebResponse<Vec<Tweet>> {
        let resp = try!(self.call(since_id, self.min_id.map(|id| id - 1)));

        self.map_ids(&resp.response);

        Ok(resp)
    }

    ///Return the set of tweets newer than the last set pulled, optionall placing a maximum tweet
    ///ID to bound with.
    pub fn newer(&mut self, max_id: Option<i64>) -> WebResponse<Vec<Tweet>> {
        let resp = try!(self.call(self.max_id, max_id));

        self.map_ids(&resp.response);

        Ok(resp)
    }

    ///Return the set of tweets between the IDs given.
    ///
    ///Note that the range is not fully inclusive; the tweet ID given by `since_id` will not be
    ///returned, but the tweet ID in `max_id` will be returned.
    ///
    ///If the range of tweets given by the IDs would return more than `self.count`, the newest set
    ///of tweets will be returned.
    pub fn call(&self, since_id: Option<i64>, max_id: Option<i64>) -> WebResponse<Vec<Tweet>> {
        let mut params = HashMap::new();
        add_param(&mut params, "count", self.count.to_string());

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

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

        let mut resp = try!(auth::get(self.link, self.con_token, self.access_token, Some(&params)));

        parse_response(&mut resp)
    }

    ///Helper builder function to set the page size.
    pub fn with_page_size(self, page_size: i32) -> Self {
        Timeline {
            link: self.link,
            con_token: self.con_token,
            access_token: self.access_token,
            count: page_size,
            max_id: self.max_id,
            min_id: self.min_id,
        }
    }

    ///With the returned slice of Tweets, set the min_id and max_id on self.
    fn map_ids(&mut self, resp: &[Tweet]) {
        self.max_id = resp.first().map(|status| status.id);
        self.min_id = resp.last().map(|status| status.id);
    }

    ///Create an instance of `Timeline` with the given link and tokens.
    pub fn new(link: &'static str, con_token: &'a auth::Token, access_token: &'a auth::Token) -> Self {
        Timeline {
            link: link,
            con_token: con_token,
            access_token: access_token,
            count: 20,
            max_id: None,
            min_id: None,
        }
    }
}
<|endoftext|>


<commit_before>//! SIMD and vendor intrinsics support library.
//!
//! This crate defines the vendor intrinsics and types primarily used for SIMD
//! in Rust. The crate here will soon be available in the standard library, but
//! for now you can also browse the documentation here, primarily in the `arch`
//! submodule.
//!
//! [stdsimd]: https://rust-lang-nursery.github.io/stdsimd/x86_64/stdsimd/

#![feature(const_fn, integer_atomics, staged_api, stdsimd)]
#![feature(cfg_target_feature, doc_cfg)]
#![cfg_attr(feature = "cargo-clippy", allow(shadow_reuse))]
#![cfg_attr(target_os = "linux", feature(linkage))]
#![no_std]
#![unstable(feature = "stdsimd", issue = "0")]

#[macro_use]
extern crate cfg_if;
extern crate coresimd;
extern crate libc;
extern crate std as _std;

#[cfg(test)]
#[macro_use]
extern crate std;

#[path = "../../../stdsimd/mod.rs"]
mod stdsimd;

pub use stdsimd::*;

#[allow(unused_imports)]
use _std::prelude;
#[allow(unused_imports)]
use _std::fs;
#[allow(unused_imports)]
use _std::io;
<commit_msg>Fix tests on nightly (#378)<commit_after>//! SIMD and vendor intrinsics support library.
//!
//! This crate defines the vendor intrinsics and types primarily used for SIMD
//! in Rust. The crate here will soon be available in the standard library, but
//! for now you can also browse the documentation here, primarily in the `arch`
//! submodule.
//!
//! [stdsimd]: https://rust-lang-nursery.github.io/stdsimd/x86_64/stdsimd/

#![feature(const_fn, integer_atomics, staged_api, stdsimd)]
#![feature(cfg_target_feature, doc_cfg)]
#![cfg_attr(feature = "cargo-clippy", allow(shadow_reuse))]
#![cfg_attr(target_os = "linux", feature(linkage))]
#![no_std]
#![unstable(feature = "stdsimd", issue = "0")]

#[macro_use]
extern crate cfg_if;
extern crate coresimd;
extern crate libc;
extern crate std as _std;

#[cfg(test)]
#[macro_use(println, print)]
extern crate std;

#[path = "../../../stdsimd/mod.rs"]
mod stdsimd;

pub use stdsimd::*;

#[allow(unused_imports)]
use _std::prelude;
#[allow(unused_imports)]
use _std::fs;
#[allow(unused_imports)]
use _std::io;
<|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.
 */

extern crate gtk;
extern crate mg;
extern crate mg_settings;
#[macro_use]
extern crate mg_settings_macros;
#[macro_use]
extern crate relm;
#[macro_use]
extern crate relm_derive;

use gtk::{
    LabelExt,
    OrientableExt,
    WidgetExt,
};
use gtk::Orientation::Vertical;
use mg::{
    AppClose,
    CustomCommand,
    DarkTheme,
    Mg,
    NoSettings,
    SetMode,
    StatusBarItem,
    Title,
    Variables,
};
use relm::Widget;
use relm_derive::widget;

use AppCommand::*;
use Msg::*;

pub struct Model {
    text: String,
}

#[derive(Msg)]
pub enum Msg {
    Command(AppCommand),
}

#[derive(Commands)]
pub enum AppCommand {
    Insert,
    Normal,
    Open(String),
    Quit,
}

#[widget]
impl Widget for Win {
    fn init_view(&mut self) {
        self.entry.grab_focus();
    }

    fn model() -> Model {
        Model {
            text: "Mg App".to_string(),
        }
    }

    fn update(&mut self, event: Msg) {
        match event {
            Command(command) => {
                match command {
                    Insert | Normal => (),
                    Open(url) => self.model.text = format!("Opening URL {}", url),
                    Quit => gtk::main_quit(),
                }
            },
        }
    }

    view! {
        #[name="mg"]
        Mg<AppCommand, NoSettings>(&[], Ok("examples/main.conf".into()), None, vec![]) {
            DarkTheme: true,
            Title: "First Mg Program".to_string(),
            Variables: vec![("url", Box::new(|| "http://duckduckgo.com/lite".to_string()))],
            gtk::Box {
                orientation: Vertical,
                gtk::Label {
                    text: &self.model.text,
                },
                #[name="entry"]
                gtk::Entry {
                },
            },
            StatusBarItem {
                text: "Rightmost",
            },
            StatusBarItem {
                text: "Test",
            },
            AppClose => Command(Quit),
            CustomCommand(Insert) => mg@SetMode("insert"),
            CustomCommand(Normal) => mg@SetMode("normal"),
            CustomCommand(ref command) => Command(command.clone()),
        }
    }
}

fn main() {
    Win::run(()).unwrap();
}
<commit_msg>Remove unused `#[macro_use]` import<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.
 */

extern crate gtk;
extern crate mg;
extern crate mg_settings;
#[macro_use]
extern crate mg_settings_macros;
extern crate relm;
#[macro_use]
extern crate relm_derive;

use gtk::{
    LabelExt,
    OrientableExt,
    WidgetExt,
};
use gtk::Orientation::Vertical;
use mg::{
    AppClose,
    CustomCommand,
    DarkTheme,
    Mg,
    NoSettings,
    SetMode,
    StatusBarItem,
    Title,
    Variables,
};
use relm::Widget;
use relm_derive::widget;

use AppCommand::*;
use Msg::*;

pub struct Model {
    text: String,
}

#[derive(Msg)]
pub enum Msg {
    Command(AppCommand),
}

#[derive(Commands)]
pub enum AppCommand {
    Insert,
    Normal,
    Open(String),
    Quit,
}

#[widget]
impl Widget for Win {
    fn init_view(&mut self) {
        self.entry.grab_focus();
    }

    fn model() -> Model {
        Model {
            text: "Mg App".to_string(),
        }
    }

    fn update(&mut self, event: Msg) {
        match event {
            Command(command) => {
                match command {
                    Insert | Normal => (),
                    Open(url) => self.model.text = format!("Opening URL {}", url),
                    Quit => gtk::main_quit(),
                }
            },
        }
    }

    view! {
        #[name="mg"]
        Mg<AppCommand, NoSettings>(&[], Ok("examples/main.conf".into()), None, vec![]) {
            DarkTheme: true,
            Title: "First Mg Program".to_string(),
            Variables: vec![("url", Box::new(|| "http://duckduckgo.com/lite".to_string()))],
            gtk::Box {
                orientation: Vertical,
                gtk::Label {
                    text: &self.model.text,
                },
                #[name="entry"]
                gtk::Entry {
                },
            },
            StatusBarItem {
                text: "Rightmost",
            },
            StatusBarItem {
                text: "Test",
            },
            AppClose => Command(Quit),
            CustomCommand(Insert) => mg@SetMode("insert"),
            CustomCommand(Normal) => mg@SetMode("normal"),
            CustomCommand(ref command) => Command(command.clone()),
        }
    }
}

fn main() {
    Win::run(()).unwrap();
}
<|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/. */

//! The `ByteString` struct.

use std::hash::{Hash, sip};
use std::str;
use std::str::FromStr;

/// Encapsulates the IDL `ByteString` type.
#[deriving(Clone,Eq,PartialEq)]
#[jstraceable]
pub struct ByteString(Vec<u8>);

impl ByteString {
    /// Creates a new `ByteString`.
    pub fn new(value: Vec<u8>) -> ByteString {
        ByteString(value)
    }

    /// Returns `self` as a string, if it encodes valid UTF-8, and `None`
    /// otherwise.
    pub fn as_str<'a>(&'a self) -> Option<&'a str> {
        let ByteString(ref vec) = *self;
        str::from_utf8(vec.as_slice())
    }

    /// Returns the underlying vector as a slice.
    pub fn as_slice<'a>(&'a self) -> &'a [u8] {
        let ByteString(ref vector) = *self;
        vector.as_slice()
    }

    /// Returns the length.
    pub fn len(&self) -> uint {
        let ByteString(ref vector) = *self;
        vector.len()
    }

    /// Compare `self` to `other`, matching A–Z and a–z as equal.
    pub fn eq_ignore_case(&self, other: &ByteString) -> bool {
        // XXXManishearth make this more efficient
        self.to_lower() == other.to_lower()
    }

    /// Returns `self` with A–Z replaced by a–z.
    pub fn to_lower(&self) -> ByteString {
        let ByteString(ref vec) = *self;
        ByteString::new(vec.iter().map(|&x| {
            if x > 'A' as u8 && x < 'Z' as u8 {
                x + ('a' as u8) - ('A' as u8)
            } else {
                x
            }
        }).collect())
    }

    /// Returns whether `self` is a `token`, as defined by
    /// [RFC 2616](http://tools.ietf.org/html/rfc2616#page-17).
    pub fn is_token(&self) -> bool {
        let ByteString(ref vec) = *self;
        if vec.len() == 0 {
            return false; // A token must be at least a single character
        }
        vec.iter().all(|&x| {
            // http://tools.ietf.org/html/rfc2616#section-2.2
            match x {
                0...31 | 127 => false, // CTLs
                40 | 41 | 60 | 62 | 64 |
                44 | 59 | 58 | 92 | 34 |
                47 | 91 | 93 | 63 | 61 |
                123 | 125 | 32  => false, // separators
                x if x > 127 => false, // non-CHARs
                _ => true
            }
        })
    }

    /// Returns whether `self` is a `field-value`, as defined by
    /// [RFC 2616](http://tools.ietf.org/html/rfc2616#page-32).
    pub fn is_field_value(&self) -> bool {
        // Classifications of characters necessary for the [CRLF] (SP|HT) rule
        #[deriving(PartialEq)]
        enum PreviousCharacter {
            Other,
            CR,
            LF,
            SPHT // SP or HT
        }
        let ByteString(ref vec) = *self;
        let mut prev = PreviousCharacter::Other; // The previous character
        vec.iter().all(|&x| {
            // http://tools.ietf.org/html/rfc2616#section-2.2
            match x {
                13  => { // CR
                    if prev == PreviousCharacter::Other || prev == PreviousCharacter::SPHT {
                        prev = PreviousCharacter::CR;
                        true
                    } else {
                        false
                    }
                },
                10 => { // LF
                    if prev == PreviousCharacter::CR {
                        prev = PreviousCharacter::LF;
                        true
                    } else {
                        false
                    }
                },
                32 => { // SP
                    if prev == PreviousCharacter::LF || prev == PreviousCharacter::SPHT {
                        prev = PreviousCharacter::SPHT;
                        true
                    } else if prev == PreviousCharacter::Other {
                        // Counts as an Other here, since it's not preceded by a CRLF
                        // SP is not a CTL, so it can be used anywhere
                        // though if used immediately after a CR the CR is invalid
                        // We don't change prev since it's already Other
                        true
                    } else {
                        false
                    }
                },
                9 => { // HT
                    if prev == PreviousCharacter::LF || prev == PreviousCharacter::SPHT {
                        prev = PreviousCharacter::SPHT;
                        true
                    } else {
                        false
                    }
                },
                0...31 | 127 => false, // CTLs
                x if x > 127 => false, // non ASCII
                _ if prev == PreviousCharacter::Other || prev == PreviousCharacter::SPHT => {
                    prev = PreviousCharacter::Other;
                    true
                },
                _ => false // Previous character was a CR/LF but not part of the [CRLF] (SP|HT) rule
            }
        })
    }
}

impl Hash for ByteString {
    fn hash(&self, state: &mut sip::SipState) {
        let ByteString(ref vec) = *self;
        vec.hash(state);
    }
}

impl FromStr for ByteString {
    fn from_str(s: &str) -> Option<ByteString> {
        Some(ByteString::new(s.to_string().into_bytes()))
    }
}
<commit_msg>auto merge of #4451 : Ms2ger/servo/bytestring-doc, r=jdm<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/. */

#![deny(missing_docs)]

//! The `ByteString` struct.

use std::hash::{Hash, sip};
use std::str;
use std::str::FromStr;

/// Encapsulates the IDL `ByteString` type.
#[deriving(Clone,Eq,PartialEq)]
#[jstraceable]
pub struct ByteString(Vec<u8>);

impl ByteString {
    /// Creates a new `ByteString`.
    pub fn new(value: Vec<u8>) -> ByteString {
        ByteString(value)
    }

    /// Returns `self` as a string, if it encodes valid UTF-8, and `None`
    /// otherwise.
    pub fn as_str<'a>(&'a self) -> Option<&'a str> {
        let ByteString(ref vec) = *self;
        str::from_utf8(vec.as_slice())
    }

    /// Returns the underlying vector as a slice.
    pub fn as_slice<'a>(&'a self) -> &'a [u8] {
        let ByteString(ref vector) = *self;
        vector.as_slice()
    }

    /// Returns the length.
    pub fn len(&self) -> uint {
        let ByteString(ref vector) = *self;
        vector.len()
    }

    /// Compare `self` to `other`, matching A–Z and a–z as equal.
    pub fn eq_ignore_case(&self, other: &ByteString) -> bool {
        // XXXManishearth make this more efficient
        self.to_lower() == other.to_lower()
    }

    /// Returns `self` with A–Z replaced by a–z.
    pub fn to_lower(&self) -> ByteString {
        let ByteString(ref vec) = *self;
        ByteString::new(vec.iter().map(|&x| {
            if x > 'A' as u8 && x < 'Z' as u8 {
                x + ('a' as u8) - ('A' as u8)
            } else {
                x
            }
        }).collect())
    }

    /// Returns whether `self` is a `token`, as defined by
    /// [RFC 2616](http://tools.ietf.org/html/rfc2616#page-17).
    pub fn is_token(&self) -> bool {
        let ByteString(ref vec) = *self;
        if vec.len() == 0 {
            return false; // A token must be at least a single character
        }
        vec.iter().all(|&x| {
            // http://tools.ietf.org/html/rfc2616#section-2.2
            match x {
                0...31 | 127 => false, // CTLs
                40 | 41 | 60 | 62 | 64 |
                44 | 59 | 58 | 92 | 34 |
                47 | 91 | 93 | 63 | 61 |
                123 | 125 | 32  => false, // separators
                x if x > 127 => false, // non-CHARs
                _ => true
            }
        })
    }

    /// Returns whether `self` is a `field-value`, as defined by
    /// [RFC 2616](http://tools.ietf.org/html/rfc2616#page-32).
    pub fn is_field_value(&self) -> bool {
        // Classifications of characters necessary for the [CRLF] (SP|HT) rule
        #[deriving(PartialEq)]
        enum PreviousCharacter {
            Other,
            CR,
            LF,
            SPHT // SP or HT
        }
        let ByteString(ref vec) = *self;
        let mut prev = PreviousCharacter::Other; // The previous character
        vec.iter().all(|&x| {
            // http://tools.ietf.org/html/rfc2616#section-2.2
            match x {
                13  => { // CR
                    if prev == PreviousCharacter::Other || prev == PreviousCharacter::SPHT {
                        prev = PreviousCharacter::CR;
                        true
                    } else {
                        false
                    }
                },
                10 => { // LF
                    if prev == PreviousCharacter::CR {
                        prev = PreviousCharacter::LF;
                        true
                    } else {
                        false
                    }
                },
                32 => { // SP
                    if prev == PreviousCharacter::LF || prev == PreviousCharacter::SPHT {
                        prev = PreviousCharacter::SPHT;
                        true
                    } else if prev == PreviousCharacter::Other {
                        // Counts as an Other here, since it's not preceded by a CRLF
                        // SP is not a CTL, so it can be used anywhere
                        // though if used immediately after a CR the CR is invalid
                        // We don't change prev since it's already Other
                        true
                    } else {
                        false
                    }
                },
                9 => { // HT
                    if prev == PreviousCharacter::LF || prev == PreviousCharacter::SPHT {
                        prev = PreviousCharacter::SPHT;
                        true
                    } else {
                        false
                    }
                },
                0...31 | 127 => false, // CTLs
                x if x > 127 => false, // non ASCII
                _ if prev == PreviousCharacter::Other || prev == PreviousCharacter::SPHT => {
                    prev = PreviousCharacter::Other;
                    true
                },
                _ => false // Previous character was a CR/LF but not part of the [CRLF] (SP|HT) rule
            }
        })
    }
}

impl Hash for ByteString {
    fn hash(&self, state: &mut sip::SipState) {
        let ByteString(ref vec) = *self;
        vec.hash(state);
    }
}

impl FromStr for ByteString {
    fn from_str(s: &str) -> Option<ByteString> {
        Some(ByteString::new(s.to_string().into_bytes()))
    }
}
<|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 https://mozilla.org/MPL/2.0/. */

use crate::dom::bindings::codegen::Bindings::WebGLRenderingContextBinding::WebGLRenderingContextMethods;
use crate::dom::bindings::codegen::Bindings::WebGL2RenderingContextBinding::WebGL2RenderingContextBinding::WebGL2RenderingContextMethods;
use crate::dom::bindings::codegen::Bindings::XRViewBinding::{XREye, XRViewMethods};
use crate::dom::bindings::codegen::Bindings::XRWebGLLayerBinding::XRWebGLLayerInit;
use crate::dom::bindings::codegen::Bindings::XRWebGLLayerBinding::XRWebGLLayerMethods;
use crate::dom::bindings::codegen::Bindings::XRWebGLLayerBinding::XRWebGLRenderingContext;
use crate::dom::bindings::error::Error;
use crate::dom::bindings::error::Fallible;
use crate::dom::bindings::reflector::{reflect_dom_object, DomObject, Reflector};
use crate::dom::bindings::root::{Dom, DomRoot};
use crate::dom::globalscope::GlobalScope;
use crate::dom::webglframebuffer::WebGLFramebuffer;
use crate::dom::webglrenderingcontext::WebGLRenderingContext;
use crate::dom::webgl2renderingcontext::WebGL2RenderingContext;
use crate::dom::window::Window;
use crate::dom::xrsession::XRSession;
use crate::dom::xrview::XRView;
use crate::dom::xrviewport::XRViewport;
use canvas_traits::webgl::WebGLFramebufferId;
use dom_struct::dom_struct;
use euclid::{Point2D, Rect, Size2D};
use std::convert::TryInto;
use webxr_api::SwapChainId as WebXRSwapChainId;
use webxr_api::{Viewport, Views};

#[derive(JSTraceable, MallocSizeOf)]
#[unrooted_must_root_lint::must_root]
pub enum RenderingContext {
    WebGL1(Dom<WebGLRenderingContext>),
    WebGL2(Dom<WebGL2RenderingContext>),
}

#[dom_struct]
pub struct XRWebGLLayer {
    reflector_: Reflector,
    antialias: bool,
    depth: bool,
    stencil: bool,
    alpha: bool,
    #[ignore_malloc_size_of = "ids don't malloc"]
    swap_chain_id: Option<WebXRSwapChainId>,
    context: RenderingContext,
    session: Dom<XRSession>,
    /// If none, this is an inline session (the composition disabled flag is true)
    framebuffer: Option<Dom<WebGLFramebuffer>>,
}

impl XRWebGLLayer {
    pub fn new_inherited(
        swap_chain_id: Option<WebXRSwapChainId>,
        session: &XRSession,
        context: XRWebGLRenderingContext,
        init: &XRWebGLLayerInit,
        framebuffer: Option<&WebGLFramebuffer>,
    ) -> XRWebGLLayer {
        XRWebGLLayer {
            reflector_: Reflector::new(),
            antialias: init.antialias,
            depth: init.depth,
            stencil: init.stencil,
            alpha: init.alpha,
            swap_chain_id,
            context: match context {
                XRWebGLRenderingContext::WebGLRenderingContext(ctx) => {
                    RenderingContext::WebGL1(Dom::from_ref(&*ctx))
                },
                XRWebGLRenderingContext::WebGL2RenderingContext(ctx) => {
                    RenderingContext::WebGL2(Dom::from_ref(&*ctx))
                },
            },
            session: Dom::from_ref(session),
            framebuffer: framebuffer.map(Dom::from_ref),
        }
    }

    pub fn new(
        global: &GlobalScope,
        swap_chain_id: Option<WebXRSwapChainId>,
        session: &XRSession,
        context: XRWebGLRenderingContext,
        init: &XRWebGLLayerInit,
        framebuffer: Option<&WebGLFramebuffer>,
    ) -> DomRoot<XRWebGLLayer> {
        reflect_dom_object(
            Box::new(XRWebGLLayer::new_inherited(
                swap_chain_id,
                session,
                context,
                init,
                framebuffer,
            )),
            global,
        )
    }

    /// https://immersive-web.github.io/webxr/#dom-xrwebgllayer-xrwebgllayer
    #[allow(non_snake_case)]
    pub fn Constructor(
        global: &Window,
        session: &XRSession,
        context: XRWebGLRenderingContext,
        init: &XRWebGLLayerInit,
    ) -> Fallible<DomRoot<Self>> {
        let framebuffer;
        // Step 2
        if session.is_ended() {
            return Err(Error::InvalidState);
        }
        // XXXManishearth step 3: throw error if context is lost
        // XXXManishearth step 4: check XR compat flag for immersive sessions

        // Step 9.2. "Initialize layer’s framebuffer to a new opaque framebuffer created with context."
        let (swap_chain_id, framebuffer) = if session.is_immersive() {
            let size = session.with_session(|session| session.recommended_framebuffer_resolution());
            let (swap_chain_id, fb) = WebGLFramebuffer::maybe_new_webxr(session, &context, size)
                .ok_or(Error::Operation)?;
            framebuffer = fb;
            (Some(swap_chain_id), Some(&*framebuffer))
        } else {
            (None, None)
        };

        // Step 9.3. "Allocate and initialize resources compatible with session’s XR device,
        // including GPU accessible memory buffers, as required to support the compositing of layer."

        // Step 9.4: "If layer’s resources were unable to be created for any reason,
        // throw an OperationError and abort these steps."

        // Ensure that we finish setting up this layer before continuing.
        match context {
            XRWebGLRenderingContext::WebGLRenderingContext(ref ctx) => ctx.Finish(),
            XRWebGLRenderingContext::WebGL2RenderingContext(ref ctx) => ctx.Finish(),
        }

        // Step 10. "Return layer."
        Ok(XRWebGLLayer::new(
            &global.global(),
            swap_chain_id,
            session,
            context,
            init,
            framebuffer,
        ))
    }

    pub fn swap_chain_id(&self) -> WebXRSwapChainId {
        self.swap_chain_id
            .expect("swap_chain_id must not be called for inline sessions")
    }

    pub fn session(&self) -> &XRSession {
        &self.session
    }

    pub fn swap_buffers(&self) {
        if let WebGLFramebufferId::Opaque(id) = self
            .framebuffer
            .as_ref()
            .expect("swap_buffers must not be called for inline sessions")
            .id()
        {
            match self.context {
                RenderingContext::WebGL1(ref ctx) => ctx.swap_buffers(Some(id)),
                RenderingContext::WebGL2(ref ctx) => ctx.base_context().swap_buffers(Some(id)),
            }
        }
    }

    pub fn size(&self) -> Size2D<u32, Viewport> {
        if let Some(framebuffer) = self.framebuffer.as_ref() {
            let size = framebuffer.size().unwrap_or((0, 0));
            Size2D::new(
                size.0.try_into().unwrap_or(0),
                size.1.try_into().unwrap_or(0),
            )
        } else {
            let size = match self.context {
                RenderingContext::WebGL1(ref ctx) => ctx.Canvas().get_size(),
                RenderingContext::WebGL2(ref ctx) => ctx.base_context().Canvas().get_size(),
            };
            Size2D::from_untyped(size)
        }
    }
}

impl XRWebGLLayerMethods for XRWebGLLayer {
    /// https://immersive-web.github.io/webxr/#dom-xrwebgllayer-depth
    fn Depth(&self) -> bool {
        self.depth
    }

    /// https://immersive-web.github.io/webxr/#dom-xrwebgllayer-stencil
    fn Stencil(&self) -> bool {
        self.stencil
    }

    /// https://immersive-web.github.io/webxr/#dom-xrwebgllayer-antialias
    fn Antialias(&self) -> bool {
        self.antialias
    }

    /// https://immersive-web.github.io/webxr/#dom-xrwebgllayer-alpha
    fn Alpha(&self) -> bool {
        self.alpha
    }

    /// https://immersive-web.github.io/webxr/#dom-xrwebgllayer-context
    fn Context(&self) -> XRWebGLRenderingContext {
        match self.context {
            RenderingContext::WebGL1(ref ctx) => {
                XRWebGLRenderingContext::WebGLRenderingContext(DomRoot::from_ref(&**ctx))
            },
            RenderingContext::WebGL2(ref ctx) => {
                XRWebGLRenderingContext::WebGL2RenderingContext(DomRoot::from_ref(&**ctx))
            },
        }
    }

    /// https://immersive-web.github.io/webxr/#dom-xrwebgllayer-framebuffer
    fn GetFramebuffer(&self) -> Option<DomRoot<WebGLFramebuffer>> {
        self.framebuffer.as_ref().map(|x| DomRoot::from_ref(&**x))
    }

    /// https://immersive-web.github.io/webxr/#dom-xrwebgllayer-framebufferwidth
    fn FramebufferWidth(&self) -> u32 {
        self.size().width
    }

    /// https://immersive-web.github.io/webxr/#dom-xrwebgllayer-framebufferheight
    fn FramebufferHeight(&self) -> u32 {
        self.size().height
    }

    /// https://immersive-web.github.io/webxr/#dom-xrwebgllayer-getviewport
    fn GetViewport(&self, view: &XRView) -> Option<DomRoot<XRViewport>> {
        if self.session != view.session() {
            return None;
        }

        let views = self.session.with_session(|s| s.views().clone());

        let viewport = match (view.Eye(), views) {
            (XREye::None, Views::Inline) => {
                let origin = Point2D::new(0, 0);
                Rect::new(origin, self.size().cast())
            },
            (XREye::None, Views::Mono(view)) => view.viewport,
            (XREye::Left, Views::Stereo(view, _)) => view.viewport,
            (XREye::Right, Views::Stereo(_, view)) => view.viewport,
            _ => return None,
        };

        Some(XRViewport::new(&self.global(), viewport))
    }
}
<commit_msg>Handle StereoCapture in GetViewport()<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 https://mozilla.org/MPL/2.0/. */

use crate::dom::bindings::codegen::Bindings::WebGLRenderingContextBinding::WebGLRenderingContextMethods;
use crate::dom::bindings::codegen::Bindings::WebGL2RenderingContextBinding::WebGL2RenderingContextBinding::WebGL2RenderingContextMethods;
use crate::dom::bindings::codegen::Bindings::XRViewBinding::{XREye, XRViewMethods};
use crate::dom::bindings::codegen::Bindings::XRWebGLLayerBinding::XRWebGLLayerInit;
use crate::dom::bindings::codegen::Bindings::XRWebGLLayerBinding::XRWebGLLayerMethods;
use crate::dom::bindings::codegen::Bindings::XRWebGLLayerBinding::XRWebGLRenderingContext;
use crate::dom::bindings::error::Error;
use crate::dom::bindings::error::Fallible;
use crate::dom::bindings::reflector::{reflect_dom_object, DomObject, Reflector};
use crate::dom::bindings::root::{Dom, DomRoot};
use crate::dom::globalscope::GlobalScope;
use crate::dom::webglframebuffer::WebGLFramebuffer;
use crate::dom::webglrenderingcontext::WebGLRenderingContext;
use crate::dom::webgl2renderingcontext::WebGL2RenderingContext;
use crate::dom::window::Window;
use crate::dom::xrsession::XRSession;
use crate::dom::xrview::XRView;
use crate::dom::xrviewport::XRViewport;
use canvas_traits::webgl::WebGLFramebufferId;
use dom_struct::dom_struct;
use euclid::{Point2D, Rect, Size2D};
use std::convert::TryInto;
use webxr_api::SwapChainId as WebXRSwapChainId;
use webxr_api::{Viewport, Views};

#[derive(JSTraceable, MallocSizeOf)]
#[unrooted_must_root_lint::must_root]
pub enum RenderingContext {
    WebGL1(Dom<WebGLRenderingContext>),
    WebGL2(Dom<WebGL2RenderingContext>),
}

#[dom_struct]
pub struct XRWebGLLayer {
    reflector_: Reflector,
    antialias: bool,
    depth: bool,
    stencil: bool,
    alpha: bool,
    #[ignore_malloc_size_of = "ids don't malloc"]
    swap_chain_id: Option<WebXRSwapChainId>,
    context: RenderingContext,
    session: Dom<XRSession>,
    /// If none, this is an inline session (the composition disabled flag is true)
    framebuffer: Option<Dom<WebGLFramebuffer>>,
}

impl XRWebGLLayer {
    pub fn new_inherited(
        swap_chain_id: Option<WebXRSwapChainId>,
        session: &XRSession,
        context: XRWebGLRenderingContext,
        init: &XRWebGLLayerInit,
        framebuffer: Option<&WebGLFramebuffer>,
    ) -> XRWebGLLayer {
        XRWebGLLayer {
            reflector_: Reflector::new(),
            antialias: init.antialias,
            depth: init.depth,
            stencil: init.stencil,
            alpha: init.alpha,
            swap_chain_id,
            context: match context {
                XRWebGLRenderingContext::WebGLRenderingContext(ctx) => {
                    RenderingContext::WebGL1(Dom::from_ref(&*ctx))
                },
                XRWebGLRenderingContext::WebGL2RenderingContext(ctx) => {
                    RenderingContext::WebGL2(Dom::from_ref(&*ctx))
                },
            },
            session: Dom::from_ref(session),
            framebuffer: framebuffer.map(Dom::from_ref),
        }
    }

    pub fn new(
        global: &GlobalScope,
        swap_chain_id: Option<WebXRSwapChainId>,
        session: &XRSession,
        context: XRWebGLRenderingContext,
        init: &XRWebGLLayerInit,
        framebuffer: Option<&WebGLFramebuffer>,
    ) -> DomRoot<XRWebGLLayer> {
        reflect_dom_object(
            Box::new(XRWebGLLayer::new_inherited(
                swap_chain_id,
                session,
                context,
                init,
                framebuffer,
            )),
            global,
        )
    }

    /// https://immersive-web.github.io/webxr/#dom-xrwebgllayer-xrwebgllayer
    #[allow(non_snake_case)]
    pub fn Constructor(
        global: &Window,
        session: &XRSession,
        context: XRWebGLRenderingContext,
        init: &XRWebGLLayerInit,
    ) -> Fallible<DomRoot<Self>> {
        let framebuffer;
        // Step 2
        if session.is_ended() {
            return Err(Error::InvalidState);
        }
        // XXXManishearth step 3: throw error if context is lost
        // XXXManishearth step 4: check XR compat flag for immersive sessions

        // Step 9.2. "Initialize layer’s framebuffer to a new opaque framebuffer created with context."
        let (swap_chain_id, framebuffer) = if session.is_immersive() {
            let size = session.with_session(|session| session.recommended_framebuffer_resolution());
            let (swap_chain_id, fb) = WebGLFramebuffer::maybe_new_webxr(session, &context, size)
                .ok_or(Error::Operation)?;
            framebuffer = fb;
            (Some(swap_chain_id), Some(&*framebuffer))
        } else {
            (None, None)
        };

        // Step 9.3. "Allocate and initialize resources compatible with session’s XR device,
        // including GPU accessible memory buffers, as required to support the compositing of layer."

        // Step 9.4: "If layer’s resources were unable to be created for any reason,
        // throw an OperationError and abort these steps."

        // Ensure that we finish setting up this layer before continuing.
        match context {
            XRWebGLRenderingContext::WebGLRenderingContext(ref ctx) => ctx.Finish(),
            XRWebGLRenderingContext::WebGL2RenderingContext(ref ctx) => ctx.Finish(),
        }

        // Step 10. "Return layer."
        Ok(XRWebGLLayer::new(
            &global.global(),
            swap_chain_id,
            session,
            context,
            init,
            framebuffer,
        ))
    }

    pub fn swap_chain_id(&self) -> WebXRSwapChainId {
        self.swap_chain_id
            .expect("swap_chain_id must not be called for inline sessions")
    }

    pub fn session(&self) -> &XRSession {
        &self.session
    }

    pub fn swap_buffers(&self) {
        if let WebGLFramebufferId::Opaque(id) = self
            .framebuffer
            .as_ref()
            .expect("swap_buffers must not be called for inline sessions")
            .id()
        {
            match self.context {
                RenderingContext::WebGL1(ref ctx) => ctx.swap_buffers(Some(id)),
                RenderingContext::WebGL2(ref ctx) => ctx.base_context().swap_buffers(Some(id)),
            }
        }
    }

    pub fn size(&self) -> Size2D<u32, Viewport> {
        if let Some(framebuffer) = self.framebuffer.as_ref() {
            let size = framebuffer.size().unwrap_or((0, 0));
            Size2D::new(
                size.0.try_into().unwrap_or(0),
                size.1.try_into().unwrap_or(0),
            )
        } else {
            let size = match self.context {
                RenderingContext::WebGL1(ref ctx) => ctx.Canvas().get_size(),
                RenderingContext::WebGL2(ref ctx) => ctx.base_context().Canvas().get_size(),
            };
            Size2D::from_untyped(size)
        }
    }
}

impl XRWebGLLayerMethods for XRWebGLLayer {
    /// https://immersive-web.github.io/webxr/#dom-xrwebgllayer-depth
    fn Depth(&self) -> bool {
        self.depth
    }

    /// https://immersive-web.github.io/webxr/#dom-xrwebgllayer-stencil
    fn Stencil(&self) -> bool {
        self.stencil
    }

    /// https://immersive-web.github.io/webxr/#dom-xrwebgllayer-antialias
    fn Antialias(&self) -> bool {
        self.antialias
    }

    /// https://immersive-web.github.io/webxr/#dom-xrwebgllayer-alpha
    fn Alpha(&self) -> bool {
        self.alpha
    }

    /// https://immersive-web.github.io/webxr/#dom-xrwebgllayer-context
    fn Context(&self) -> XRWebGLRenderingContext {
        match self.context {
            RenderingContext::WebGL1(ref ctx) => {
                XRWebGLRenderingContext::WebGLRenderingContext(DomRoot::from_ref(&**ctx))
            },
            RenderingContext::WebGL2(ref ctx) => {
                XRWebGLRenderingContext::WebGL2RenderingContext(DomRoot::from_ref(&**ctx))
            },
        }
    }

    /// https://immersive-web.github.io/webxr/#dom-xrwebgllayer-framebuffer
    fn GetFramebuffer(&self) -> Option<DomRoot<WebGLFramebuffer>> {
        self.framebuffer.as_ref().map(|x| DomRoot::from_ref(&**x))
    }

    /// https://immersive-web.github.io/webxr/#dom-xrwebgllayer-framebufferwidth
    fn FramebufferWidth(&self) -> u32 {
        self.size().width
    }

    /// https://immersive-web.github.io/webxr/#dom-xrwebgllayer-framebufferheight
    fn FramebufferHeight(&self) -> u32 {
        self.size().height
    }

    /// https://immersive-web.github.io/webxr/#dom-xrwebgllayer-getviewport
    fn GetViewport(&self, view: &XRView) -> Option<DomRoot<XRViewport>> {
        if self.session != view.session() {
            return None;
        }

        let views = self.session.with_session(|s| s.views().clone());

        let viewport = match (view.Eye(), views) {
            (XREye::None, Views::Inline) => {
                let origin = Point2D::new(0, 0);
                Rect::new(origin, self.size().cast())
            },
            (XREye::None, Views::Mono(view)) => view.viewport,
            (XREye::None, Views::StereoCapture(_, _, view)) => view.viewport,
            (XREye::Left, Views::Stereo(view, _)) => view.viewport,
            (XREye::Left, Views::StereoCapture(view, _, _)) => view.viewport,
            (XREye::Right, Views::Stereo(_, view)) => view.viewport,
            (XREye::Right, Views::StereoCapture(_, view, _)) => view.viewport,
            _ => return None,
        };

        Some(XRViewport::new(&self.global(), viewport))
    }
}
<|endoftext|>


<commit_before>use ast::Script;
use compile::ExecutableDevEnv;
use run::{ Execution, ExecutionEvent, Error as RunError, StartStopError };

use std::collections::HashMap;
use std::path::{ Path as FilePath, PathBuf as FilePathBuf };

use foxbox_taxonomy::api::ResultMap;
use foxbox_taxonomy::parse::*;
use foxbox_taxonomy::util::{ Id };

use rusqlite;
use transformable_channels::mpsc::{ channel, ExtSender, TransformableSender };

/// A ScriptManager error.
#[derive(Serialize, Debug)]
pub enum Error {
    /// The script you requested (by ID) does not exist.
    NoSuchScriptError,

    /// There was an error executing some SQL.
    SQLError(String),

    /// There was an error attempting to run a script. (See `run.rs`.)
    RunError(RunError),

    /// There was an error parsing the script's JSON.
    ParseError(String),
}

/// A type for ensuring type-safety (Id<ScriptId>).
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, Hash, Eq)]
pub struct ScriptId;

/// ScriptManager stores a persistent database of scripts and executes them.
/// Each script can be individually enabled or disabled.
/// When a script is enabled, it is always running (unless an error occured during launch).
/// Script sources are stored as JSON strings in a SQLite database.
pub struct ScriptManager<Env, T> where Env: ExecutableDevEnv + Clone + 'static {
    env: Env,

    /// The path to the SQLite file to store, e.g. "./database.sqlite"
    path: FilePathBuf,

    /// A map to track currently-executing scripts.
    runners: HashMap<Id<ScriptId>, Execution<Env>>,

    /// The tx end of the channel passed to ScriptManager::new()
    tx: Box<T>,
}

impl<Env, T> ScriptManager<Env, T>
    where Env: ExecutableDevEnv + Clone + 'static,
          T: ExtSender<(Id<ScriptId>, ExecutionEvent)> + TransformableSender<(Id<ScriptId>, ExecutionEvent)> {

    /// Create a ScriptManager using a SQLite database file with the given path, i.e. filename.
    /// If the database file does not exist, it will be created.
    ///
    /// NOTE: You MUST consume the contents of `tx` to prevent memory leaks.
    ///
    /// The database stores the raw script source, but only after the source has been parsed
    /// to ensure validity.
    pub fn new(env: Env, path: &FilePath, tx: Box<T>) -> Result<Self, Error> {

        let connection = try!(rusqlite::Connection::open(&path));
        try!(connection.execute("CREATE TABLE IF NOT EXISTS scripts (
            id          TEXT NOT NULL PRIMARY KEY,
            source      TEXT NOT NULL,
            is_enabled  BOOL NOT NULL DEFAULT 1
        )", &[]));

        Ok(ScriptManager {
            path: path.to_owned(),
            env: env,
            runners: HashMap::new(),
            tx: tx
        })
    }

    /// Load and launch all existing scripts from the database.
    pub fn load(&mut self) -> Result<ResultMap<Id<ScriptId>, (), Error>, Error> {
        let connection = try!(rusqlite::Connection::open(&self.path));
        let mut result_map = HashMap::new();
        let mut stmt = try!(connection.prepare("SELECT id, source, is_enabled FROM scripts"));
        let rows = try!(stmt.query(&[]));

        for result_row in rows {
            let row = try!(result_row);
            let id_string: String = try!(row.get_checked(0));
            let id: Id<ScriptId> = Id::new(&id_string);
            let source: String = try!(row.get_checked(1));
            let is_enabled: bool = try!(row.get_checked(2));

            if is_enabled {
                result_map.insert(
                    id.clone(),
                    self.start_script(&id, &source).map(|_| ()));
            }
        }
        Ok(result_map)
    }

    /// Attempt to add a new script. The script will be executed and persisted to disk.
    /// The ID is chosen by the consumer and must be unique.
    pub fn put(&mut self, id: &Id<ScriptId>, source: &String) -> Result<(), Error> {
        try!(self.start_script(&id, &source));

        let connection = try!(rusqlite::Connection::open(&self.path));
        connection.execute("INSERT OR REPLACE INTO scripts (id, source, is_enabled)
                VALUES ($1, $2, $3)", &[&id.to_string(), source, &1])
            .map(|_| ()).map_err(From::from)
    }

    /// Enable or disable a script, starting or stopping the script if necessary.
    pub fn set_enabled(&mut self, id: &Id<ScriptId>, enabled: bool) -> Result<(), Error> {
        let source = try!(self.get_source(id));
        let is_running = self.runners.contains_key(&id);
        match (enabled, is_running) {
            (false, true) => {
                if let Some(mut runner) = self.runners.remove(&id) {
                    let (tx, rx) = channel();
                    runner.stop(move |result| {
                        let _ = tx.send(result);
                    });
                    if let Err(_) = rx.recv() {
                        return Err(Error::RunError(RunError::StartStopError(StartStopError::ThreadError)));
                    }
                }

                let connection = try!(rusqlite::Connection::open(&self.path));
                try!(connection.execute("UPDATE scripts SET is_enabled = 0 WHERE id = $1",
                                        &[&id.to_string()]));
            },
            (true, false) => {
                try!(self.start_script(id, &source));
                let connection = try!(rusqlite::Connection::open(&self.path));
                try!(connection.execute("UPDATE scripts SET is_enabled = 1 WHERE id = $1",
                                        &[&id.to_string()]));
            },
            _ => {
                // Nothing to do.
            }
        }

        Ok(())
    }

    /// Remove a script entirely, stopping it if necessary.
    /// If the script cannot be stopped (due to an error), it will not be removed.
    pub fn remove(&mut self, id: &Id<ScriptId>) -> Result<(), Error> {
        try!(self.set_enabled(id, false));
        let connection = try!(rusqlite::Connection::open(&self.path));
        connection.execute("DELETE FROM scripts WHERE id = $1", &[&id.to_string()])
            .map(|_| ())
            .map_err(From::from)
    }

    /// Remove all scripts, stopping any running scripts.
    /// (If any scripts fail to stop, we store and return those errors in a Vec<Error> so that
    /// we ensure that the database always gets wiped.)
    pub fn remove_all(&mut self) -> Result<Vec<Error>, Error> {
        // Get a copy of the keys (so that we don't borow `self` twice).
        let keys: Vec<Id<ScriptId>> = self.runners.keys().cloned().collect();
        let mut errors = Vec::new();
        // Remove any running scripts, storing errors for later return so that we
        // for sure end up nuking the database at the end.
        for id in keys {
            if let Err(err) = self.remove(&id) {
                errors.push(err);
            }
        }
        // Nuke the scripts database.
        let connection = try!(rusqlite::Connection::open(&self.path));
        try!(connection.execute("DELETE FROM scripts", &[])
                .map(|_| ()));
        Ok(errors)
    }

    /// Get the number of currently-running scripts.
    pub fn get_running_count(&self) -> usize {
        self.runners.len()
    }

    /// Get the source for a script with the given id.
    fn get_source(&self, id: &Id<ScriptId>) -> Result<String, Error> {
        let connection = try!(rusqlite::Connection::open(&self.path));
        let mut stmt = try!(connection.prepare("SELECT source FROM scripts WHERE id = $1"));
        let mut rows = try!(stmt.query(&[&id.to_string()]));
        let first_row = try!(try!(rows.nth(0).ok_or(Error::NoSuchScriptError)));
        Ok(try!(first_row.get_checked(0)))
    }

    /// Return true if the script is enabled.
    pub fn is_enabled(&self, id: &Id<ScriptId>) -> bool {
        self.runners.contains_key(id)
    }

    /// Execute a script. Returns an error if the script is already running,
    /// or it won't parse, or it won't compile.
    fn start_script(&mut self, id: &Id<ScriptId>, source: &String) -> Result<(), Error> {
        if self.runners.contains_key(id) {
            return Err(Error::RunError(RunError::StartStopError(StartStopError::AlreadyRunning)));
        }
        let mut runner = Execution::<Env>::new();
        let tx_id = id.clone();
        let tx = self.tx.map(move |event| {
            (tx_id.clone(), event)
        });
        let parsed_source = try!(Script::from_str(source));
        try!(runner.start(self.env.clone(), parsed_source, tx));
        self.runners.insert(id.clone(), runner);
        Ok(())
    }
}

impl From<rusqlite::Error> for Error {
    fn from(err: rusqlite::Error) -> Error {
        Error::SQLError(format!("{:?}", err))
    }
}

impl From<RunError> for Error {
    fn from(err: RunError) -> Error {
        Error::RunError(err)
    }
}

impl From<ParseError> for Error {
    fn from(err: ParseError) -> Error {
        Error::ParseError(format!("{:?}", err))
    }
}
<commit_msg>[fxbox/thinkerbell] Insert results into ScriptManager even if the script is disabled.<commit_after>use ast::Script;
use compile::ExecutableDevEnv;
use run::{ Execution, ExecutionEvent, Error as RunError, StartStopError };

use std::collections::HashMap;
use std::path::{ Path as FilePath, PathBuf as FilePathBuf };

use foxbox_taxonomy::api::ResultMap;
use foxbox_taxonomy::parse::*;
use foxbox_taxonomy::util::{ Id };

use rusqlite;
use transformable_channels::mpsc::{ channel, ExtSender, TransformableSender };

/// A ScriptManager error.
#[derive(Serialize, Debug)]
pub enum Error {
    /// The script you requested (by ID) does not exist.
    NoSuchScriptError,

    /// There was an error executing some SQL.
    SQLError(String),

    /// There was an error attempting to run a script. (See `run.rs`.)
    RunError(RunError),

    /// There was an error parsing the script's JSON.
    ParseError(String),
}

/// A type for ensuring type-safety (Id<ScriptId>).
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, Hash, Eq)]
pub struct ScriptId;

/// ScriptManager stores a persistent database of scripts and executes them.
/// Each script can be individually enabled or disabled.
/// When a script is enabled, it is always running (unless an error occured during launch).
/// Script sources are stored as JSON strings in a SQLite database.
pub struct ScriptManager<Env, T> where Env: ExecutableDevEnv + Clone + 'static {
    env: Env,

    /// The path to the SQLite file to store, e.g. "./database.sqlite"
    path: FilePathBuf,

    /// A map to track currently-executing scripts.
    runners: HashMap<Id<ScriptId>, Execution<Env>>,

    /// The tx end of the channel passed to ScriptManager::new()
    tx: Box<T>,
}

impl<Env, T> ScriptManager<Env, T>
    where Env: ExecutableDevEnv + Clone + 'static,
          T: ExtSender<(Id<ScriptId>, ExecutionEvent)> + TransformableSender<(Id<ScriptId>, ExecutionEvent)> {

    /// Create a ScriptManager using a SQLite database file with the given path, i.e. filename.
    /// If the database file does not exist, it will be created.
    ///
    /// NOTE: You MUST consume the contents of `tx` to prevent memory leaks.
    ///
    /// The database stores the raw script source, but only after the source has been parsed
    /// to ensure validity.
    pub fn new(env: Env, path: &FilePath, tx: Box<T>) -> Result<Self, Error> {

        let connection = try!(rusqlite::Connection::open(&path));
        try!(connection.execute("CREATE TABLE IF NOT EXISTS scripts (
            id          TEXT NOT NULL PRIMARY KEY,
            source      TEXT NOT NULL,
            is_enabled  BOOL NOT NULL DEFAULT 1
        )", &[]));

        Ok(ScriptManager {
            path: path.to_owned(),
            env: env,
            runners: HashMap::new(),
            tx: tx
        })
    }

    /// Load and launch all existing scripts from the database.
    pub fn load(&mut self) -> Result<ResultMap<Id<ScriptId>, (), Error>, Error> {
        let connection = try!(rusqlite::Connection::open(&self.path));
        let mut result_map = HashMap::new();
        let mut stmt = try!(connection.prepare("SELECT id, source, is_enabled FROM scripts"));
        let rows = try!(stmt.query(&[]));

        for result_row in rows {
            let row = try!(result_row);
            let id_string: String = try!(row.get_checked(0));
            let id: Id<ScriptId> = Id::new(&id_string);
            let source: String = try!(row.get_checked(1));
            let is_enabled: bool = try!(row.get_checked(2));

            if is_enabled {
                result_map.insert(
                    id.clone(),
                    self.start_script(&id, &source).map(|_| ()));
            } else {
                result_map.insert(id.clone(), Ok(()));
            }
        }
        Ok(result_map)
    }

    /// Attempt to add a new script. The script will be executed and persisted to disk.
    /// The ID is chosen by the consumer and must be unique.
    pub fn put(&mut self, id: &Id<ScriptId>, source: &String) -> Result<(), Error> {
        try!(self.start_script(&id, &source));

        let connection = try!(rusqlite::Connection::open(&self.path));
        connection.execute("INSERT OR REPLACE INTO scripts (id, source, is_enabled)
                VALUES ($1, $2, $3)", &[&id.to_string(), source, &1])
            .map(|_| ()).map_err(From::from)
    }

    /// Enable or disable a script, starting or stopping the script if necessary.
    pub fn set_enabled(&mut self, id: &Id<ScriptId>, enabled: bool) -> Result<(), Error> {
        let source = try!(self.get_source(id));
        let is_running = self.runners.contains_key(&id);
        match (enabled, is_running) {
            (false, true) => {
                if let Some(mut runner) = self.runners.remove(&id) {
                    let (tx, rx) = channel();
                    runner.stop(move |result| {
                        let _ = tx.send(result);
                    });
                    if let Err(_) = rx.recv() {
                        return Err(Error::RunError(RunError::StartStopError(StartStopError::ThreadError)));
                    }
                }

                let connection = try!(rusqlite::Connection::open(&self.path));
                try!(connection.execute("UPDATE scripts SET is_enabled = 0 WHERE id = $1",
                                        &[&id.to_string()]));
            },
            (true, false) => {
                try!(self.start_script(id, &source));
                let connection = try!(rusqlite::Connection::open(&self.path));
                try!(connection.execute("UPDATE scripts SET is_enabled = 1 WHERE id = $1",
                                        &[&id.to_string()]));
            },
            _ => {
                // Nothing to do.
            }
        }

        Ok(())
    }

    /// Remove a script entirely, stopping it if necessary.
    /// If the script cannot be stopped (due to an error), it will not be removed.
    pub fn remove(&mut self, id: &Id<ScriptId>) -> Result<(), Error> {
        try!(self.set_enabled(id, false));
        let connection = try!(rusqlite::Connection::open(&self.path));
        connection.execute("DELETE FROM scripts WHERE id = $1", &[&id.to_string()])
            .map(|_| ())
            .map_err(From::from)
    }

    /// Remove all scripts, stopping any running scripts.
    /// (If any scripts fail to stop, we store and return those errors in a Vec<Error> so that
    /// we ensure that the database always gets wiped.)
    pub fn remove_all(&mut self) -> Result<Vec<Error>, Error> {
        // Get a copy of the keys (so that we don't borow `self` twice).
        let keys: Vec<Id<ScriptId>> = self.runners.keys().cloned().collect();
        let mut errors = Vec::new();
        // Remove any running scripts, storing errors for later return so that we
        // for sure end up nuking the database at the end.
        for id in keys {
            if let Err(err) = self.remove(&id) {
                errors.push(err);
            }
        }
        // Nuke the scripts database.
        let connection = try!(rusqlite::Connection::open(&self.path));
        try!(connection.execute("DELETE FROM scripts", &[])
                .map(|_| ()));
        Ok(errors)
    }

    /// Get the number of currently-running scripts.
    pub fn get_running_count(&self) -> usize {
        self.runners.len()
    }

    /// Get the source for a script with the given id.
    pub fn get_source(&self, id: &Id<ScriptId>) -> Result<String, Error> {
        let connection = try!(rusqlite::Connection::open(&self.path));
        let mut stmt = try!(connection.prepare("SELECT source FROM scripts WHERE id = $1"));
        let mut rows = try!(stmt.query(&[&id.to_string()]));
        let first_row = try!(try!(rows.nth(0).ok_or(Error::NoSuchScriptError)));
        Ok(try!(first_row.get_checked(0)))
    }

    /// Return true if the script is enabled.
    pub fn is_enabled(&self, id: &Id<ScriptId>) -> bool {
        self.runners.contains_key(id)
    }

    /// Execute a script. Returns an error if the script is already running,
    /// or it won't parse, or it won't compile.
    fn start_script(&mut self, id: &Id<ScriptId>, source: &String) -> Result<(), Error> {
        if self.runners.contains_key(id) {
            return Err(Error::RunError(RunError::StartStopError(StartStopError::AlreadyRunning)));
        }
        let mut runner = Execution::<Env>::new();
        let tx_id = id.clone();
        let tx = self.tx.map(move |event| {
            (tx_id.clone(), event)
        });
        let parsed_source = try!(Script::from_str(source));
        try!(runner.start(self.env.clone(), parsed_source, tx));
        self.runners.insert(id.clone(), runner);
        Ok(())
    }
}

impl From<rusqlite::Error> for Error {
    fn from(err: rusqlite::Error) -> Error {
        Error::SQLError(format!("{:?}", err))
    }
}

impl From<RunError> for Error {
    fn from(err: RunError) -> Error {
        Error::RunError(err)
    }
}

impl From<ParseError> for Error {
    fn from(err: ParseError) -> Error {
        Error::ParseError(format!("{:?}", err))
    }
}
<|endoftext|>


<commit_before>//! Assertions for array

use ndarray::*;

use super::norm::*;
use super::types::*;

/// check two values are close in terms of the relative torrence
pub fn rclose<A: Scalar>(test: A, truth: A, rtol: A::Real) -> Result<A::Real, A::Real> {
    let dev = (test - truth).abs() / truth.abs();
    if dev < rtol { Ok(dev) } else { Err(dev) }
}

/// check two values are close in terms of the absolute torrence
pub fn aclose<A: Scalar>(test: A, truth: A, atol: A::Real) -> Result<A::Real, A::Real> {
    let dev = (test - truth).abs();
    if dev < atol { Ok(dev) } else { Err(dev) }
}

/// check two arrays are close in maximum norm
pub fn close_max<A, S1, S2, D>(
    test: &ArrayBase<S1, D>,
    truth: &ArrayBase<S2, D>,
    atol: A::Real,
) -> Result<A::Real, A::Real>
where
    A: Scalar,
    S1: Data<Elem = A>,
    S2: Data<Elem = A>,
    D: Dimension,
{
    let tol = (test - truth).norm_max();
    if tol < atol { Ok(tol) } else { Err(tol) }
}

/// check two arrays are close in L1 norm
pub fn close_l1<A, S1, S2, D>(
    test: &ArrayBase<S1, D>,
    truth: &ArrayBase<S2, D>,
    rtol: A::Real,
) -> Result<A::Real, A::Real>
where
    A: Scalar,
    S1: Data<Elem = A>,
    S2: Data<Elem = A>,
    D: Dimension,
{
    let tol = (test - truth).norm_l1() / truth.norm_l1();
    if tol < rtol { Ok(tol) } else { Err(tol) }
}

/// check two arrays are close in L2 norm
pub fn close_l2<A, S1, S2, D>(
    test: &ArrayBase<S1, D>,
    truth: &ArrayBase<S2, D>,
    rtol: A::Real,
) -> Result<A::Real, A::Real>
where
    A: Scalar,
    S1: Data<Elem = A>,
    S2: Data<Elem = A>,
    D: Dimension,
{
    let tol = (test - truth).norm_l2() / truth.norm_l2();
    if tol < rtol { Ok(tol) } else { Err(tol) }
}

macro_rules! generate_assert {
    ($assert:ident, $close:path) => {
#[macro_export]
macro_rules! $assert {
    ($test:expr, $truth:expr, $tol:expr) => {
        $close($test, $truth, $tol).unwrap();
    };
    ($test:expr, $truth:expr, $tol:expr; $comment:expr) => {
        $close($test, $truth, $tol).expect($comment);
    };
}
}} // generate_assert!

generate_assert!(assert_rclose, rclose);
generate_assert!(assert_aclose, aclose);
generate_assert!(assert_close_max, close_max);
generate_assert!(assert_close_l1, close_l1);
generate_assert!(assert_close_l2, close_l2);
<commit_msg>Add $crate for macro generator<commit_after>//! Assertions for array

use ndarray::*;

use super::norm::*;
use super::types::*;

/// check two values are close in terms of the relative torrence
pub fn rclose<A: Scalar>(test: A, truth: A, rtol: A::Real) -> Result<A::Real, A::Real> {
    let dev = (test - truth).abs() / truth.abs();
    if dev < rtol { Ok(dev) } else { Err(dev) }
}

/// check two values are close in terms of the absolute torrence
pub fn aclose<A: Scalar>(test: A, truth: A, atol: A::Real) -> Result<A::Real, A::Real> {
    let dev = (test - truth).abs();
    if dev < atol { Ok(dev) } else { Err(dev) }
}

/// check two arrays are close in maximum norm
pub fn close_max<A, S1, S2, D>(
    test: &ArrayBase<S1, D>,
    truth: &ArrayBase<S2, D>,
    atol: A::Real,
) -> Result<A::Real, A::Real>
where
    A: Scalar,
    S1: Data<Elem = A>,
    S2: Data<Elem = A>,
    D: Dimension,
{
    let tol = (test - truth).norm_max();
    if tol < atol { Ok(tol) } else { Err(tol) }
}

/// check two arrays are close in L1 norm
pub fn close_l1<A, S1, S2, D>(
    test: &ArrayBase<S1, D>,
    truth: &ArrayBase<S2, D>,
    rtol: A::Real,
) -> Result<A::Real, A::Real>
where
    A: Scalar,
    S1: Data<Elem = A>,
    S2: Data<Elem = A>,
    D: Dimension,
{
    let tol = (test - truth).norm_l1() / truth.norm_l1();
    if tol < rtol { Ok(tol) } else { Err(tol) }
}

/// check two arrays are close in L2 norm
pub fn close_l2<A, S1, S2, D>(
    test: &ArrayBase<S1, D>,
    truth: &ArrayBase<S2, D>,
    rtol: A::Real,
) -> Result<A::Real, A::Real>
where
    A: Scalar,
    S1: Data<Elem = A>,
    S2: Data<Elem = A>,
    D: Dimension,
{
    let tol = (test - truth).norm_l2() / truth.norm_l2();
    if tol < rtol { Ok(tol) } else { Err(tol) }
}

macro_rules! generate_assert {
    ($assert:ident, $close:path) => {
#[macro_export]
macro_rules! $assert {
    ($test:expr, $truth:expr, $tol:expr) => {
        $crate::$close($test, $truth, $tol).unwrap();
    };
    ($test:expr, $truth:expr, $tol:expr; $comment:expr) => {
        $crate::$close($test, $truth, $tol).expect($comment);
    };
}
}} // generate_assert!

generate_assert!(assert_rclose, rclose);
generate_assert!(assert_aclose, aclose);
generate_assert!(assert_close_max, close_max);
generate_assert!(assert_close_l1, close_l1);
generate_assert!(assert_close_l2, close_l2);
<|endoftext|>