<commit_before>use Push;
use Commit;
use config::Config;
use taste::TastingResult;
use github_rs::StatusCode;
use github_rs::client::{Executor, Github};
use serde_json;

pub struct GithubNotifier {
    api_token: String,
}

#[derive(Deserialize)]
struct GithubError {
    message: String,
}

#[derive(Serialize)]
struct Payload {
    state: String,
    description: String,
    context: String,
}

impl GithubNotifier {
    pub fn new(api_token: &str) -> GithubNotifier {
        GithubNotifier {
            api_token: String::from(api_token),
        }
    }

    fn post_status(&self, push: &Push, commit: &Commit, payload: &Payload) -> Result<(), String> {
        let owner_name = push.owner_name.clone().unwrap();
        let repo_name = push.repo_name.clone().unwrap();
        println!(
            "Setting status of {}/{}#{} to {}",
            owner_name,
            repo_name,
            commit.id,
            payload.state
        );

        let client = Github::new(self.api_token.clone()).unwrap();
        let result = client
            .post(payload)
            .repos()
            .owner(owner_name.as_str())
            .repo(repo_name.as_str())
            .statuses()
            .sha(&commit.id.to_string())
            .execute::<serde_json::Value>();

        match result {
            Ok((_, StatusCode::Created, Some(_))) => Ok(()),
            Ok((_, status_code, Some(response))) => serde_json::from_value::<GithubError>(response)
                .map_err(|err| {
                    format!("Failed to parse error response ({}): {}", status_code, err)
                })
                .and_then(|err| Err(err.message.into())),
            Ok((_, _, None)) => Err("Received error response from GitHub with no message".into()),
            Err(err) => Err(format!("Failed to execute GitHub request: {}", err)),
        }
    }

    pub fn notify_pending(&self, push: &Push, commit: &Commit) -> Result<(), String> {
        let payload = Payload {
            context: "Taster".to_string(),
            state: "pending".to_string(),
            description: "Currently tasting...".to_string(),
        };

        self.post_status(push, commit, &payload)
    }

    pub fn notify(
        &self,
        _cfg: Option<&Config>,
        res: &TastingResult,
        push: &Push,
        commit: &Commit,
    ) -> Result<(), String> {
        let state = if !res.build || !res.test || !res.bench {
            "failure"
        } else {
            "success"
        };

        let taste = if !res.build || !res.bench {
            "was inedible"
        } else if !res.test {
            "had a mixed palate"
        } else {
            "tasted nice"
        };

        let payload = Payload {
            context: "Taster".to_string(),
            state: state.to_string(),
            description: format!("It {}.", taste),
        };

        self.post_status(push, commit, &payload)
    }
}
<commit_msg>Don't pass Payload as a reference<commit_after>use Push;
use Commit;
use config::Config;
use taste::TastingResult;
use github_rs::StatusCode;
use github_rs::client::{Executor, Github};
use serde_json;

pub struct GithubNotifier {
    api_token: String,
}

#[derive(Deserialize)]
struct GithubError {
    message: String,
}

#[derive(Serialize)]
struct Payload {
    state: String,
    description: String,
    context: String,
}

impl GithubNotifier {
    pub fn new(api_token: &str) -> GithubNotifier {
        GithubNotifier {
            api_token: String::from(api_token),
        }
    }

    fn post_status(&self, push: &Push, commit: &Commit, payload: Payload) -> Result<(), String> {
        let owner_name = push.owner_name.clone().unwrap();
        let repo_name = push.repo_name.clone().unwrap();
        println!(
            "Setting status of {}/{}#{} to {}",
            owner_name,
            repo_name,
            commit.id,
            payload.state
        );

        let client = Github::new(self.api_token.clone()).unwrap();
        let result = client
            .post(&payload)
            .repos()
            .owner(owner_name.as_str())
            .repo(repo_name.as_str())
            .statuses()
            .sha(&commit.id.to_string())
            .execute::<serde_json::Value>();

        match result {
            Ok((_, StatusCode::Created, Some(_))) => Ok(()),
            Ok((_, status_code, Some(response))) => serde_json::from_value::<GithubError>(response)
                .map_err(|err| {
                    format!("Failed to parse error response ({}): {}", status_code, err)
                })
                .and_then(|err| Err(err.message.into())),
            Ok((_, _, None)) => Err("Received error response from GitHub with no message".into()),
            Err(err) => Err(format!("Failed to execute GitHub request: {}", err)),
        }
    }

    pub fn notify_pending(&self, push: &Push, commit: &Commit) -> Result<(), String> {
        let payload = Payload {
            context: "Taster".to_string(),
            state: "pending".to_string(),
            description: "Currently tasting...".to_string(),
        };

        self.post_status(push, commit, payload)
    }

    pub fn notify(
        &self,
        _cfg: Option<&Config>,
        res: &TastingResult,
        push: &Push,
        commit: &Commit,
    ) -> Result<(), String> {
        let state = if !res.build || !res.test || !res.bench {
            "failure"
        } else {
            "success"
        };

        let taste = if !res.build || !res.bench {
            "was inedible"
        } else if !res.test {
            "had a mixed palate"
        } else {
            "tasted nice"
        };

        let payload = Payload {
            context: "Taster".to_string(),
            state: state.to_string(),
            description: format!("It {}.", taste),
        };

        self.post_status(push, commit, payload)
    }
}
<|endoftext|>


<commit_before>fn main() {
    greet_the_world();

    // * the following two declarations
    //   are the same - aside from identifiers.
    // * they are both immutable.
    // * therefore, they must be initialised
    //   immediately
    let x = 5i;
    let y:int = 5;

    // this declares a mutable variable:
    let mut z = 10i;
    z = 100i; // tada!

    if z >= 50i {
        println!("z is a big number");
    } else {
        println!("z isn't a big number");
    }

    // similar to a ternary operator:
    let a = if x > 1 { true } else { false };
    // (these need semicolons)

    describe_number(200i);
    describe_number(23i);
}

// argument types must be specified
// ... and so must return types
fn describe_number(number: int) -> int {
    println!("the number is {}", number);

    let big = if number > 50 { "is big" } else { "isn't big" };
    println!("the number {}", big);

    number // ruby-esque return statements
           // don't need a semicolon, or else rust
           // would look for another expression to return
           // (and there isn't one, thrfr. the return type
           // would be a lie)
}

// * what follows is a doc comment (notice the triple slash):
// * doc comments support markdown!
// * `rustdoc` will generate HTML documentation from doc comments.

/// `greet_the_world` is a useless function that prints a string
/// that can be used for greeting the world.
///
/// # Arguments
///
/// * there are no arguments
///
/// # Example
///
/// ```rust
/// fn main() {
///     greet_the_world(); // prints 'hello, world'
/// }
/// ```
fn greet_the_world() {
    println!("hello, world");
}

<commit_msg>more rust features shown in try-rust<commit_after>#[allow(unused_variables)]
#[allow(unused_assignments)]

fn main() {
    greet_the_world();

    // * the following two declarations
    //   are the same - aside from identifiers.
    // * they are both immutable.
    // * therefore, they must be initialised
    //   immediately
    let x = 5;
    let y:i32 = 5;

    // this declares a mutable variable:
    let mut z = 10;
    z = 100; // tada!

    if z >= 50 {
        println!("z is a big number");
    } else {
        println!("z isn't a big number");
    }

    // similar to a ternary operator:
    let a = if x > 1 { true } else { false };
    // (these need semicolons)

    describe_number(200);
    describe_number(23);

    iterations();

//  fn  square   (x:i32) { x * x }
    let square = |x:i32| { x * x };
    // see the `twice()` function for a 'proper'
    // use of rust's closures

    println!("the square of {} is {}", 17, square(17));
    println!("twice the square of {} is {}", 29, twice(29, square));
}

fn twice<F: Fn(i32) -> i32>(x: i32, f: F) -> i32 {
    f(x) + f(x)
}

fn describe_number(number: i32) -> i32 {
    println!("the number is {}", number);

    let big = if number > 50 { "is big" } else { "isn't big" };
    println!("the number {}", big);

    number // ruby-esque return statements
           // don't need a semicolon, or else rust
           // would look for another expression to return
           // (and there isn't one, thrfr. the return type
           // would be a lie)
}

fn iterations() {
    let arr = [3, 8, 9, 2, 3, 0, 1, 8, 5, 4];
    for element in arr[0..arr.len()].iter() {
        print!("{}, ", element);
    }
    println!("{}", arr[arr.len() -1 ]);
}

// * what follows is a doc comment (notice the triple slash):
// * doc comments support markdown!
// * `rustdoc` will generate HTML documentation from doc comments.

/// `greet_the_world` is a useless function that prints a string
/// that can be used for greeting the world.
///
/// # Arguments
///
/// * there are no arguments
///
/// # Example
///
/// ```rust
/// fn main() {
///     greet_the_world(); // prints 'hello, world'
/// }
/// ```
fn greet_the_world() {
    println!("hello, world");
}
<|endoftext|>


<commit_before>//! Issues interface

use self::super::{Github, Result, SortDirection, State};
use rep::{Issue, IssueReq, Label};
use rustc_serialize::json;
use std::fmt;
use std::default::Default;
use url::form_urlencoded;

#[derive(Debug, PartialEq)]
pub enum Filter {
    Assigned,
    Created,
    Mentioned,
    Subscribed,
    All,
}

impl fmt::Display for Filter {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f,
               "{}",
               match *self {
                   Filter::Assigned => "assigned",
                   Filter::Created => "created",
                   Filter::Mentioned => "mentioned",
                   Filter::Subscribed => "subscribed",
                   Filter::All => "all",
               })
    }
}

impl Default for Filter {
    fn default() -> Filter {
        Filter::Assigned
    }
}

#[derive(Clone, Debug, PartialEq)]
pub enum Sort {
    Created,
    Updated,
    Comments,
}

impl fmt::Display for Sort {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f,
               "{}",
               match *self {
                   Sort::Created => "created",
                   Sort::Updated => "updated",
                   Sort::Comments => "comments",
               })
    }
}

impl Default for Sort {
    fn default() -> Sort {
        Sort::Created
    }
}

pub struct IssueLabels<'a> {
    github: &'a Github<'a>,
    owner: String,
    repo: String,
    number: u64,
}

impl<'a> IssueLabels<'a> {
    pub fn new<O, R>(github: &'a Github<'a>, owner: O, repo: R, number: u64) -> IssueLabels<'a>
        where O: Into<String>,
              R: Into<String>
    {
        IssueLabels {
            github: github,
            owner: owner.into(),
            repo: repo.into(),
            number: number,
        }
    }

    fn path(&self, more: &str) -> String {
        format!("/repos/{}/{}/issues/{}/labels{}",
                self.owner,
                self.repo,
                self.number,
                more)
    }

    /// add a set of labels to this issue ref
    pub fn add(&self, labels: Vec<&str>) -> Result<Vec<Label>> {
        self.github
            .post::<Vec<Label>>(&self.path(""), try!(json::encode(&labels)).as_bytes())
    }

    /// remove a label from this issue
    pub fn remove(&self, label: &str) -> Result<()> {
        self.github
            .delete(&self.path(&format!("/{}", label)))
    }

    /// replace all labels associated with this issue with a new set.
    /// providing an empty set of labels is the same as clearing the
    /// current labels
    pub fn set(&self, labels: Vec<&str>) -> Result<Vec<Label>> {
        self.github.put::<Vec<Label>>(&self.path(""), try!(json::encode(&labels)).as_bytes())
    }

    /// remove all labels from an issue
    pub fn clear(&self) -> Result<()> {
        self.github
            .delete(&self.path(""))
    }
}

pub struct IssueRef<'a> {
    github: &'a Github<'a>,
    owner: String,
    repo: String,
    number: u64,
}

impl<'a> IssueRef<'a> {
    /// create a new instance of a github repo issue ref
    pub fn new<O, R>(github: &'a Github<'a>, owner: O, repo: R, number: u64) -> IssueRef<'a>
        where O: Into<String>,
              R: Into<String>
    {
        IssueRef {
            github: github,
            owner: owner.into(),
            repo: repo.into(),
            number: number,
        }
    }

    fn path(&self, more: &str) -> String {
        format!("/repos/{}/{}/issues/{}{}",
                self.owner,
                self.repo,
                self.number,
                more)
    }

    pub fn labels(&self) -> IssueLabels {
        IssueLabels::new(self.github,
                         self.owner.as_ref(),
                         self.repo.as_ref(),
                         self.number)
    }

    pub fn edit(&self, is: &IssueReq) -> Result<Issue> {
        let data = try!(json::encode(&is));
        self.github.patch::<Issue>(&self.path(""), data.as_bytes())
    }
}

pub struct Issues<'a> {
    github: &'a Github<'a>,
    owner: String,
    repo: String,
}

pub struct ListReq {
    state: State,
    sort: Sort,
    direction: SortDirection,
    assignee: Option<String>,
    creator: Option<String>,
    mentioned: Option<String>,
    labels: Vec<String>,
    since: Option<String>,
}

impl ListReq {
    pub fn builder() -> ListReqBuilder {
        ListReqBuilder::new()
    }

    pub fn serialize(&self) -> String {
        let mut params = Vec::new();
        params.push(("state", self.state.to_string()));
        params.push(("sort", self.sort.to_string()));
        params.push(("direction", self.direction.to_string()));
        if let Some(ref a) = self.assignee {
            params.push(("assignee", a.to_owned()));
        }
        if let Some(ref c) = self.creator {
            params.push(("creator", c.to_owned()));
        }
        if let Some(ref m) = self.mentioned {
            params.push(("mentioned", m.to_owned()));
        }
        if let Some(ref s) = self.since {
            params.push(("since", s.to_owned()));
        }
        if !self.labels.is_empty() {
            params.push(("labels", self.labels.connect(",")));
        }
        form_urlencoded::serialize(params)
    }
}

/// an mutable issue list builder
#[derive(Default)]
pub struct ListReqBuilder {
    state: State,
    sort: Sort,
    direction: SortDirection,
    assignee: Option<String>,
    creator: Option<String>,
    mentioned: Option<String>,
    labels: Vec<String>,
    since: Option<String>,
}

impl ListReqBuilder {
    pub fn new() -> ListReqBuilder {
        ListReqBuilder { ..Default::default() }
    }

    pub fn state(&mut self, state: State) -> &mut ListReqBuilder {
        self.state = state;
        self
    }

    pub fn sort(&mut self, sort: Sort) -> &mut ListReqBuilder {
        self.sort = sort;
        self
    }

    pub fn direction(&mut self, direction: SortDirection) -> &mut ListReqBuilder {
        self.direction = direction;
        self
    }

    pub fn assignee<A>(&mut self, assignee: A) -> &mut ListReqBuilder
        where A: Into<String>
    {
        self.assignee = Some(assignee.into());
        self
    }

    pub fn creator<C>(&mut self, creator: C) -> &mut ListReqBuilder
        where C: Into<String>
    {
        self.creator = Some(creator.into());
        self
    }

    pub fn mentioned<M>(&mut self, mentioned: M) -> &mut ListReqBuilder
        where M: Into<String>
    {
        self.mentioned = Some(mentioned.into());
        self
    }

    pub fn labels<L>(&mut self, labels: Vec<L>) -> &mut ListReqBuilder
        where L: Into<String>
    {
        self.labels = labels.into_iter().map(|l| l.into()).collect::<Vec<String>>();
        self
    }

    pub fn since<S>(&mut self, since: S) -> &mut ListReqBuilder
        where S: Into<String>
    {
        self.since = Some(since.into());
        self
    }

    pub fn build(&self) -> ListReq {
        ListReq {
            state: self.state.clone(),
            sort: self.sort.clone(),
            direction: self.direction.clone(),
            assignee: self.assignee.clone(),
            creator: self.creator.clone(),
            mentioned: self.mentioned.clone(),
            labels: self.labels.clone(),
            since: self.since.clone(),
        }
    }
}

impl<'a> Issues<'a> {
    /// create a new instance of a github repo issue ref
    pub fn new<O, R>(github: &'a Github<'a>, owner: O, repo: R) -> Issues<'a>
        where O: Into<String>,
              R: Into<String>
    {
        Issues {
            github: github,
            owner: owner.into(),
            repo: repo.into(),
        }
    }

    fn path(&self, more: &str) -> String {
        format!("/repos/{}/{}/issues{}", self.owner, self.repo, more)
    }

    pub fn get(&self, number: u64) -> IssueRef {
        IssueRef::new(self.github, self.owner.as_ref(), self.repo.as_ref(), number)
    }

    pub fn create(&self, is: &IssueReq) -> Result<Issue> {
        let data = try!(json::encode(&is));
        self.github.post::<Issue>(&self.path(""), data.as_bytes())
    }

    pub fn list(&self, req: &ListReq) -> Result<Vec<Issue>> {
        let url = self.path(&format!("?{}", req.serialize()));
        self.github.get::<Vec<Issue>>(&url)
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use super::super::*;

    #[test]
    fn list_reqs() {
        fn test_serialize(tests: Vec<(ListReq, &str)>) {
            for test in tests {
                match test {
                    (k, v) => assert_eq!(k.serialize(), v),
                }
            }
        }
        let tests = vec![
            (
                ListReq::builder().build(),
                "state=open&sort=created&direction=asc"
            ),
            (
                ListReq::builder().state(State::Closed).build(),
                "state=closed&sort=created&direction=asc"
             ),
            (
                ListReq::builder().labels(vec!["foo", "bar"]).build(),
                "state=open&sort=created&direction=asc&labels=foo%2Cbar"
            ),
        ];
        test_serialize(tests)
    }

    #[test]
    fn filter_default() {
        let default: Filter = Default::default();
        assert_eq!(default, Filter::Assigned)
    }

    #[test]
    fn filter_display() {
        for (k, v) in vec![
            (Filter::Assigned, "assigned"),
            (Filter::Created, "created"),
            (Filter::Mentioned, "mentioned"),
            (Filter::Subscribed, "subscribed"),
            (Filter::All, "all"),
        ] {
            assert_eq!(k.to_string(), v)
        }
    }

    #[test]
    fn sort_default() {
        let default: Sort = Default::default();
        assert_eq!(default, Sort::Created)
    }

    #[test]
    fn sort_display() {
        for (k, v) in vec![(Sort::Created, "created"),
                           (Sort::Updated, "updated"),
                           (Sort::Comments, "comments")] {
            assert_eq!(k.to_string(), v)
        }
    }
}
<commit_msg>name should be more consistent<commit_after>//! Issues interface

use self::super::{Github, Result, SortDirection, State};
use rep::{Issue, IssueReq, Label};
use rustc_serialize::json;
use std::fmt;
use std::default::Default;
use url::form_urlencoded;

#[derive(Debug, PartialEq)]
pub enum Filter {
    Assigned,
    Created,
    Mentioned,
    Subscribed,
    All,
}

impl fmt::Display for Filter {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f,
               "{}",
               match *self {
                   Filter::Assigned => "assigned",
                   Filter::Created => "created",
                   Filter::Mentioned => "mentioned",
                   Filter::Subscribed => "subscribed",
                   Filter::All => "all",
               })
    }
}

impl Default for Filter {
    fn default() -> Filter {
        Filter::Assigned
    }
}

#[derive(Clone, Debug, PartialEq)]
pub enum Sort {
    Created,
    Updated,
    Comments,
}

impl fmt::Display for Sort {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f,
               "{}",
               match *self {
                   Sort::Created => "created",
                   Sort::Updated => "updated",
                   Sort::Comments => "comments",
               })
    }
}

impl Default for Sort {
    fn default() -> Sort {
        Sort::Created
    }
}

pub struct IssueLabels<'a> {
    github: &'a Github<'a>,
    owner: String,
    repo: String,
    number: u64,
}

impl<'a> IssueLabels<'a> {
    pub fn new<O, R>(github: &'a Github<'a>, owner: O, repo: R, number: u64) -> IssueLabels<'a>
        where O: Into<String>,
              R: Into<String>
    {
        IssueLabels {
            github: github,
            owner: owner.into(),
            repo: repo.into(),
            number: number,
        }
    }

    fn path(&self, more: &str) -> String {
        format!("/repos/{}/{}/issues/{}/labels{}",
                self.owner,
                self.repo,
                self.number,
                more)
    }

    /// add a set of labels to this issue ref
    pub fn add(&self, labels: Vec<&str>) -> Result<Vec<Label>> {
        self.github
            .post::<Vec<Label>>(&self.path(""), try!(json::encode(&labels)).as_bytes())
    }

    /// remove a label from this issue
    pub fn remove(&self, label: &str) -> Result<()> {
        self.github
            .delete(&self.path(&format!("/{}", label)))
    }

    /// replace all labels associated with this issue with a new set.
    /// providing an empty set of labels is the same as clearing the
    /// current labels
    pub fn set(&self, labels: Vec<&str>) -> Result<Vec<Label>> {
        self.github.put::<Vec<Label>>(&self.path(""), try!(json::encode(&labels)).as_bytes())
    }

    /// remove all labels from an issue
    pub fn clear(&self) -> Result<()> {
        self.github
            .delete(&self.path(""))
    }
}

pub struct IssueRef<'a> {
    github: &'a Github<'a>,
    owner: String,
    repo: String,
    number: u64,
}

impl<'a> IssueRef<'a> {
    /// create a new instance of a github repo issue ref
    pub fn new<O, R>(github: &'a Github<'a>, owner: O, repo: R, number: u64) -> IssueRef<'a>
        where O: Into<String>,
              R: Into<String>
    {
        IssueRef {
            github: github,
            owner: owner.into(),
            repo: repo.into(),
            number: number,
        }
    }

    fn path(&self, more: &str) -> String {
        format!("/repos/{}/{}/issues/{}{}",
                self.owner,
                self.repo,
                self.number,
                more)
    }

    pub fn labels(&self) -> IssueLabels {
        IssueLabels::new(self.github,
                         self.owner.as_ref(),
                         self.repo.as_ref(),
                         self.number)
    }

    pub fn edit(&self, is: &IssueReq) -> Result<Issue> {
        let data = try!(json::encode(&is));
        self.github.patch::<Issue>(&self.path(""), data.as_bytes())
    }
}

pub struct Issues<'a> {
    github: &'a Github<'a>,
    owner: String,
    repo: String,
}

pub struct IssueListReq {
    state: State,
    sort: Sort,
    direction: SortDirection,
    assignee: Option<String>,
    creator: Option<String>,
    mentioned: Option<String>,
    labels: Vec<String>,
    since: Option<String>,
}

impl IssueListReq {
    pub fn builder() -> IssueListReqBuilder {
        IssueListReqBuilder::new()
    }

    pub fn serialize(&self) -> String {
        let mut params = Vec::new();
        params.push(("state", self.state.to_string()));
        params.push(("sort", self.sort.to_string()));
        params.push(("direction", self.direction.to_string()));
        if let Some(ref a) = self.assignee {
            params.push(("assignee", a.to_owned()));
        }
        if let Some(ref c) = self.creator {
            params.push(("creator", c.to_owned()));
        }
        if let Some(ref m) = self.mentioned {
            params.push(("mentioned", m.to_owned()));
        }
        if let Some(ref s) = self.since {
            params.push(("since", s.to_owned()));
        }
        if !self.labels.is_empty() {
            params.push(("labels", self.labels.connect(",")));
        }
        form_urlencoded::serialize(params)
    }
}

/// a mutable issue list builder
#[derive(Default)]
pub struct IssueListReqBuilder {
    state: State,
    sort: Sort,
    direction: SortDirection,
    assignee: Option<String>,
    creator: Option<String>,
    mentioned: Option<String>,
    labels: Vec<String>,
    since: Option<String>,
}

impl IssueListReqBuilder {
    pub fn new() -> IssueListReqBuilder {
        IssueListReqBuilder { ..Default::default() }
    }

    pub fn state(&mut self, state: State) -> &mut IssueListReqBuilder {
        self.state = state;
        self
    }

    pub fn sort(&mut self, sort: Sort) -> &mut IssueListReqBuilder {
        self.sort = sort;
        self
    }

    pub fn direction(&mut self, direction: SortDirection) -> &mut IssueListReqBuilder {
        self.direction = direction;
        self
    }

    pub fn assignee<A>(&mut self, assignee: A) -> &mut IssueListReqBuilder
        where A: Into<String>
    {
        self.assignee = Some(assignee.into());
        self
    }

    pub fn creator<C>(&mut self, creator: C) -> &mut IssueListReqBuilder
        where C: Into<String>
    {
        self.creator = Some(creator.into());
        self
    }

    pub fn mentioned<M>(&mut self, mentioned: M) -> &mut IssueListReqBuilder
        where M: Into<String>
    {
        self.mentioned = Some(mentioned.into());
        self
    }

    pub fn labels<L>(&mut self, labels: Vec<L>) -> &mut IssueListReqBuilder
        where L: Into<String>
    {
        self.labels = labels.into_iter().map(|l| l.into()).collect::<Vec<String>>();
        self
    }

    pub fn since<S>(&mut self, since: S) -> &mut IssueListReqBuilder
        where S: Into<String>
    {
        self.since = Some(since.into());
        self
    }

    pub fn build(&self) -> IssueListReq {
        IssueListReq {
            state: self.state.clone(),
            sort: self.sort.clone(),
            direction: self.direction.clone(),
            assignee: self.assignee.clone(),
            creator: self.creator.clone(),
            mentioned: self.mentioned.clone(),
            labels: self.labels.clone(),
            since: self.since.clone(),
        }
    }
}

impl<'a> Issues<'a> {
    /// create a new instance of a github repo issue ref
    pub fn new<O, R>(github: &'a Github<'a>, owner: O, repo: R) -> Issues<'a>
        where O: Into<String>,
              R: Into<String>
    {
        Issues {
            github: github,
            owner: owner.into(),
            repo: repo.into(),
        }
    }

    fn path(&self, more: &str) -> String {
        format!("/repos/{}/{}/issues{}", self.owner, self.repo, more)
    }

    pub fn get(&self, number: u64) -> IssueRef {
        IssueRef::new(self.github, self.owner.as_ref(), self.repo.as_ref(), number)
    }

    pub fn create(&self, is: &IssueReq) -> Result<Issue> {
        let data = try!(json::encode(&is));
        self.github.post::<Issue>(&self.path(""), data.as_bytes())
    }

    pub fn list(&self, req: &IssueListReq) -> Result<Vec<Issue>> {
        let url = self.path(&format!("?{}", req.serialize()));
        self.github.get::<Vec<Issue>>(&url)
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use super::super::*;

    #[test]
    fn list_reqs() {
        fn test_serialize(tests: Vec<(IssueListReq, &str)>) {
            for test in tests {
                match test {
                    (k, v) => assert_eq!(k.serialize(), v),
                }
            }
        }
        let tests = vec![
            (
                IssueListReq::builder().build(),
                "state=open&sort=created&direction=asc"
            ),
            (
                IssueListReq::builder().state(State::Closed).build(),
                "state=closed&sort=created&direction=asc"
             ),
            (
                IssueListReq::builder().labels(vec!["foo", "bar"]).build(),
                "state=open&sort=created&direction=asc&labels=foo%2Cbar"
            ),
        ];
        test_serialize(tests)
    }

    #[test]
    fn filter_default() {
        let default: Filter = Default::default();
        assert_eq!(default, Filter::Assigned)
    }

    #[test]
    fn filter_display() {
        for (k, v) in vec![
            (Filter::Assigned, "assigned"),
            (Filter::Created, "created"),
            (Filter::Mentioned, "mentioned"),
            (Filter::Subscribed, "subscribed"),
            (Filter::All, "all"),
        ] {
            assert_eq!(k.to_string(), v)
        }
    }

    #[test]
    fn sort_default() {
        let default: Sort = Default::default();
        assert_eq!(default, Sort::Created)
    }

    #[test]
    fn sort_display() {
        for (k, v) in vec![(Sort::Created, "created"),
                           (Sort::Updated, "updated"),
                           (Sort::Comments, "comments")] {
            assert_eq!(k.to_string(), v)
        }
    }
}
<|endoftext|>


<commit_before>/// TODO: parse and return flags per DSO, add as entry to the struct
/// TODO: fix the high address mapperr for `__libc_start_main`

use std::fs::File;
use std::os::unix::io::AsRawFd;
use std::os::raw::{c_int};

use utils::{self, mmap, page};
use image::SharedObject;
use binary::elf::header;
use binary::elf::program_header;
use binary::elf::dyn;
use binary::elf::sym;
use binary::elf::rela;
use binary::elf::strtab::Strtab;
use binary::elf::gnu_hash::GnuHash;

#[inline(always)]
fn compute_load_size (phdrs: &[program_header::ProgramHeader]) -> (usize, u64, u64) {
    let mut max_vaddr = 0;
    let mut min_vaddr = 0;
    for phdr in phdrs {

        if phdr.p_type != program_header::PT_LOAD {
            continue
        }

        if phdr.p_vaddr < min_vaddr {
            min_vaddr = phdr.p_vaddr;
        }

        if phdr.p_vaddr + phdr.p_memsz > max_vaddr {
            max_vaddr = phdr.p_vaddr + phdr.p_memsz;
        }
    }

    min_vaddr = page::page_start(min_vaddr);
    max_vaddr = page::page_end(max_vaddr);

    ((max_vaddr - min_vaddr) as usize, min_vaddr, max_vaddr)
}

#[inline(always)]
fn reserve_address_space (phdrs: &[program_header::ProgramHeader]) -> Result <(u64, u64, u64), String> {

    let (size, min_vaddr, max_vaddr) = compute_load_size(&phdrs);

    let mmap_flags = mmap::MAP_PRIVATE | mmap::MAP_ANONYMOUS;
    let start = unsafe { mmap::mmap(0 as *const u64,
                                    size,
                                    // for now, using PROT_NONE seems to give SEGV_ACCERR on execution of PT_LOAD mmaped segments (i.e., operation not allowed on mapped object)
                                    mmap::PROT_EXEC | mmap::PROT_READ | mmap::PROT_WRITE,
                                    mmap_flags as c_int,  // TODO: I think we should copy glibc's lead here and use their mmap flags
                                    -1,
                                    0) };

    if start == mmap::MAP_FAILED {

        Err (format!("Error: anonymous mmap failed for size {:x} with errno {}", size, utils::get_errno()))

    } else {

        let load_bias = start - min_vaddr;
        let end = start + size as u64;
        Ok ((start, load_bias, end))
    }
}

#[inline(always)]
fn pflags_to_prot (x: u32) -> isize {
    use binary::elf::program_header::{PF_X, PF_R, PF_W};

    // I'm a dick for writing this/copying maniac C programmer implementations: but it checks the flag to see if it's the PF value,
    // and returns the appropriate mmap version, and logical ORs this for use in the mmap prot argument
    (if x & PF_X == PF_X { mmap::PROT_EXEC } else { 0 }) |
    (if x & PF_R == PF_R { mmap::PROT_READ } else { 0 }) |
    (if x & PF_W == PF_W { mmap::PROT_WRITE } else { 0 })
}

/// Loads an ELF binary from the given fd, mmaps its contents, and returns a SharedObject, whose lifetime is tied to the mmap's, i.e., manually managed
pub fn load<'a> (soname: &str, load_path: String, fd: &mut File, debug: bool) -> Result <SharedObject<'a>, String> {

    ///////////////
    // Part I:
    //   wherein we read the binary from disk,
    //   and lovingly mmap it's joyous contents
    ///////////////

    // 1. Suck up the elf header on disk and construct the program headers
    let ehdr = header::Header::from_fd(fd).map_err(|e| format!("Error {:?}", e))?;
    let phdrs = program_header::ProgramHeader::from_fd(fd, ehdr.e_phoff, ehdr.e_phnum as usize).map_err(|e| format!("Error {:?}", e))?;

    // 2. Reserve address space with anon mmap
    let (start, load_bias, end) = reserve_address_space(&phdrs)?;
    dbgc!(red_bold: debug, "loader", "reserved {:#x} - {:#x} with load_bias: 0x{:x}", start, end, load_bias);

    // 3. Now we iterate through the phdrs, and
    // a. mmap the PT_LOAD program headers
    // b. collect the vaddrs of the phdrs and the dynamic array
    // c. TODO: mmap and setup TLS
    let mut phdrs_vaddr = 0;
    let mut dynamic_vaddr = None;
    let mut has_pt_load = false;
    for phdr in &phdrs {

        match phdr.p_type {

            program_header::PT_LOAD => {
                has_pt_load = true;
                // Segment offsets: rounds down the segment start to a value suitable for mmaping, and adjusts the size of the
                // mmap breadth appropriately
                let seg_start: u64 = phdr.p_vaddr + load_bias;
                let seg_end: u64   = seg_start + phdr.p_memsz;

                let seg_page_start: u64 = page::page_start(seg_start);
                let seg_page_end: u64   = page::page_start(seg_end);

                // TODO: unused, I think we need to zero some stuff
                let seg_file_end: u64 = seg_start + phdr.p_filesz;

                // File offsets.
                let file_start: u64 = phdr.p_offset;
                let file_end: u64   = file_start + phdr.p_filesz;

                // "rounds" to an mmap-able value (i.e., file_start % pagesize)
                // file_page_start <= file_start
                // so sometimes the beginning of the page is not the beginning of the PT_LOAD!
                let file_page_start = page::page_start(file_start);
                let file_length: u64 = file_end - file_page_start;

                // TODO: add error checking, if file size <= 0, if file_end greater than file_size, etc.

                dbgc!(red_bold: debug, "loader", "PT_LOAD:\n\tseg_start: {:x} seg_end: {:x} seg_page_start: {:x} seg_page_end: {:x} seg_file_end: {:x}\n\tfile_start: {:x} file_end: {:x} file_page_start: {:x} file_length: {:x}", seg_start, seg_end, seg_page_start, seg_page_end, seg_file_end, file_start, file_end, file_page_start, file_length);

                if file_length != 0 {
                    let mmap_flags = mmap::MAP_FIXED | mmap::MAP_PRIVATE;
                    let prot_flags = pflags_to_prot(phdr.p_flags);
                    unsafe {
                        let start = mmap::mmap(seg_page_start as *const u64,
                                               file_length as usize,
                                               prot_flags,
                                               mmap_flags as c_int,
                                               fd.as_raw_fd() as c_int,
                                               file_page_start as usize);

                        if start == mmap::MAP_FAILED {

                            return Err(format!("Error: loader loading phdrs for {} failed with errno {}, aborting execution", &soname, utils::get_errno()))
                        }
                    }

                    // TODO: other more boring shit to do with zero'd out extra pages if too big, etc.
                    //seg_file_end = page::page_end(seg_file_end);

                }
            } // end match PT_LOAD

            program_header::PT_PHDR => {
                phdrs_vaddr = phdr.p_vaddr;
            },
            program_header::PT_DYNAMIC => {
                dynamic_vaddr = Some(phdr.p_vaddr);
            },
            _ => () // do nothing, i.e., continue
        }
    }

    if !has_pt_load {
        return Err(format!("Error: loader {} has no PT_LOAD sections", soname));
    }

    ///////////////
    // Part Deux:
    //   wherein we construct our components for this SharedObject
    //   from the newly mmap'd memory
    ///////////////

    // use the now mmap'd program headers
    let phdrs = unsafe { program_header::ProgramHeader::from_raw_parts((phdrs_vaddr + load_bias) as *const program_header::ProgramHeader, phdrs.len()) };

    // construct the dynamic slice in whatever mmap'd PT_LOAD it's in
    let dynamic_vaddr = dynamic_vaddr.ok_or(format!("Error: loader {} has no dynamic array", soname))?;
    let dynamic = unsafe { dyn::from_raw(load_bias, dynamic_vaddr) };

    // build the link info with the bias and the dynamic array
    let link_info = dyn::LinkInfo::new(&dynamic, load_bias as usize);

    // now get the strtab from the dynamic array
    let strtab = unsafe { Strtab::from_raw(link_info.strtab as *const u8, link_info.strsz as usize) };

    // now get the libs we will need
    let libs = dyn::get_needed(dynamic, &strtab, link_info.needed_count);

    // caveat about rdr doing this for hundres of binaries and it being "ok"
    let num_syms = (link_info.strtab - link_info.symtab) / sym::SIZEOF_SYM;

    // now construct the symtab
    let symtab = unsafe { sym::from_raw(link_info.symtab as *const sym::Sym, num_syms) };

    // now grab relatab, and pltreltab which we'll use for relocating this shared object later
    let relatab = unsafe { rela::from_raw(link_info.rela as *const rela::Rela, link_info.relasz) };
    let pltrelatab = unsafe { rela::from_raw(link_info.jmprel as *const rela::Rela, link_info.pltrelsz) };

    // the pltgot we need for doing lazy dynamic linking
    let pltgot = if let Some(addr) = link_info.pltgot { addr } else { 0 }; // musl doesn't have a PLTGOT, for example

    // and finally grab the gnu_hash (if it has one)
    let gnu_hash = if let Some(addr) = link_info.gnu_hash { Some (GnuHash::new(addr as *const u32, symtab.len())) } else { None };

    let shared_object = SharedObject {
        name: strtab.get(link_info.soname),
        load_bias: load_bias,
        libs: libs,
        map_begin: start,
        map_end: end,
        phdrs: phdrs,
        dynamic: dynamic,
        symtab: symtab,
        strtab: strtab,
        relatab: relatab,
        pltrelatab: pltrelatab,
        pltgot: pltgot as *const u64,
        gnu_hash: gnu_hash,
        load_path: Some (load_path),
        flags: link_info.flags,
        state_flags: link_info.flags_1,
    };

    Ok (shared_object)
}
<commit_msg>loader: move src location of PT_PHDR and PT_DYNAMIC<commit_after>/// TODO: parse and return flags per DSO, add as entry to the struct
/// TODO: fix the high address mapperr for `__libc_start_main`

use std::fs::File;
use std::os::unix::io::AsRawFd;
use std::os::raw::{c_int};

use utils::{self, mmap, page};
use image::SharedObject;
use binary::elf::header;
use binary::elf::program_header;
use binary::elf::dyn;
use binary::elf::sym;
use binary::elf::rela;
use binary::elf::strtab::Strtab;
use binary::elf::gnu_hash::GnuHash;

#[inline(always)]
fn compute_load_size (phdrs: &[program_header::ProgramHeader]) -> (usize, u64, u64) {
    let mut max_vaddr = 0;
    let mut min_vaddr = 0;
    for phdr in phdrs {

        if phdr.p_type != program_header::PT_LOAD {
            continue
        }

        if phdr.p_vaddr < min_vaddr {
            min_vaddr = phdr.p_vaddr;
        }

        if phdr.p_vaddr + phdr.p_memsz > max_vaddr {
            max_vaddr = phdr.p_vaddr + phdr.p_memsz;
        }
    }

    min_vaddr = page::page_start(min_vaddr);
    max_vaddr = page::page_end(max_vaddr);

    ((max_vaddr - min_vaddr) as usize, min_vaddr, max_vaddr)
}

#[inline(always)]
fn reserve_address_space (phdrs: &[program_header::ProgramHeader]) -> Result <(u64, u64, u64), String> {

    let (size, min_vaddr, max_vaddr) = compute_load_size(&phdrs);

    let mmap_flags = mmap::MAP_PRIVATE | mmap::MAP_ANONYMOUS;
    let start = unsafe { mmap::mmap(0 as *const u64,
                                    size,
                                    // for now, using PROT_NONE seems to give SEGV_ACCERR on execution of PT_LOAD mmaped segments (i.e., operation not allowed on mapped object)
                                    mmap::PROT_EXEC | mmap::PROT_READ | mmap::PROT_WRITE,
                                    mmap_flags as c_int,  // TODO: I think we should copy glibc's lead here and use their mmap flags
                                    -1,
                                    0) };

    if start == mmap::MAP_FAILED {

        Err (format!("Error: anonymous mmap failed for size {:x} with errno {}", size, utils::get_errno()))

    } else {

        let load_bias = start - min_vaddr;
        let end = start + size as u64;
        Ok ((start, load_bias, end))
    }
}

#[inline(always)]
fn pflags_to_prot (x: u32) -> isize {
    use binary::elf::program_header::{PF_X, PF_R, PF_W};

    // I'm a dick for writing this/copying maniac C programmer implementations: but it checks the flag to see if it's the PF value,
    // and returns the appropriate mmap version, and logical ORs this for use in the mmap prot argument
    (if x & PF_X == PF_X { mmap::PROT_EXEC } else { 0 }) |
    (if x & PF_R == PF_R { mmap::PROT_READ } else { 0 }) |
    (if x & PF_W == PF_W { mmap::PROT_WRITE } else { 0 })
}

/// Loads an ELF binary from the given fd, mmaps its contents, and returns a SharedObject, whose lifetime is tied to the mmap's, i.e., manually managed
pub fn load<'a> (soname: &str, load_path: String, fd: &mut File, debug: bool) -> Result <SharedObject<'a>, String> {

    ///////////////
    // Part I:
    //   wherein we read the binary from disk,
    //   and lovingly mmap it's joyous contents
    ///////////////

    // 1. Suck up the elf header on disk and construct the program headers
    let ehdr = header::Header::from_fd(fd).map_err(|e| format!("Error {:?}", e))?;
    let phdrs = program_header::ProgramHeader::from_fd(fd, ehdr.e_phoff, ehdr.e_phnum as usize).map_err(|e| format!("Error {:?}", e))?;

    // 2. Reserve address space with anon mmap
    let (start, load_bias, end) = reserve_address_space(&phdrs)?;
    dbgc!(red_bold: debug, "loader", "reserved {:#x} - {:#x} with load_bias: 0x{:x}", start, end, load_bias);

    // 3. Now we iterate through the phdrs, and
    // a. mmap the PT_LOAD program headers
    // b. collect the vaddrs of the phdrs and the dynamic array
    // c. TODO: mmap and setup TLS
    let mut phdrs_vaddr = 0;
    let mut dynamic_vaddr = None;
    let mut has_pt_load = false;
    for phdr in &phdrs {

        match phdr.p_type {

            program_header::PT_PHDR => {
                phdrs_vaddr = phdr.p_vaddr;
            },

            program_header::PT_DYNAMIC => {
                dynamic_vaddr = Some(phdr.p_vaddr);
            },

            program_header::PT_LOAD => {
                has_pt_load = true;
                // Segment offsets: rounds down the segment start to a value suitable for mmaping, and adjusts the size of the
                // mmap breadth appropriately
                let seg_start: u64 = phdr.p_vaddr + load_bias;
                let seg_end: u64   = seg_start + phdr.p_memsz;

                let seg_page_start: u64 = page::page_start(seg_start);
                let seg_page_end: u64   = page::page_start(seg_end);

                // TODO: unused, I think we need to zero some stuff
                let seg_file_end: u64 = seg_start + phdr.p_filesz;

                // File offsets.
                let file_start: u64 = phdr.p_offset;
                let file_end: u64   = file_start + phdr.p_filesz;

                // "rounds" to an mmap-able value (i.e., file_start % pagesize)
                // file_page_start <= file_start
                // so sometimes the beginning of the page is not the beginning of the PT_LOAD!
                let file_page_start = page::page_start(file_start);
                let file_length: u64 = file_end - file_page_start;

                // TODO: add error checking, if file size <= 0, if file_end greater than file_size, etc.

                dbgc!(red_bold: debug, "loader", "PT_LOAD:\n\tseg_start: {:x} seg_end: {:x} seg_page_start: {:x} seg_page_end: {:x} seg_file_end: {:x}\n\tfile_start: {:x} file_end: {:x} file_page_start: {:x} file_length: {:x}", seg_start, seg_end, seg_page_start, seg_page_end, seg_file_end, file_start, file_end, file_page_start, file_length);

                if file_length != 0 {
                    let mmap_flags = mmap::MAP_FIXED | mmap::MAP_PRIVATE;
                    let prot_flags = pflags_to_prot(phdr.p_flags);
                    unsafe {
                        let start = mmap::mmap(seg_page_start as *const u64,
                                               file_length as usize,
                                               prot_flags,
                                               mmap_flags as c_int,
                                               fd.as_raw_fd() as c_int,
                                               file_page_start as usize);

                        if start == mmap::MAP_FAILED {

                            return Err(format!("Error: loader loading phdrs for {} failed with errno {}, aborting execution", &soname, utils::get_errno()))
                        }
                    }

                    // TODO: other more boring shit to do with zero'd out extra pages if too big, etc.
                    //seg_file_end = page::page_end(seg_file_end);

                }
            }, // end match PT_LOAD
            _ => () // do nothing, i.e., continue
        }
    }

    if !has_pt_load {
        return Err(format!("Error: loader {} has no PT_LOAD sections", soname));
    }

    ///////////////
    // Part Deux:
    //   wherein we construct our components for this SharedObject
    //   from the newly mmap'd memory
    ///////////////

    // use the now mmap'd program headers
    let phdrs = unsafe { program_header::ProgramHeader::from_raw_parts((phdrs_vaddr + load_bias) as *const program_header::ProgramHeader, phdrs.len()) };

    // construct the dynamic slice in whatever mmap'd PT_LOAD it's in
    let dynamic_vaddr = dynamic_vaddr.ok_or(format!("Error: loader {} has no dynamic array", soname))?;
    let dynamic = unsafe { dyn::from_raw(load_bias, dynamic_vaddr) };

    // build the link info with the bias and the dynamic array
    let link_info = dyn::LinkInfo::new(&dynamic, load_bias as usize);

    // now get the strtab from the dynamic array
    let strtab = unsafe { Strtab::from_raw(link_info.strtab as *const u8, link_info.strsz as usize) };

    // now get the libs we will need
    let libs = dyn::get_needed(dynamic, &strtab, link_info.needed_count);

    // caveat about rdr doing this for hundres of binaries and it being "ok"
    let num_syms = (link_info.strtab - link_info.symtab) / sym::SIZEOF_SYM;

    // now construct the symtab
    let symtab = unsafe { sym::from_raw(link_info.symtab as *const sym::Sym, num_syms) };

    // now grab relatab, and pltreltab which we'll use for relocating this shared object later
    let relatab = unsafe { rela::from_raw(link_info.rela as *const rela::Rela, link_info.relasz) };
    let pltrelatab = unsafe { rela::from_raw(link_info.jmprel as *const rela::Rela, link_info.pltrelsz) };

    // the pltgot we need for doing lazy dynamic linking
    let pltgot = if let Some(addr) = link_info.pltgot { addr } else { 0 }; // musl doesn't have a PLTGOT, for example

    // and finally grab the gnu_hash (if it has one)
    let gnu_hash = if let Some(addr) = link_info.gnu_hash { Some (GnuHash::new(addr as *const u32, symtab.len())) } else { None };

    let shared_object = SharedObject {
        name: strtab.get(link_info.soname),
        load_bias: load_bias,
        libs: libs,
        map_begin: start,
        map_end: end,
        phdrs: phdrs,
        dynamic: dynamic,
        symtab: symtab,
        strtab: strtab,
        relatab: relatab,
        pltrelatab: pltrelatab,
        pltgot: pltgot as *const u64,
        gnu_hash: gnu_hash,
        load_path: Some (load_path),
        flags: link_info.flags,
        state_flags: link_info.flags_1,
    };

    Ok (shared_object)
}
<|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/.

// A simple logger that sets the max log level to Trace in debug builds and to Info in release ones.

use log::{self, LogRecord, LogLevelFilter, LogMetadata, SetLoggerError};

#[macro_export]
macro_rules! print {
    ($($args:tt)*) => {
        // Ignore logging errors. It's not worth killing the program because of
        // failed debug output. It would be nicer to save the error and report
        // it later, however.
        use core::fmt::Write;
        let mut console = $crate::cc3200::Console {};
        let _ = write!(console, $($args)*);
    }
}

#[macro_export]
macro_rules! println {
    ($fmt:expr)               => ( print!(concat!($fmt, '\n')) );
    ($fmt:expr, $($args:tt)*) => ( print!(concat!($fmt, '\n'), $($args)*) );
}

pub struct SimpleLogger;

#[cfg(debug_assertions)]
static MAX_LOG_LEVEL: LogLevelFilter = LogLevelFilter::Trace;

#[cfg(not(debug_assertions))]
static MAX_LOG_LEVEL: LogLevelFilter = LogLevelFilter::Info;

impl log::Log for SimpleLogger {
    fn enabled(&self, metadata: &LogMetadata) -> bool {
        return metadata.level() <= MAX_LOG_LEVEL;
    }

    fn log(&self, record: &LogRecord) {
        if self.enabled(record.metadata()) {
            println!("{:5} [{}@{}] {}",
                     record.level(),
                     record.target(),
                     record.location().line(),
                     record.args());
        }
    }
}

impl SimpleLogger {
    pub fn init() -> Result<(), SetLoggerError> {
        println!("Logger level is {}", MAX_LOG_LEVEL);
        unsafe {
            log::set_logger_raw(|max_log_level| {
                max_log_level.set(MAX_LOG_LEVEL);
                &SimpleLogger
            })
        }
    }
}
<commit_msg>Remove forgotten debug println!()<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/.

// A simple logger that sets the max log level to Trace in debug builds and to Info in release ones.

use log::{self, LogRecord, LogLevelFilter, LogMetadata, SetLoggerError};

#[macro_export]
macro_rules! print {
    ($($args:tt)*) => {
        // Ignore logging errors. It's not worth killing the program because of
        // failed debug output. It would be nicer to save the error and report
        // it later, however.
        use core::fmt::Write;
        let mut console = $crate::cc3200::Console {};
        let _ = write!(console, $($args)*);
    }
}

#[macro_export]
macro_rules! println {
    ($fmt:expr)               => ( print!(concat!($fmt, '\n')) );
    ($fmt:expr, $($args:tt)*) => ( print!(concat!($fmt, '\n'), $($args)*) );
}

pub struct SimpleLogger;

#[cfg(debug_assertions)]
static MAX_LOG_LEVEL: LogLevelFilter = LogLevelFilter::Trace;

#[cfg(not(debug_assertions))]
static MAX_LOG_LEVEL: LogLevelFilter = LogLevelFilter::Info;

impl log::Log for SimpleLogger {
    fn enabled(&self, metadata: &LogMetadata) -> bool {
        return metadata.level() <= MAX_LOG_LEVEL;
    }

    fn log(&self, record: &LogRecord) {
        if self.enabled(record.metadata()) {
            println!("{:5} [{}@{}] {}",
                     record.level(),
                     record.target(),
                     record.location().line(),
                     record.args());
        }
    }
}

impl SimpleLogger {
    pub fn init() -> Result<(), SetLoggerError> {
        unsafe {
            log::set_logger_raw(|max_log_level| {
                max_log_level.set(MAX_LOG_LEVEL);
                &SimpleLogger
            })
        }
    }
}
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2017 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.
 */

include!("../relm-state/src/macros.rs");
<commit_msg>Temporary fix to publish the crate<commit_after>/*
 * Copyright (c) 2017 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.
 */

/// Connect events to sending a message.
///
/// ## Rules
/// 1. Send `$msg` to `$other_component` when the GTK+ `$event` is emitted on `$widget`.
///
/// 2. Optionally send `$msg.0` when the GTK+ `$event` is emitted on `$widget`.
/// Return `$msg.1` in the GTK+ callback.
/// This variant gives more control to the caller since it expects a `$msg` returning `(Option<MSG>,
/// ReturnValue)` where the `ReturnValue` is the value to return in the GTK+ callback.
/// Option<MSG> can be None if no message needs to be emitted.
///
/// 3. Send `$msg` when the GTK+ `$event` is emitted on `$widget`.
///
/// 4. Send `$msg` to `$widget` when the `$message` is received on `$stream`.
#[macro_export]
macro_rules! connect {
    // Connect to a GTK+ widget event, sending a message to another widget.
    ($widget:expr, $event:ident($($args:pat),*), $other_component:expr, $msg:expr) => {
        connect_stream!($widget, $event($($args),*), $other_component.stream(), $msg);
    };

    // Connect to a GTK+ widget event.
    // This variant gives more control to the caller since it expects a `$msg` returning (Option<MSG>,
    // ReturnValue) where the ReturnValue is the value to return in the GTK+ callback.
    // Option<MSG> can be None if no message needs to be emitted.
    ($relm:expr, $widget:expr, $event:ident($($args:pat),*), return $msg:expr) => {{
        connect_stream!(return $relm.stream(), $widget, $event($($args),*), $msg);
    }};

    // Connect to a GTK+ widget event.
    ($relm:expr, $widget:expr, $event:ident($($args:pat),*), $msg:expr) => {{
        let stream = $relm.stream().clone();
        let _ = $widget.$event(move |$($args),*| {
            let msg: Option<_> = $crate::IntoOption::into_option($msg);
            if let Some(msg) = msg {
                stream.emit(msg);
            }
        });
    }};

    // Connect to a message reception.
    // TODO: create another macro rule accepting multiple patterns.
    ($src_component:ident @ $message:pat, $dst_component:expr, $msg:expr) => {
        let stream = $src_component.stream().clone();
        connect_stream!(stream@$message, $dst_component.stream(), $msg);
    };
}

/// Connect events to sending a message.
/// Similar to `connect!` but wants a stream instead of a component.
///
/// ## Rules
/// 1. Send `$msg` to `$other_stream` when the GTK+ `$event` is emitted on `$widget`.
///
/// 2. Send `$msg` to `$widget` when the `$message` is received on `$stream`.
#[macro_export]
macro_rules! connect_stream {
    // Connect to a GTK+ widget event.
    // This variant gives more control to the caller since it expects a `$msg` returning (Option<MSG>,
    // ReturnValue) where the ReturnValue is the value to return in the GTK+ callback.
    // Option<MSG> can be None if no message needs to be emitted.
    (return $stream:expr, $widget:expr, $event:ident($($args:pat),*), $msg:expr) => {{
        let stream = $stream.clone();
        let _ = $widget.$event(move |$($args),*| {
            let (msg, return_value) = $crate::IntoPair::into_pair($msg);
            let msg: Option<_> = $crate::IntoOption::into_option(msg);
            if let Some(msg) = msg {
                stream.emit(msg);
            }
            return_value
        });
    }};

    // Connect to a GTK+ widget event, sending a message to another widget.
    ($widget:expr, $event:ident($($args:pat),*), $other_stream:expr, $msg:expr) => {
        let stream = $other_stream.clone();
        let _ = $widget.$event(move |$($args),*| {
            let msg: Option<_> = $crate::IntoOption::into_option($msg);
            if let Some(msg) = msg {
                stream.emit(msg);
            }
        });
    };

    // Connect to a message reception.
    // TODO: create another macro rule accepting multiple patterns.
    ($src_stream:ident @ $message:pat, $dst_stream:expr, $msg:expr) => {
        let stream = $dst_stream.clone();
        $src_stream.observe(move |msg| {
            #[allow(unreachable_patterns)]
            match msg {
                &$message =>  {
                    let msg: Option<_> = $crate::IntoOption::into_option($msg);
                    if let Some(msg) = msg {
                        stream.emit(msg);
                    }
                },
                _ => (),
            }
        });
    };
}

/// Connect an asynchronous method call to send a message.
/// The variants with `$fail_msg` will send this message when there's an error.
/// Those without this argument will ignore the error.
#[macro_export]
macro_rules! connect_async {
    ($object:expr, $async_method:ident, $relm:expr, $msg:expr) => {
        connect_async!($object, $async_method(), $relm, $msg)
    };
    ($object:expr, $async_method:ident ( $($args:expr),* ), $relm:expr, $msg:expr) => {{
        let stream = $relm.stream().clone();
        $object.$async_method($($args,)* None, move |result| {
            if let Ok(result) = result {
                stream.emit($msg(result));
            }
        });
    }};
    ($object:expr, $async_method:ident, $relm:expr, $msg:expr, $fail_msg:expr) => {
        connect_async!($object, $async_method(), $relm, $msg, $fail_msg)
    };
    ($object:expr, $async_method:ident ( $($args:expr),* ), $relm:expr, $msg:expr, $fail_msg:expr) => {{
        let event_stream = $relm.stream().clone();
        let fail_event_stream = $relm.stream().clone();
        $object.$async_method($($args,)* None, move |result| {
            match result {
                Ok(value) => event_stream.emit($msg(value)),
                Err(error) => fail_event_stream.emit($fail_msg(error)),
            }
        });
    }};
}

/// Connect an asynchronous function call to send a message.
/// The variants with `$fail_msg` will send this message when there's an error.
/// Those without this argument will ignore the error.
#[macro_export]
macro_rules! connect_async_func {
    ($class:ident :: $async_function:ident, $relm:expr, $msg:expr) => {
        connect_async_func!($class::$async_func(), $relm, $msg)
    };
    ($class:ident :: $async_func:ident ( $($args:expr),* ), $relm:expr, $msg:expr) => {{
        let stream = $relm.stream().clone();
        $class::$async_func($($args,)* None, move |result| {
            if let Ok(result) = result {
                stream.emit($msg(result));
            }
        });
    }};
    ($class:ident :: $async_func:ident, $relm:expr, $msg:expr, $fail_msg:expr) => {
        connect_async_func!($class::$async_func(), $relm, $msg, $fail_msg)
    };
    ($class:ident :: $async_func:ident ( $($args:expr),* ), $relm:expr, $msg:expr, $fail_msg:expr) => {{
        let event_stream = $relm.stream().clone();
        let fail_event_stream = $relm.stream().clone();
        $class::$async_func($($args,)* None, move |result| {
            match result {
                Ok(value) => event_stream.emit($msg(value)),
                Err(error) => fail_event_stream.emit($fail_msg(error)),
            }
        });

    }};
}

/// Like `connect_async!`, but also return a `Cancellable` to control the asynchronous request.
#[macro_export]
macro_rules! connect_async_full {
    ($object:expr, $async_method:ident, $relm:expr, $msg:expr) => {
        connect_async_full!($object, $async_method(), $relm, $msg)
    };
    ($object:expr, $async_method:ident ( $($args:expr),* ), $relm:expr, $msg:expr) => {{
        let cancellable = ::gio::Cancellable::new();
        let stream = $relm.stream().clone();
        $object.$async_method($($args,)* Some(&cancellable), move |result| {
            if let Ok(result) = result {
                stream.emit($msg(result));
            }
        });
        cancellable
    }};
    ($object:expr, $async_method:ident, $relm:expr, $msg:expr, $fail_msg:expr) => {
        connect_async_full!($object, $async_method(), $relm, $msg, $fail_msg)
    };
    ($object:expr, $async_method:ident ( $($args:expr),* ), $relm:expr, $msg:expr, $fail_msg:expr) => {{
        let cancellable = ::gio::Cancellable::new();
        let event_stream = $relm.stream().clone();
        let fail_event_stream = $relm.stream().clone();
        $object.$async_method($($args,)* Some(&cancellable), move |result| {
            match result {
                Ok(value) => event_stream.emit($msg(value)),
                Err(error) => fail_event_stream.emit($fail_msg(error)),
            }
        });

        cancellable
    }};
}

/// Like `connect_async_func!`, but also return a `Cancellable` to control the asynchronous request.
#[macro_export]
macro_rules! connect_async_func_full {
    ($class:ident :: $async_function:ident, $relm:expr, $msg:expr) => {
        connect_async!($async_func(), $relm, $msg)
    };
    ($class:ident :: $async_func:ident ( $($args:expr),* ), $relm:expr, $msg:expr) => {{
        let cancellable = ::gio::Cancellable::new();
        let stream = $relm.stream().clone();
        $class::$async_func($($args,)* Some(&cancellable), move |result| {
            if let Ok(result) = result {
                stream.emit($msg(result));
            }
        });
        cancellable
    }};
    ($class:ident :: $async_func:ident, $relm:expr, $msg:expr, $fail_msg:expr) => {
        connect_async!($async_func(), $relm, $msg, $fail_msg)
    };
    ($class:ident :: $async_func:ident ( $($args:expr),* ), $relm:expr, $msg:expr, $fail_msg:expr) => {{
        let cancellable = ::gio::Cancellable::new();
        let event_stream = $relm.stream().clone();
        let fail_event_stream = $relm.stream().clone();
        $class::$async_func($($args,)* Some(&cancellable), move |result| {
            match result {
                Ok(value) => event_stream.emit($msg(value)),
                Err(error) => fail_event_stream.emit($fail_msg(error)),
            }
        });

        cancellable
    }};
}
<|endoftext|>


<commit_before>//! Various macros

/// Generates an integer type `Name` where computations are done modulo `m`
#[macro_export]
macro_rules! define_modulo_ring(
($Name:ident, $m:expr) => (
#[deriving(PartialEq,Clone)]
struct $Name {
    value: i64
}
impl $Name {
    fn new(v: i64) -> $Name {
        let x=v%$m;
        if x < 0 {
            $Name { value: x + $m }
        } else {
            $Name { value: x }
        }
    }
}
impl core::fmt::Show for $Name {
    fn fmt(&self, fmt: &mut core::fmt::Formatter) -> core::fmt::Result {
        write!(fmt, "{} (mod {})", self.value, $m)
    }
}
impl Add<$Name,$Name> for $Name {
    fn add(&self, other: &$Name) -> $Name {
        $Name { value: (self.value + other.value)%$m }
    }
}
impl Sub<$Name,$Name> for $Name {
    fn sub(&self, other: &$Name) -> $Name {
        $Name { value: (self.value - other.value)%$m }
    }
}
impl Mul<$Name,$Name> for $Name {
    fn mul(&self, other: &$Name) -> $Name {
        $Name { value: (self.value*other.value)%$m }
    }
}
impl Div<$Name,$Name> for $Name {
    fn div(&self, other: &$Name) -> $Name {
        let inv=algoritmoi::moduli::invert_mod(other.value, $m);
        match inv {
            Some(i) => $Name::new(self.value*i),
            _ => fail!("Trying to divide by {} modulo {}", other.value, $m)
        }
    }
}
impl core::num::One for $Name {
    fn one() -> $Name {
        $Name { value: core::num::One::one() }
    }
}
impl core::num::Zero for $Name {
    fn zero() -> $Name {
        $Name { value: core::num::Zero::zero() }
    }
    fn is_zero(&self) -> bool {
        self.value%$m == 0
    }
}
impl FromPrimitive for $Name {
    fn from_i64(n: i64) -> Option<$Name> {
        Some($Name { value: n%$m })
    }
    fn from_u64(n: u64) -> Option<$Name> {
        Some($Name { value: (n%$m) as i64 })
    }
}
)
)

<commit_msg>Added Neg trait.<commit_after>//! Various macros

/// Generates an integer type `Name` where computations are done modulo `m`
#[macro_export]
macro_rules! define_modulo_ring(
($Name:ident, $m:expr) => (
#[deriving(PartialEq,Clone)]
struct $Name {
    value: i64
}
impl $Name {
    fn new(v: i64) -> $Name {
        let x=v%$m;
        if x < 0 {
            $Name { value: x + $m }
        } else {
            $Name { value: x }
        }
    }
}
impl core::fmt::Show for $Name {
    fn fmt(&self, fmt: &mut core::fmt::Formatter) -> core::fmt::Result {
        write!(fmt, "{} (mod {})", self.value, $m)
    }
}
impl Add<$Name,$Name> for $Name {
    fn add(&self, other: &$Name) -> $Name {
        $Name { value: (self.value + other.value)%$m }
    }
}
impl Sub<$Name,$Name> for $Name {
    fn sub(&self, other: &$Name) -> $Name {
        $Name { value: (self.value - other.value)%$m }
    }
}
impl Mul<$Name,$Name> for $Name {
    fn mul(&self, other: &$Name) -> $Name {
        $Name { value: (self.value*other.value)%$m }
    }
}
impl Div<$Name,$Name> for $Name {
    fn div(&self, other: &$Name) -> $Name {
        let inv=algoritmoi::moduli::invert_mod(other.value, $m);
        match inv {
            Some(i) => $Name::new(self.value*i),
            _ => fail!("Trying to divide by {} modulo {}", other.value, $m)
        }
    }
}
impl Neg<$Name> for $Name {
    fn neg(&self) -> $Name {
        $Name { value: $m - self.value }
    }
}
impl core::num::One for $Name {
    fn one() -> $Name {
        $Name { value: core::num::One::one() }
    }
}
impl core::num::Zero for $Name {
    fn zero() -> $Name {
        $Name { value: core::num::Zero::zero() }
    }
    fn is_zero(&self) -> bool {
        self.value%$m == 0
    }
}
impl FromPrimitive for $Name {
    fn from_i64(n: i64) -> Option<$Name> {
        Some($Name { value: n%$m })
    }
    fn from_u64(n: u64) -> Option<$Name> {
        Some($Name { value: (n%$m) as i64 })
    }
}
)
)

<|endoftext|>


<commit_before>
#[macro_export]
macro_rules! dyon_macro_items { ($($x:item)+) => ($($x)+) }

#[macro_export]
macro_rules! dyon_fn {
    (fn $name:ident () -> $rt:ty $b:block) => {
        fn $name(rt: &mut $crate::Runtime) -> Result<(), String> {
            rt.push::<$rt>($b);
            Ok(())
        }
    };
    (fn $name:ident ($arg:tt : $t:ty) -> $rt:ty $b:block) => {
        dyon_macro_items!{
            fn $name(rt: &mut $crate::Runtime) -> Result<(), String> {
                let $arg: $t = try!(rt.pop());
                rt.push::<$rt>($b);
                Ok(())
            }
        }
    };
    (fn $name:ident ($arg0:tt : $t0:ty, $arg1:tt : $t1:ty) -> $rt:ty $b:block) => {
        dyon_macro_items!{
            fn $name(rt: &mut $crate::Runtime) -> Result<(), String> {
                let $arg1: $t1 = try!(rt.pop());
                let $arg0: $t0 = try!(rt.pop());
                rt.push::<$rt>($b);
                Ok(())
            }
        }
    };
    (fn $name:ident (
        $arg0:tt : $t0:ty,
        $arg1:tt : $t1:ty,
        $arg2:tt : $t2:ty
    ) -> $rt:ty $b:block) => {
        dyon_macro_items!{
            fn $name(rt: &mut $crate::Runtime) -> Result<(), String> {
                let $arg2: $t2 = try!(rt.pop());
                let $arg1: $t1 = try!(rt.pop());
                let $arg0: $t0 = try!(rt.pop());
                rt.push::<$rt>($b);
                Ok(())
            }
        }
    };
    (fn $name:ident (
        $arg0:tt : $t0:ty,
        $arg1:tt : $t1:ty,
        $arg2:tt : $t2:ty,
        $arg3:tt : $t3:ty
    ) -> $rt:ty $b:block) => {
        dyon_macro_items!{
            fn $name(rt: &mut $crate::Runtime) -> Result<(), String> {
                let $arg3: $t3 = try!(rt.pop());
                let $arg2: $t2 = try!(rt.pop());
                let $arg1: $t1 = try!(rt.pop());
                let $arg0: $t0 = try!(rt.pop());
                rt.push::<$rt>($b);
                Ok(())
            }
        }
    };
    (fn $name:ident () $b:block) => {
        fn $name(_: &mut $crate::Runtime) -> Result<(), String> {
            $b
            Ok(())
        }
    };
    (fn $name:ident ($arg:tt : $t:ty) $b:block) => {
        dyon_macro_items!{
            fn $name(rt: &mut $crate::Runtime) -> Result<(), String> {
                let $arg: $t = try!(rt.pop());
                $b
                Ok(())
            }
        }
    };
    (fn $name:ident ($arg0:tt : $t0:ty, $arg1:tt : $t1:ty) $b:block) => {
        dyon_macro_items!{
            fn $name(rt: &mut $crate::Runtime) -> Result<(), String> {
                let $arg1: $t1 = try!(rt.pop());
                let $arg0: $t0 = try!(rt.pop());
                $b
                Ok(())
            }
        }
    };
    (fn $name:ident (
        $arg0:tt : $t0:ty,
        $arg1:tt : $t1:ty,
        $arg2:tt : $t2:ty
    ) $b:block) => {
        dyon_macro_items!{
            fn $name(rt: &mut $crate::Runtime) -> Result<(), String> {
                let $arg2: $t2 = try!(rt.pop());
                let $arg1: $t1 = try!(rt.pop());
                let $arg0: $t0 = try!(rt.pop());
                $b
                Ok(())
            }
        }
    };
    (fn $name:ident (
        $arg0:tt : $t0:ty,
        $arg1:tt : $t1:ty,
        $arg2:tt : $t2:ty,
        $arg3:tt : $t3:ty
    ) $b:block) => {
        dyon_macro_items!{
            fn $name(rt: &mut $crate::Runtime) -> Result<(), String> {
                let $arg3: $t3 = try!(rt.pop());
                let $arg2: $t2 = try!(rt.pop());
                let $arg1: $t1 = try!(rt.pop());
                let $arg0: $t0 = try!(rt.pop());
                $b
                Ok(())
            }
        }
    };
}

#[macro_export]
macro_rules! dyon_obj {
    ($t:tt { $($f:tt),* }) => {
        dyon_macro_items!{
            impl $crate::embed::PopVariable for $t {
                fn pop_var(rt: &$crate::Runtime, var: &$crate::Variable) -> Result<Self, String> {
                    use dyon::embed::obj_field;
                    let var = rt.resolve(var);
                    if let &$crate::Variable::Object(ref obj) = var {
                        Ok($t {
                            $(
                                $f: try!(obj_field(rt, obj, stringify!($f)))
                            ),*
                        })
                    } else {
                        Err(rt.expected(var, stringify!($t)))
                    }
                }
            }

            impl $crate::embed::PushVariable for $t {
                fn push_var(&self) -> $crate::Variable {
                    use std::sync::Arc;
                    use std::collections::HashMap;

                    let mut obj: HashMap<_, $crate::Variable> = HashMap::new();
                    $(
                        obj.insert(Arc::new(stringify!($f).into()), self.$f.push_var())
                    ;)*
                    $crate::Variable::Object(Arc::new(obj))
                }
            }
        }
    }
}
<commit_msg>Add support for `return` inside `dyon_fn`<commit_after>
#[macro_export]
macro_rules! dyon_macro_items { ($($x:item)+) => ($($x)+) }

#[macro_export]
macro_rules! dyon_fn {
    (fn $name:ident () -> $rt:ty $b:block) => {
        fn $name(rt: &mut $crate::Runtime) -> Result<(), String> {
            fn inner() -> $rt {
                $b
            }

            rt.push(inner());
            Ok(())
        }
    };
    (fn $name:ident ($arg:tt : $t:ty) -> $rt:ty $b:block) => {
        dyon_macro_items!{
            fn $name(rt: &mut $crate::Runtime) -> Result<(), String> {
                fn inner($arg: $t) -> $rt {
                    $b
                }

                let $arg: $t = try!(rt.pop());
                rt.push(inner($arg));
                Ok(())
            }
        }
    };
    (fn $name:ident ($arg0:tt : $t0:ty, $arg1:tt : $t1:ty) -> $rt:ty $b:block) => {
        dyon_macro_items!{
            fn $name(rt: &mut $crate::Runtime) -> Result<(), String> {
                fn inner($arg0: $t0, $arg1: $t1) -> $rt {
                    $b
                }

                let $arg1: $t1 = try!(rt.pop());
                let $arg0: $t0 = try!(rt.pop());
                rt.push(inner($arg0, $arg1));
                Ok(())
            }
        }
    };
    (fn $name:ident (
        $arg0:tt : $t0:ty,
        $arg1:tt : $t1:ty,
        $arg2:tt : $t2:ty
    ) -> $rt:ty $b:block) => {
        dyon_macro_items!{
            fn $name(rt: &mut $crate::Runtime) -> Result<(), String> {
                fn inner($arg0: $t0, $arg1: $t1, $arg2: $t2) -> $rt {
                    $b
                }

                let $arg2: $t2 = try!(rt.pop());
                let $arg1: $t1 = try!(rt.pop());
                let $arg0: $t0 = try!(rt.pop());
                rt.push(inner($arg0, $arg1, $arg2));
                Ok(())
            }
        }
    };
    (fn $name:ident (
        $arg0:tt : $t0:ty,
        $arg1:tt : $t1:ty,
        $arg2:tt : $t2:ty,
        $arg3:tt : $t3:ty
    ) -> $rt:ty $b:block) => {
        dyon_macro_items!{
            fn $name(rt: &mut $crate::Runtime) -> Result<(), String> {
                fn inner($arg0: $t0, $arg1: $t1, $arg2: $t2, $arg3: $t3) -> $rt {
                    $b
                }

                let $arg3: $t3 = try!(rt.pop());
                let $arg2: $t2 = try!(rt.pop());
                let $arg1: $t1 = try!(rt.pop());
                let $arg0: $t0 = try!(rt.pop());
                rt.push(inner($arg0, $arg1, $arg2, $arg3));
                Ok(())
            }
        }
    };
    (fn $name:ident () $b:block) => {
        fn $name(_: &mut $crate::Runtime) -> Result<(), String> {
            fn inner() {
                $b
            }

            inner();
            Ok(())
        }
    };
    (fn $name:ident ($arg:tt : $t:ty) $b:block) => {
        dyon_macro_items!{
            fn $name(rt: &mut $crate::Runtime) -> Result<(), String> {
                fn inner($arg: $t) {
                    $b
                }

                let $arg: $t = try!(rt.pop());
                inner($arg);
                Ok(())
            }
        }
    };
    (fn $name:ident ($arg0:tt : $t0:ty, $arg1:tt : $t1:ty) $b:block) => {
        dyon_macro_items!{
            fn $name(rt: &mut $crate::Runtime) -> Result<(), String> {
                fn inner($arg0: $t0, $arg1: $t1) {
                    $b
                }

                let $arg1: $t1 = try!(rt.pop());
                let $arg0: $t0 = try!(rt.pop());
                inner($arg0, $arg1);
                Ok(())
            }
        }
    };
    (fn $name:ident (
        $arg0:tt : $t0:ty,
        $arg1:tt : $t1:ty,
        $arg2:tt : $t2:ty
    ) $b:block) => {
        dyon_macro_items!{
            fn $name(rt: &mut $crate::Runtime) -> Result<(), String> {
                fn inner($arg0: $t0, $arg1: $t1, $arg2: $t2) {
                    $b
                }

                let $arg2: $t2 = try!(rt.pop());
                let $arg1: $t1 = try!(rt.pop());
                let $arg0: $t0 = try!(rt.pop());
                inner($arg0, $arg1, $arg2);
                Ok(())
            }
        }
    };
    (fn $name:ident (
        $arg0:tt : $t0:ty,
        $arg1:tt : $t1:ty,
        $arg2:tt : $t2:ty,
        $arg3:tt : $t3:ty
    ) $b:block) => {
        dyon_macro_items!{
            fn $name(rt: &mut $crate::Runtime) -> Result<(), String> {
                fn inner($arg0: $t0, $arg1: $t1, $arg2: $t2, $arg3: $t3) {
                    $b
                }

                let $arg3: $t3 = try!(rt.pop());
                let $arg2: $t2 = try!(rt.pop());
                let $arg1: $t1 = try!(rt.pop());
                let $arg0: $t0 = try!(rt.pop());
                inner($arg0, $arg1, $arg2, $arg3);
                Ok(())
            }
        }
    };
}

#[macro_export]
macro_rules! dyon_obj {
    ($t:tt { $($f:tt),* }) => {
        dyon_macro_items!{
            impl $crate::embed::PopVariable for $t {
                fn pop_var(rt: &$crate::Runtime, var: &$crate::Variable) -> Result<Self, String> {
                    use dyon::embed::obj_field;
                    let var = rt.resolve(var);
                    if let &$crate::Variable::Object(ref obj) = var {
                        Ok($t {
                            $(
                                $f: try!(obj_field(rt, obj, stringify!($f)))
                            ),*
                        })
                    } else {
                        Err(rt.expected(var, stringify!($t)))
                    }
                }
            }

            impl $crate::embed::PushVariable for $t {
                fn push_var(&self) -> $crate::Variable {
                    use std::sync::Arc;
                    use std::collections::HashMap;

                    let mut obj: HashMap<_, $crate::Variable> = HashMap::new();
                    $(
                        obj.insert(Arc::new(stringify!($f).into()), self.$f.push_var())
                    ;)*
                    $crate::Variable::Object(Arc::new(obj))
                }
            }
        }
    }
}
<|endoftext|>


<commit_before>/// Implement `serde::Serialize` for a trait object that has
/// `erased_serde::Serialize` as a supertrait.
///
/// ```
/// use erased_serde::serialize_trait_object;
///
/// trait Event: erased_serde::Serialize {
///     /* ... */
/// }
///
/// erased_serde::serialize_trait_object!(Event);
/// ```
///
/// The macro supports traits that have type parameters and/or `where` clauses.
///
/// ```
/// # use erased_serde::serialize_trait_object;
/// #
/// trait Difficult<T>: erased_serde::Serialize where T: Copy {
///     /* ... */
/// }
///
/// serialize_trait_object!(<T> Difficult<T> where T: Copy);
/// ```
#[macro_export]
macro_rules! serialize_trait_object {
    ($($path:tt)+) => {
        $crate::__internal_serialize_trait_object!(begin $($path)+);
    };
}

#[doc(hidden)]
#[macro_export]
macro_rules! __internal_serialize_trait_object {
    // Invocation started with `<`, parse generics.
    (begin < $($rest:tt)*) => {
        $crate::__internal_serialize_trait_object!(generics () () $($rest)*);
    };

    // Invocation did not start with `<`.
    (begin $first:tt $($rest:tt)*) => {
        $crate::__internal_serialize_trait_object!(path () ($first) $($rest)*);
    };

    // End of generics.
    (generics ($($generics:tt)*) () > $($rest:tt)*) => {
        $crate::__internal_serialize_trait_object!(path ($($generics)*) () $($rest)*);
    };

    // Generics open bracket.
    (generics ($($generics:tt)*) ($($brackets:tt)*) < $($rest:tt)*) => {
        $crate::__internal_serialize_trait_object!(generics ($($generics)* <) ($($brackets)* <) $($rest)*);
    };

    // Generics close bracket.
    (generics ($($generics:tt)*) (< $($brackets:tt)*) > $($rest:tt)*) => {
        $crate::__internal_serialize_trait_object!(generics ($($generics)* >) ($($brackets)*) $($rest)*);
    };

    // Token inside of generics.
    (generics ($($generics:tt)*) ($($brackets:tt)*) $first:tt $($rest:tt)*) => {
        $crate::__internal_serialize_trait_object!(generics ($($generics)* $first) ($($brackets)*) $($rest)*);
    };

    // End with `where` clause.
    (path ($($generics:tt)*) ($($path:tt)*) where $($rest:tt)*) => {
        $crate::__internal_serialize_trait_object!(sendsync ($($generics)*) ($($path)*) ($($rest)*));
    };

    // End without `where` clause.
    (path ($($generics:tt)*) ($($path:tt)*)) => {
        $crate::__internal_serialize_trait_object!(sendsync ($($generics)*) ($($path)*) ());
    };

    // Token inside of path.
    (path ($($generics:tt)*) ($($path:tt)*) $first:tt $($rest:tt)*) => {
        $crate::__internal_serialize_trait_object!(path ($($generics)*) ($($path)* $first) $($rest)*);
    };

    // Expand into four impls.
    (sendsync ($($generics:tt)*) ($($path:tt)*) ($($bound:tt)*)) => {
        $crate::__internal_serialize_trait_object!(impl ($($generics)*) ($($path)*) ($($bound)*) {
            fn __check_erased_serialize_supertrait<__T, $($generics)*>()
            where
                __T: ?$crate::private::Sized + $($path)*,
                $($bound)*
            {
                $crate::private::require_erased_serialize_impl::<__T>();
            }
        });
        $crate::__internal_serialize_trait_object!(impl ($($generics)*) ($($path)* + $crate::private::Send) ($($bound)*));
        $crate::__internal_serialize_trait_object!(impl ($($generics)*) ($($path)* + $crate::private::Sync) ($($bound)*));
        $crate::__internal_serialize_trait_object!(impl ($($generics)*) ($($path)* + $crate::private::Send + $crate::private::Sync) ($($bound)*));
    };

    // The impl.
    (impl ($($generics:tt)*) ($($path:tt)*) ($($bound:tt)*) $({$($body:tt)*})*) => {
        impl<'erased, $($generics)*> $crate::private::serde::Serialize for dyn $($path)* + 'erased
        where
            $($bound)*
        {
            fn serialize<S>(&self, serializer: S) -> $crate::private::Result<S::Ok, S::Error>
            where
                S: $crate::private::serde::Serializer,
            {
                $($($body)*)*
                $crate::serialize(self, serializer)
            }
        }
    };
}

// TEST ////////////////////////////////////////////////////////////////////////

#[cfg(test)]
mod tests {
    use crate::Serialize;

    fn assert_serialize<T: ?Sized + serde::Serialize>() {}

    #[test]
    fn test_plain() {
        trait Trait: Serialize {}

        serialize_trait_object!(Trait);
        assert_serialize::<dyn Trait>();
        assert_serialize::<dyn Trait + Send>();
    }

    #[test]
    fn test_type_parameter() {
        trait Trait<T>: Serialize {}

        serialize_trait_object!(<T> Trait<T>);
        assert_serialize::<dyn Trait<u32>>();
        assert_serialize::<dyn Trait<u32> + Send>();
    }

    #[test]
    fn test_generic_bound() {
        trait Trait<T: PartialEq<T>, U>: Serialize {}

        serialize_trait_object!(<T: PartialEq<T>, U> Trait<T, U>);
        assert_serialize::<dyn Trait<u32, ()>>();
        assert_serialize::<dyn Trait<u32, ()> + Send>();
    }

    #[test]
    fn test_where_clause() {
        trait Trait<T>: Serialize
        where
            T: Clone,
        {
        }

        serialize_trait_object!(<T> Trait<T> where T: Clone);
        assert_serialize::<dyn Trait<u32>>();
        assert_serialize::<dyn Trait<u32> + Send>();
    }
}
<commit_msg>Fix lifetime ordering in serialize_trait_object<commit_after>/// Implement `serde::Serialize` for a trait object that has
/// `erased_serde::Serialize` as a supertrait.
///
/// ```
/// use erased_serde::serialize_trait_object;
///
/// trait Event: erased_serde::Serialize {
///     /* ... */
/// }
///
/// erased_serde::serialize_trait_object!(Event);
/// ```
///
/// The macro supports traits that have type parameters and/or `where` clauses.
///
/// ```
/// # use erased_serde::serialize_trait_object;
/// #
/// trait Difficult<T>: erased_serde::Serialize where T: Copy {
///     /* ... */
/// }
///
/// serialize_trait_object!(<T> Difficult<T> where T: Copy);
/// ```
#[macro_export]
macro_rules! serialize_trait_object {
    ($($path:tt)+) => {
        $crate::__internal_serialize_trait_object!(begin $($path)+);
    };
}

#[doc(hidden)]
#[macro_export]
macro_rules! __internal_serialize_trait_object {
    // Invocation started with `<`, parse generics.
    (begin < $($rest:tt)*) => {
        $crate::__internal_serialize_trait_object!(generics () () $($rest)*);
    };

    // Invocation did not start with `<`.
    (begin $first:tt $($rest:tt)*) => {
        $crate::__internal_serialize_trait_object!(path () ($first) $($rest)*);
    };

    // End of generics with trailing comma.
    (generics ($($generics:tt)*) () , > $($rest:tt)*) => {
        $crate::__internal_serialize_trait_object!(path ($($generics)* ,) () $($rest)*);
    };

    // End of generics without trailing comma.
    (generics ($($generics:tt)*) () > $($rest:tt)*) => {
        $crate::__internal_serialize_trait_object!(path ($($generics)* ,) () $($rest)*);
    };

    // Generics open bracket.
    (generics ($($generics:tt)*) ($($brackets:tt)*) < $($rest:tt)*) => {
        $crate::__internal_serialize_trait_object!(generics ($($generics)* <) ($($brackets)* <) $($rest)*);
    };

    // Generics close bracket.
    (generics ($($generics:tt)*) (< $($brackets:tt)*) > $($rest:tt)*) => {
        $crate::__internal_serialize_trait_object!(generics ($($generics)* >) ($($brackets)*) $($rest)*);
    };

    // Token inside of generics.
    (generics ($($generics:tt)*) ($($brackets:tt)*) $first:tt $($rest:tt)*) => {
        $crate::__internal_serialize_trait_object!(generics ($($generics)* $first) ($($brackets)*) $($rest)*);
    };

    // End with `where` clause.
    (path ($($generics:tt)*) ($($path:tt)*) where $($rest:tt)*) => {
        $crate::__internal_serialize_trait_object!(sendsync ($($generics)*) ($($path)*) ($($rest)*));
    };

    // End without `where` clause.
    (path ($($generics:tt)*) ($($path:tt)*)) => {
        $crate::__internal_serialize_trait_object!(sendsync ($($generics)*) ($($path)*) ());
    };

    // Token inside of path.
    (path ($($generics:tt)*) ($($path:tt)*) $first:tt $($rest:tt)*) => {
        $crate::__internal_serialize_trait_object!(path ($($generics)*) ($($path)* $first) $($rest)*);
    };

    // Expand into four impls.
    (sendsync ($($generics:tt)*) ($($path:tt)*) ($($bound:tt)*)) => {
        $crate::__internal_serialize_trait_object!(impl ($($generics)*) ($($path)*) ($($bound)*) {
            fn __check_erased_serialize_supertrait<$($generics)* __T>()
            where
                __T: ?$crate::private::Sized + $($path)*,
                $($bound)*
            {
                $crate::private::require_erased_serialize_impl::<__T>();
            }
        });
        $crate::__internal_serialize_trait_object!(impl ($($generics)*) ($($path)* + $crate::private::Send) ($($bound)*));
        $crate::__internal_serialize_trait_object!(impl ($($generics)*) ($($path)* + $crate::private::Sync) ($($bound)*));
        $crate::__internal_serialize_trait_object!(impl ($($generics)*) ($($path)* + $crate::private::Send + $crate::private::Sync) ($($bound)*));
    };

    // The impl.
    (impl ($($generics:tt)*) ($($path:tt)*) ($($bound:tt)*) $({$($body:tt)*})*) => {
        impl<'erased, $($generics)*> $crate::private::serde::Serialize for dyn $($path)* + 'erased
        where
            $($bound)*
        {
            fn serialize<S>(&self, serializer: S) -> $crate::private::Result<S::Ok, S::Error>
            where
                S: $crate::private::serde::Serializer,
            {
                $($($body)*)*
                $crate::serialize(self, serializer)
            }
        }
    };
}

// TEST ////////////////////////////////////////////////////////////////////////

#[cfg(test)]
mod tests {
    use crate::Serialize;

    fn assert_serialize<T: ?Sized + serde::Serialize>() {}

    #[test]
    fn test_plain() {
        trait Trait: Serialize {}

        serialize_trait_object!(Trait);
        assert_serialize::<dyn Trait>();
        assert_serialize::<dyn Trait + Send>();
    }

    #[test]
    fn test_type_parameter() {
        trait Trait<T>: Serialize {}

        serialize_trait_object!(<T> Trait<T>);
        assert_serialize::<dyn Trait<u32>>();
        assert_serialize::<dyn Trait<u32> + Send>();
    }

    #[test]
    fn test_generic_bound() {
        trait Trait<T: PartialEq<T>, U>: Serialize {}

        serialize_trait_object!(<T: PartialEq<T>, U> Trait<T, U>);
        assert_serialize::<dyn Trait<u32, ()>>();
        assert_serialize::<dyn Trait<u32, ()> + Send>();
    }

    #[test]
    fn test_where_clause() {
        trait Trait<T>: Serialize
        where
            T: Clone,
        {
        }

        serialize_trait_object!(<T> Trait<T> where T: Clone);
        assert_serialize::<dyn Trait<u32>>();
        assert_serialize::<dyn Trait<u32> + Send>();
    }
}
<|endoftext|>