<commit_before>use ast::{Expr, Function, List, Quote, Symbol};
use combine::{Stream, Parser, ParseError, ParseResult};
use combine::{between, many, parser, satisfy_map, token};
use ops;
use token::Token;

pub fn parse<I>(input: I) -> Result<(Vec<Expr>, I), ParseError<I>>
    where I: Stream<Item = Token>
{
    many(parser(expr)).parse(input)
}

fn expr<I>(input: I) -> ParseResult<Expr, I>
    where I: Stream<Item = Token>
{
    parser(atom)
        .or(parser(builtin))
        .or(parser(symbol))
        .or(parser(list))
        .or(parser(quote))
        .parse_stream(input)
}

fn atom<I>(input: I) -> ParseResult<Expr, I>
    where I: Stream<Item = Token>
{
    satisfy_map(|token| {
            if let Token::Literal(lit) = token {
                Some(Expr::from(lit))
            } else {
                None
            }
        })
        .parse_stream(input)
}

#[cfg_attr(rustfmt, rustfmt_skip)]
fn builtin<I>(input: I) -> ParseResult<Expr, I>
    where I: Stream<Item = Token>
{
    satisfy_map(|token| {
            match token {
                // Math tokens
                Token::Plus    => Some(Function::new(Some("+"), Box::new(ops::add)).into()),
                Token::Minus   => Some(Function::new(Some("-"), Box::new(ops::sub)).into()),
                Token::Star    => Some(Function::new(Some("*"), Box::new(ops::mul)).into()),
                Token::Slash   => Some(Function::new(Some("/"), Box::new(ops::div)).into()),

                // Comparison tokens
                Token::Equal   => Some(Function::new(Some("="), Box::new(ops::equal)).into()),
                Token::Less    => Some(Function::new(Some("<"), Box::new(ops::less)).into()),
                Token::LessEq  => Some(Function::new(Some("<="), Box::new(ops::less_eq)).into()),
                Token::Greater => Some(Function::new(Some(">"), Box::new(ops::greater)).into()),

                // Keywords
                Token::Not     => Some(Function::new(Some("not"), Box::new(ops::not)).into()),
                Token::Or      => Some(Function::new(Some("or"), Box::new(ops::or)).into()),
                Token::And     => Some(Function::new(Some("and"), Box::new(ops::and)).into()),
                Token::Print   => Some(Function::new(Some("print"), Box::new(ops::print)).into()),
                _ => None,
            }
        })
        .parse_stream(input)
}

fn list<I>(input: I) -> ParseResult<Expr, I>
    where I: Stream<Item = Token>
{
    between(token(Token::LParen),
            token(Token::RParen),
            many(parser(expr)).map(List).map(Expr::List))
        .parse_stream(input)
}

fn quote<I>(input: I) -> ParseResult<Expr, I>
    where I: Stream<Item = Token>
{
    between(token(Token::LBracket),
            token(Token::RBracket),
            many(parser(expr)).map(Quote).map(Expr::Quote))
        .parse_stream(input)
}

fn symbol<I>(input: I) -> ParseResult<Expr, I>
    where I: Stream<Item = Token>
{
    satisfy_map(|token| {
            if let Token::Symbol(sym) = token {
                Some(Expr::from(Symbol(sym)))
            } else {
                None
            }
        })
        .parse_stream(input)
}
<commit_msg>Add missing >= parsing case<commit_after>use ast::{Expr, Function, List, Quote, Symbol};
use combine::{Stream, Parser, ParseError, ParseResult};
use combine::{between, many, parser, satisfy_map, token};
use ops;
use token::Token;

pub fn parse<I>(input: I) -> Result<(Vec<Expr>, I), ParseError<I>>
    where I: Stream<Item = Token>
{
    many(parser(expr)).parse(input)
}

fn expr<I>(input: I) -> ParseResult<Expr, I>
    where I: Stream<Item = Token>
{
    choice!(
        parser(atom),
        parser(builtin),
        parser(symbol),
        parser(list),
        parser(quote)
    ).parse_stream(input)
}

fn atom<I>(input: I) -> ParseResult<Expr, I>
    where I: Stream<Item = Token>
{
    satisfy_map(|token| {
            if let Token::Literal(lit) = token {
                Some(Expr::from(lit))
            } else {
                None
            }
        })
        .parse_stream(input)
}

#[cfg_attr(rustfmt, rustfmt_skip)]
fn builtin<I>(input: I) -> ParseResult<Expr, I>
    where I: Stream<Item = Token>
{
    satisfy_map(|token| {
            match token {
                // Math tokens
                Token::Plus    => Some(Function::new(Some("+"), Box::new(ops::add)).into()),
                Token::Minus   => Some(Function::new(Some("-"), Box::new(ops::sub)).into()),
                Token::Star    => Some(Function::new(Some("*"), Box::new(ops::mul)).into()),
                Token::Slash   => Some(Function::new(Some("/"), Box::new(ops::div)).into()),

                // Comparison tokens
                Token::Equal   => Some(Function::new(Some("="), Box::new(ops::equal)).into()),
                Token::Less    => Some(Function::new(Some("<"), Box::new(ops::less)).into()),
                Token::LessEq  => Some(Function::new(Some("<="), Box::new(ops::less_eq)).into()),
                Token::Greater => Some(Function::new(Some(">"), Box::new(ops::greater)).into()),
                Token::GreaterEq => Some(Function::new(Some(">"), Box::new(ops::greater_eq)).into()),

                // Keywords
                Token::Not     => Some(Function::new(Some("not"), Box::new(ops::not)).into()),
                Token::Or      => Some(Function::new(Some("or"), Box::new(ops::or)).into()),
                Token::And     => Some(Function::new(Some("and"), Box::new(ops::and)).into()),
                Token::Print   => Some(Function::new(Some("print"), Box::new(ops::print)).into()),
                _ => None,
            }
        })
        .parse_stream(input)
}

fn list<I>(input: I) -> ParseResult<Expr, I>
    where I: Stream<Item = Token>
{
    between(token(Token::LParen),
            token(Token::RParen),
            many(parser(expr)).map(List).map(Expr::List))
        .parse_stream(input)
}

fn quote<I>(input: I) -> ParseResult<Expr, I>
    where I: Stream<Item = Token>
{
    between(token(Token::LBracket),
            token(Token::RBracket),
            many(parser(expr)).map(Quote).map(Expr::Quote))
        .parse_stream(input)
}

fn symbol<I>(input: I) -> ParseResult<Expr, I>
    where I: Stream<Item = Token>
{
    satisfy_map(|token| {
            if let Token::Symbol(sym) = token {
                Some(Expr::from(Symbol(sym)))
            } else {
                None
            }
        })
        .parse_stream(input)
}
<|endoftext|>


<commit_before>use std::error::Error;
use std::sync::Arc;

use conduit::{Handler, Request, Response};
use conduit_git_http_backend;
use conduit_router::{RequestParams, RouteBuilder};

use util::errors::{std_error, CargoError, CargoResult, NotFound};
use util::RequestProxy;
use {App, Env};
use controllers::*;

pub fn build_router(app: &App) -> R404 {
    let mut api_router = RouteBuilder::new();

    // Route used by both `cargo search` and the frontend
    api_router.get("/crates", C(krate::search::search));

    // Routes used by `cargo`
    api_router.put("/crates/new", C(krate::publish::publish));
    api_router.get("/crates/:crate_id/owners", C(krate::owners::owners));
    api_router.put("/crates/:crate_id/owners", C(krate::owners::add_owners));
    api_router.delete("/crates/:crate_id/owners", C(krate::owners::remove_owners));
    api_router.delete("/crates/:crate_id/:version/yank", C(version::yank::yank));
    api_router.put(
        "/crates/:crate_id/:version/unyank",
        C(version::yank::unyank),
    );
    api_router.get(
        "/crates/:crate_id/:version/download",
        C(version::downloads::download),
    );

    // Routes that appear to be unused
    api_router.get("/versions", C(version::deprecated::index));
    api_router.get("/versions/:version_id", C(version::deprecated::show));

    // Routes used by the frontend
    api_router.get("/crates/:crate_id", C(krate::metadata::show));
    api_router.get("/crates/:crate_id/:version", C(version::deprecated::show));
    api_router.get(
        "/crates/:crate_id/:version/readme",
        C(krate::metadata::readme),
    );
    api_router.get(
        "/crates/:crate_id/:version/dependencies",
        C(version::metadata::dependencies),
    );
    api_router.get(
        "/crates/:crate_id/:version/downloads",
        C(version::downloads::downloads),
    );
    api_router.get(
        "/crates/:crate_id/:version/authors",
        C(version::metadata::authors),
    );
    api_router.get(
        "/crates/:crate_id/downloads",
        C(krate::downloads::downloads),
    );
    api_router.get("/crates/:crate_id/versions", C(krate::metadata::versions));
    api_router.put("/crates/:crate_id/follow", C(krate::follow::follow));
    api_router.delete("/crates/:crate_id/follow", C(krate::follow::unfollow));
    api_router.get("/crates/:crate_id/following", C(krate::follow::following));
    api_router.get("/crates/:crate_id/owner_team", C(krate::owners::owner_team));
    api_router.get("/crates/:crate_id/owner_user", C(krate::owners::owner_user));
    api_router.get(
        "/crates/:crate_id/reverse_dependencies",
        C(krate::metadata::reverse_dependencies),
    );
    api_router.get("/keywords", C(keyword::index));
    api_router.get("/keywords/:keyword_id", C(keyword::show));
    api_router.get("/categories", C(category::index));
    api_router.get("/categories/:category_id", C(category::show));
    api_router.get("/category_slugs", C(category::slugs));
    api_router.get("/users/:user_id", C(user::other::show));
    api_router.put("/users/:user_id", C(user::me::update_user));
    api_router.get("/users/:user_id/stats", C(user::other::stats));
    api_router.get("/teams/:team_id", C(team::show_team));
    api_router.get("/me", C(user::me::me));
    api_router.get("/me/updates", C(user::me::updates));
    api_router.get("/me/tokens", C(token::list));
    api_router.put("/me/tokens", C(token::new));
    api_router.delete("/me/tokens/:id", C(token::revoke));
    api_router.get(
        "/me/crate_owner_invitations",
        C(crate_owner_invitation::list),
    );
    api_router.put(
        "/me/crate_owner_invitations/:crate_id",
        C(crate_owner_invitation::handle_invite),
    );
    api_router.get("/summary", C(krate::metadata::summary));
    api_router.put("/confirm/:email_token", C(user::me::confirm_user_email));
    api_router.put(
        "/users/:user_id/resend",
        C(user::me::regenerate_token_and_send),
    );
    api_router.get("/site_metadata", C(site_metadata::show_deployed_sha));
    let api_router = Arc::new(R404(api_router));

    let mut router = RouteBuilder::new();

    // Mount the router under the /api/v1 path so we're at least somewhat at the
    // liberty to change things in the future!
    router.get("/api/v1/*path", R(Arc::clone(&api_router)));
    router.put("/api/v1/*path", R(Arc::clone(&api_router)));
    router.post("/api/v1/*path", R(Arc::clone(&api_router)));
    router.head("/api/v1/*path", R(Arc::clone(&api_router)));
    router.delete("/api/v1/*path", R(api_router));

    router.get("/authorize_url", C(user::session::github_authorize));
    router.get("/authorize", C(user::session::github_access_token));
    router.delete("/logout", C(user::session::logout));

    // Only serve the local checkout of the git index in development mode.
    // In production, for crates.io, cargo gets the index from
    // https://github.com/rust-lang/crates.io-index directly.
    if app.config.env == Env::Development {
        let s = conduit_git_http_backend::Serve(app.git_repo_checkout.clone());
        let s = Arc::new(s);
        router.get("/git/index/*path", R(Arc::clone(&s)));
        router.post("/git/index/*path", R(s));
    }

    R404(router)
}

struct C(pub fn(&mut Request) -> CargoResult<Response>);

impl Handler for C {
    fn call(&self, req: &mut Request) -> Result<Response, Box<Error + Send>> {
        let C(f) = *self;
        match f(req) {
            Ok(resp) => Ok(resp),
            Err(e) => match e.response() {
                Some(response) => Ok(response),
                None => Err(std_error(e)),
            },
        }
    }
}

struct R<H>(pub Arc<H>);

impl<H: Handler> Handler for R<H> {
    fn call(&self, req: &mut Request) -> Result<Response, Box<Error + Send>> {
        let path = req.params()["path"].to_string();
        let R(ref sub_router) = *self;
        sub_router.call(&mut RequestProxy {
            other: req,
            path: Some(&path),
            method: None,
        })
    }
}

// Can't derive Debug because of RouteBuilder.
#[allow(missing_debug_implementations)]
pub struct R404(pub RouteBuilder);

impl Handler for R404 {
    fn call(&self, req: &mut Request) -> Result<Response, Box<Error + Send>> {
        let R404(ref router) = *self;
        match router.recognize(&req.method(), req.path()) {
            Ok(m) => {
                req.mut_extensions().insert(m.params.clone());
                m.handler.call(req)
            }
            Err(..) => Ok(NotFound.response().unwrap()),
        }
    }
}
<commit_msg>Test error handling logic in the router<commit_after>use std::error::Error;
use std::sync::Arc;

use conduit::{Handler, Request, Response};
use conduit_git_http_backend;
use conduit_router::{RequestParams, RouteBuilder};

use util::errors::{std_error, CargoError, CargoResult, NotFound};
use util::RequestProxy;
use {App, Env};
use controllers::*;

pub fn build_router(app: &App) -> R404 {
    let mut api_router = RouteBuilder::new();

    // Route used by both `cargo search` and the frontend
    api_router.get("/crates", C(krate::search::search));

    // Routes used by `cargo`
    api_router.put("/crates/new", C(krate::publish::publish));
    api_router.get("/crates/:crate_id/owners", C(krate::owners::owners));
    api_router.put("/crates/:crate_id/owners", C(krate::owners::add_owners));
    api_router.delete("/crates/:crate_id/owners", C(krate::owners::remove_owners));
    api_router.delete("/crates/:crate_id/:version/yank", C(version::yank::yank));
    api_router.put(
        "/crates/:crate_id/:version/unyank",
        C(version::yank::unyank),
    );
    api_router.get(
        "/crates/:crate_id/:version/download",
        C(version::downloads::download),
    );

    // Routes that appear to be unused
    api_router.get("/versions", C(version::deprecated::index));
    api_router.get("/versions/:version_id", C(version::deprecated::show));

    // Routes used by the frontend
    api_router.get("/crates/:crate_id", C(krate::metadata::show));
    api_router.get("/crates/:crate_id/:version", C(version::deprecated::show));
    api_router.get(
        "/crates/:crate_id/:version/readme",
        C(krate::metadata::readme),
    );
    api_router.get(
        "/crates/:crate_id/:version/dependencies",
        C(version::metadata::dependencies),
    );
    api_router.get(
        "/crates/:crate_id/:version/downloads",
        C(version::downloads::downloads),
    );
    api_router.get(
        "/crates/:crate_id/:version/authors",
        C(version::metadata::authors),
    );
    api_router.get(
        "/crates/:crate_id/downloads",
        C(krate::downloads::downloads),
    );
    api_router.get("/crates/:crate_id/versions", C(krate::metadata::versions));
    api_router.put("/crates/:crate_id/follow", C(krate::follow::follow));
    api_router.delete("/crates/:crate_id/follow", C(krate::follow::unfollow));
    api_router.get("/crates/:crate_id/following", C(krate::follow::following));
    api_router.get("/crates/:crate_id/owner_team", C(krate::owners::owner_team));
    api_router.get("/crates/:crate_id/owner_user", C(krate::owners::owner_user));
    api_router.get(
        "/crates/:crate_id/reverse_dependencies",
        C(krate::metadata::reverse_dependencies),
    );
    api_router.get("/keywords", C(keyword::index));
    api_router.get("/keywords/:keyword_id", C(keyword::show));
    api_router.get("/categories", C(category::index));
    api_router.get("/categories/:category_id", C(category::show));
    api_router.get("/category_slugs", C(category::slugs));
    api_router.get("/users/:user_id", C(user::other::show));
    api_router.put("/users/:user_id", C(user::me::update_user));
    api_router.get("/users/:user_id/stats", C(user::other::stats));
    api_router.get("/teams/:team_id", C(team::show_team));
    api_router.get("/me", C(user::me::me));
    api_router.get("/me/updates", C(user::me::updates));
    api_router.get("/me/tokens", C(token::list));
    api_router.put("/me/tokens", C(token::new));
    api_router.delete("/me/tokens/:id", C(token::revoke));
    api_router.get(
        "/me/crate_owner_invitations",
        C(crate_owner_invitation::list),
    );
    api_router.put(
        "/me/crate_owner_invitations/:crate_id",
        C(crate_owner_invitation::handle_invite),
    );
    api_router.get("/summary", C(krate::metadata::summary));
    api_router.put("/confirm/:email_token", C(user::me::confirm_user_email));
    api_router.put(
        "/users/:user_id/resend",
        C(user::me::regenerate_token_and_send),
    );
    api_router.get("/site_metadata", C(site_metadata::show_deployed_sha));
    let api_router = Arc::new(R404(api_router));

    let mut router = RouteBuilder::new();

    // Mount the router under the /api/v1 path so we're at least somewhat at the
    // liberty to change things in the future!
    router.get("/api/v1/*path", R(Arc::clone(&api_router)));
    router.put("/api/v1/*path", R(Arc::clone(&api_router)));
    router.post("/api/v1/*path", R(Arc::clone(&api_router)));
    router.head("/api/v1/*path", R(Arc::clone(&api_router)));
    router.delete("/api/v1/*path", R(api_router));

    router.get("/authorize_url", C(user::session::github_authorize));
    router.get("/authorize", C(user::session::github_access_token));
    router.delete("/logout", C(user::session::logout));

    // Only serve the local checkout of the git index in development mode.
    // In production, for crates.io, cargo gets the index from
    // https://github.com/rust-lang/crates.io-index directly.
    if app.config.env == Env::Development {
        let s = conduit_git_http_backend::Serve(app.git_repo_checkout.clone());
        let s = Arc::new(s);
        router.get("/git/index/*path", R(Arc::clone(&s)));
        router.post("/git/index/*path", R(s));
    }

    R404(router)
}

struct C(pub fn(&mut Request) -> CargoResult<Response>);

impl Handler for C {
    fn call(&self, req: &mut Request) -> Result<Response, Box<Error + Send>> {
        let C(f) = *self;
        match f(req) {
            Ok(resp) => Ok(resp),
            Err(e) => match e.response() {
                Some(response) => Ok(response),
                None => Err(std_error(e)),
            },
        }
    }
}

struct R<H>(pub Arc<H>);

impl<H: Handler> Handler for R<H> {
    fn call(&self, req: &mut Request) -> Result<Response, Box<Error + Send>> {
        let path = req.params()["path"].to_string();
        let R(ref sub_router) = *self;
        sub_router.call(&mut RequestProxy {
            other: req,
            path: Some(&path),
            method: None,
        })
    }
}

// Can't derive Debug because of RouteBuilder.
#[allow(missing_debug_implementations)]
pub struct R404(pub RouteBuilder);

impl Handler for R404 {
    fn call(&self, req: &mut Request) -> Result<Response, Box<Error + Send>> {
        let R404(ref router) = *self;
        match router.recognize(&req.method(), req.path()) {
            Ok(m) => {
                req.mut_extensions().insert(m.params.clone());
                m.handler.call(req)
            }
            Err(..) => Ok(NotFound.response().unwrap()),
        }
    }
}

#[cfg(test)]
mod tests {
    extern crate conduit_test;

    use self::conduit_test::MockRequest;
    use super::*;
    use diesel::result::Error as DieselError;
    use util::errors::*;

    fn err<E: CargoError>(err: E) -> CargoResult<Response> {
        Err(Box::new(err))
    }

    #[test]
    fn http_error_responses() {
        let mut req = MockRequest::new(::conduit::Method::Get, "/");

        // Types for handling common error status codes
        assert_eq!(
            C(|_| Err(bad_request(""))).call(&mut req).unwrap().status.0,
            400
        );
        assert_eq!(
            C(|_| err(Unauthorized)).call(&mut req).unwrap().status.0,
            403
        );
        assert_eq!(
            C(|_| Err(DieselError::NotFound.into()))
                .call(&mut req)
                .unwrap()
                .status
                .0,
            404
        );
        assert_eq!(C(|_| err(NotFound)).call(&mut req).unwrap().status.0, 404);

        // Human errors are returned as 200 so that cargo displays this nicely on the command line
        assert_eq!(C(|_| Err(human(""))).call(&mut req).unwrap().status.0, 200);

        // All other error types are propogated up the middleware, eventually becoming status 500
        assert!(C(|_| Err(internal(""))).call(&mut req).is_err());
        assert!(C(|_| err(::curl::Error::new(0))).call(&mut req).is_err());
        assert!(
            C(|_| err(::serde_json::Error::syntax(
                ::serde_json::error::ErrorCode::ExpectedColon,
                0,
                0
            ))).call(&mut req)
                .is_err()
        );
        assert!(
            C(|_| err(::std::io::Error::new(::std::io::ErrorKind::Other, "")))
                .call(&mut req)
                .is_err()
        );
    }
}
<|endoftext|>


<commit_before>use super::{Jira, Result, SearchOptions, SearchResults};
use url::form_urlencoded;

// search interface
pub struct Search<'a> {
    jira: &'a Jira<'a>,
}

impl<'a> Search<'a> {
    pub fn new(jira: &'a Jira<'a>) -> Search<'a> {
        Search { jira: jira }
    }

    /// https://docs.atlassian.com/jira/REST/latest/#api/2/search
    pub fn list<J>(&self, jql: J, options: &SearchOptions) -> Result<SearchResults>
        where J: Into<String>
    {
        let mut path = vec!["/search".to_owned()];
        let query_options = options.serialize().unwrap_or(String::new());
        let query = form_urlencoded::Serializer::new(query_options)
            .append_pair("jql", &jql.into())
            .finish();
        path.push(query);
        self.jira.get::<SearchResults>(path.join("?").as_ref())
    }
}
<commit_msg>expose iter interface<commit_after>use super::{Jira, Result, SearchOptions, SearchResults, SearchIter};
use url::form_urlencoded;

// search interface
pub struct Search<'a> {
    jira: &'a Jira<'a>,
}

impl<'a> Search<'a> {
    pub fn new(jira: &'a Jira<'a>) -> Search<'a> {
        Search { jira: jira }
    }

    /// https://docs.atlassian.com/jira/REST/latest/#api/2/search
    pub fn list<J>(&self, jql: J, options: &SearchOptions) -> Result<SearchResults>
        where J: Into<String>
    {
        let mut path = vec!["/search".to_owned()];
        let query_options = options.serialize().unwrap_or(String::new());
        let query = form_urlencoded::Serializer::new(query_options)
            .append_pair("jql", &jql.into())
            .finish();
        path.push(query);
        self.jira.get::<SearchResults>(path.join("?").as_ref())
    }

    pub fn iter<J>(&self, jql: J, options: &SearchOptions) -> Result<SearchIter> where J: Into<String> {
        SearchIter::new(jql, options, self.jira)
    }
}
<|endoftext|>


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

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

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

use rustc_serialize::json;

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

use rustc_serialize::json;

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

        let req = auth::get(links::statuses::SEARCH, token, Some(&params));

        make_future(handle, req, |full_resp: String, headers: &Headers| {
            let mut ret: Response<SearchResult> = try!(make_response(full_resp, headers));
            ret.params = Some(params);
            Ok(ret)
        })
    }
}

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

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

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

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

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

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

        let req = auth::get(links::statuses::SEARCH, token, Some(&params));

        make_future(handle, req, |full_resp: String, headers: &Headers| {
            let mut ret: Response<SearchResult> = try!(make_response(full_resp, headers));
            ret.params = Some(params);
            Ok(ret)
        })
    }

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

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

        let req = auth::get(links::statuses::SEARCH, token, Some(&params));

        make_future(handle, req, |full_resp: String, headers: &Headers| {
            let mut ret: Response<SearchResult> = try!(make_response(full_resp, headers));
            ret.params = Some(params);
            Ok(ret)
        })
    }
}
<|endoftext|>


<commit_before>use llvm_sys::prelude::LLVMTypeRef;

use std::fmt::Debug;

use crate::AddressSpace;
use crate::types::{IntType, FunctionType, FloatType, PointerType, StructType, ArrayType, VectorType, VoidType, Type};
use crate::types::enums::{AnyTypeEnum, BasicTypeEnum};
use crate::values::{IntMathValue, FloatMathValue, PointerMathValue, IntValue, FloatValue, PointerValue, VectorValue};

// This is an ugly privacy hack so that Type can stay private to this module
// and so that super traits using this trait will be not be implementable
// outside this library
pub trait AsTypeRef {
    fn as_type_ref(&self) -> LLVMTypeRef;
}

macro_rules! trait_type_set {
    ($trait_name:ident: $($args:ident),*) => (
        $(
            impl<'ctx> $trait_name<'ctx> for $args<'ctx> {}
        )*
    );
}

// REVIEW: print_to_string might be a good candidate to live here?
/// Represents any LLVM type.
pub trait AnyType<'ctx>: AsTypeRef + Debug {
    /// Returns an `AnyTypeEnum` that represents the current type.
    fn as_any_type_enum(&self) -> AnyTypeEnum<'ctx> {
        AnyTypeEnum::new(self.as_type_ref())
    }
}

/// Represents a basic LLVM type, that may be used in functions and struct definitions.
pub trait BasicType<'ctx>: AnyType<'ctx> {
    /// Returns a `BasicTypeEnum` that represents the current type.
    fn as_basic_type_enum(&self) -> BasicTypeEnum<'ctx> {
        BasicTypeEnum::new(self.as_type_ref())
    }

    /// Create a `FunctionType` with this `BasicType` as its return type.
    ///
    /// # Example:
    ///
    /// ```no_run
    /// use inkwell::context::Context;
    /// use inkwell::types::BasicType;
    ///
    /// let context = Context::create();
    /// let int = context.i32_type();
    /// let int_basic_type = int.as_basic_type_enum();
    /// assert_eq!(int_basic_type.fn_type(&[], false), int.fn_type(&[], false));
    /// ```
    fn fn_type(&self, param_types: &[BasicTypeEnum<'ctx>], is_var_args: bool) -> FunctionType<'ctx> {
        Type::new(self.as_type_ref()).fn_type(param_types, is_var_args)
    }

    /// Determines whether or not this `BasicType` is sized or not.
    /// For example, opaque structs are unsized.
    ///
    /// # Example
    ///
    /// ```no_run
    /// use inkwell::context::Context;
    /// use inkwell::types::BasicType;
    ///
    /// let context = Context::create();
    /// let f32_type = context.f32_type();
    /// let f32_vec_type = f32_type.vec_type(40);
    ///
    /// assert!(f32_vec_type.is_sized());
    /// ```
    fn is_sized(&self) -> bool {
        Type::new(self.as_type_ref()).is_sized()
    }

    /// Gets the size of this `BasicType`. Value may vary depending on the target architecture.
    ///
    /// # Example
    ///
    /// ```no_run
    /// use inkwell::context::Context;
    /// use inkwell::types::BasicType;
    ///
    /// let context = Context::create();
    /// let f32_type = context.f32_type();
    /// let f32_basic_type = f32_type.as_basic_type_enum();
    /// let f32_type_size = f32_basic_type.size_of();
    /// ```
    fn size_of(&self) -> Option<IntValue<'ctx>> {
        Type::new(self.as_type_ref()).size_of()
    }

    /// Create an `ArrayType` with this `BasicType` as its elements.
    ///
    /// Example:
    /// ```no_run
    /// use inkwell::context::Context;
    /// use inkwell::types::BasicType;
    ///
    /// let context = Context::create();
    /// let int = context.i32_type();
    /// let int_basic_type = int.as_basic_type_enum();
    /// assert_eq!(int_basic_type.array_type(32), int.array_type(32));
    /// ```
    fn array_type(&self, size: u32) -> ArrayType<'ctx> {
        Type::new(self.as_type_ref()).array_type(size)
    }

    /// Create a `PointerType` that points to this `BasicType`.
    ///
    /// Example:
    /// ```no_run
    /// use inkwell::context::Context;
    /// use inkwell::types::BasicType;
    /// use inkwell::AddressSpace;
    ///
    /// let context = Context::create();
    /// let int = context.i32_type();
    /// let int_basic_type = int.as_basic_type_enum();
    /// let addr_space = AddressSpace::Generic;
    /// assert_eq!(int_basic_type.ptr_type(addr_space), int.ptr_type(addr_space));
    /// ```
    fn ptr_type(&self, address_space: AddressSpace) -> PointerType<'ctx> {
        Type::new(self.as_type_ref()).ptr_type(address_space)
    }
}

/// Represents an LLVM type that can have integer math operations applied to it.
pub trait IntMathType<'ctx>: BasicType<'ctx> {
    /// The value instance of an int or int vector type.
    type ValueType: IntMathValue<'ctx>;
    /// The type for int to float or int vector to float vector conversions.
    type MathConvType: FloatMathType<'ctx>;
    /// The type for int to pointer or int vector to pointer vector conversions.
    type PtrConvType: PointerMathType<'ctx>;
}

/// Represents an LLVM type that can have floating point math operations applied to it.
pub trait FloatMathType<'ctx>: BasicType<'ctx> {
    /// The value instance of a float or float vector type.
    type ValueType: FloatMathValue<'ctx>;
    /// The type for float to int or float vector to int vector conversions.
    type MathConvType: IntMathType<'ctx>;
}

/// Represents an LLVM type that can have pointer operations applied to it.
pub trait PointerMathType<'ctx>: BasicType<'ctx> {
    /// The value instance of a pointer type.
    type ValueType: PointerMathValue<'ctx>;
    /// The type for pointer to int or pointer vector to int conversions.
    type PtrConvType: IntMathType<'ctx>;
}

trait_type_set! {AnyType: AnyTypeEnum, BasicTypeEnum, IntType, FunctionType, FloatType, PointerType, StructType, ArrayType, VoidType, VectorType}
trait_type_set! {BasicType: BasicTypeEnum, IntType, FloatType, PointerType, StructType, ArrayType, VectorType}

impl<'ctx> IntMathType<'ctx> for IntType<'ctx> {
    type ValueType = IntValue<'ctx>;
    type MathConvType = FloatType<'ctx>;
    type PtrConvType = PointerType<'ctx>;
}

impl<'ctx> IntMathType<'ctx> for VectorType<'ctx> {
    type ValueType = VectorValue<'ctx>;
    type MathConvType = VectorType<'ctx>;
    type PtrConvType = VectorType<'ctx>;
}

impl<'ctx> FloatMathType<'ctx> for FloatType<'ctx> {
    type ValueType = FloatValue<'ctx>;
    type MathConvType = IntType<'ctx>;
}

impl<'ctx> FloatMathType<'ctx> for VectorType<'ctx> {
    type ValueType = VectorValue<'ctx>;
    type MathConvType = VectorType<'ctx>;
}

impl<'ctx> PointerMathType<'ctx> for PointerType<'ctx> {
    type ValueType = PointerValue<'ctx>;
    type PtrConvType = IntType<'ctx>;
}

impl<'ctx> PointerMathType<'ctx> for VectorType<'ctx> {
    type ValueType = VectorValue<'ctx>;
    type PtrConvType = VectorType<'ctx>;
}
<commit_msg>Added comment for fixing later<commit_after>use llvm_sys::prelude::LLVMTypeRef;

use std::fmt::Debug;

use crate::AddressSpace;
use crate::types::{IntType, FunctionType, FloatType, PointerType, StructType, ArrayType, VectorType, VoidType, Type};
use crate::types::enums::{AnyTypeEnum, BasicTypeEnum};
use crate::values::{IntMathValue, FloatMathValue, PointerMathValue, IntValue, FloatValue, PointerValue, VectorValue};

// This is an ugly privacy hack so that Type can stay private to this module
// and so that super traits using this trait will be not be implementable
// outside this library
pub trait AsTypeRef {
    fn as_type_ref(&self) -> LLVMTypeRef;
}

macro_rules! trait_type_set {
    ($trait_name:ident: $($args:ident),*) => (
        $(
            impl<'ctx> $trait_name<'ctx> for $args<'ctx> {}
        )*
    );
}

// REVIEW: print_to_string might be a good candidate to live here?
/// Represents any LLVM type.
pub trait AnyType<'ctx>: AsTypeRef + Debug {
    /// Returns an `AnyTypeEnum` that represents the current type.
    fn as_any_type_enum(&self) -> AnyTypeEnum<'ctx> {
        AnyTypeEnum::new(self.as_type_ref())
    }
}

/// Represents a basic LLVM type, that may be used in functions and struct definitions.
pub trait BasicType<'ctx>: AnyType<'ctx> {
    /// Returns a `BasicTypeEnum` that represents the current type.
    fn as_basic_type_enum(&self) -> BasicTypeEnum<'ctx> {
        BasicTypeEnum::new(self.as_type_ref())
    }

    /// Create a `FunctionType` with this `BasicType` as its return type.
    ///
    /// # Example:
    ///
    /// ```no_run
    /// use inkwell::context::Context;
    /// use inkwell::types::BasicType;
    ///
    /// let context = Context::create();
    /// let int = context.i32_type();
    /// let int_basic_type = int.as_basic_type_enum();
    /// assert_eq!(int_basic_type.fn_type(&[], false), int.fn_type(&[], false));
    /// ```
    fn fn_type(&self, param_types: &[BasicTypeEnum<'ctx>], is_var_args: bool) -> FunctionType<'ctx> {
        Type::new(self.as_type_ref()).fn_type(param_types, is_var_args)
    }

    /// Determines whether or not this `BasicType` is sized or not.
    /// For example, opaque structs are unsized.
    ///
    /// # Example
    ///
    /// ```no_run
    /// use inkwell::context::Context;
    /// use inkwell::types::BasicType;
    ///
    /// let context = Context::create();
    /// let f32_type = context.f32_type();
    /// let f32_vec_type = f32_type.vec_type(40);
    ///
    /// assert!(f32_vec_type.is_sized());
    /// ```
    fn is_sized(&self) -> bool {
        Type::new(self.as_type_ref()).is_sized()
    }

    /// Gets the size of this `BasicType`. Value may vary depending on the target architecture.
    ///
    /// # Example
    ///
    /// ```no_run
    /// use inkwell::context::Context;
    /// use inkwell::types::BasicType;
    ///
    /// let context = Context::create();
    /// let f32_type = context.f32_type();
    /// let f32_basic_type = f32_type.as_basic_type_enum();
    /// let f32_type_size = f32_basic_type.size_of();
    /// ```
    fn size_of(&self) -> Option<IntValue<'ctx>> {
        Type::new(self.as_type_ref()).size_of()
    }

    /// Create an `ArrayType` with this `BasicType` as its elements.
    ///
    /// Example:
    /// ```no_run
    /// use inkwell::context::Context;
    /// use inkwell::types::BasicType;
    ///
    /// let context = Context::create();
    /// let int = context.i32_type();
    /// let int_basic_type = int.as_basic_type_enum();
    /// assert_eq!(int_basic_type.array_type(32), int.array_type(32));
    /// ```
    // FIXME: This likely doesn't belong on the trait, since not all basic types can be turned into arrays?
    fn array_type(&self, size: u32) -> ArrayType<'ctx> {
        Type::new(self.as_type_ref()).array_type(size)
    }

    /// Create a `PointerType` that points to this `BasicType`.
    ///
    /// Example:
    /// ```no_run
    /// use inkwell::context::Context;
    /// use inkwell::types::BasicType;
    /// use inkwell::AddressSpace;
    ///
    /// let context = Context::create();
    /// let int = context.i32_type();
    /// let int_basic_type = int.as_basic_type_enum();
    /// let addr_space = AddressSpace::Generic;
    /// assert_eq!(int_basic_type.ptr_type(addr_space), int.ptr_type(addr_space));
    /// ```
    fn ptr_type(&self, address_space: AddressSpace) -> PointerType<'ctx> {
        Type::new(self.as_type_ref()).ptr_type(address_space)
    }
}

/// Represents an LLVM type that can have integer math operations applied to it.
pub trait IntMathType<'ctx>: BasicType<'ctx> {
    /// The value instance of an int or int vector type.
    type ValueType: IntMathValue<'ctx>;
    /// The type for int to float or int vector to float vector conversions.
    type MathConvType: FloatMathType<'ctx>;
    /// The type for int to pointer or int vector to pointer vector conversions.
    type PtrConvType: PointerMathType<'ctx>;
}

/// Represents an LLVM type that can have floating point math operations applied to it.
pub trait FloatMathType<'ctx>: BasicType<'ctx> {
    /// The value instance of a float or float vector type.
    type ValueType: FloatMathValue<'ctx>;
    /// The type for float to int or float vector to int vector conversions.
    type MathConvType: IntMathType<'ctx>;
}

/// Represents an LLVM type that can have pointer operations applied to it.
pub trait PointerMathType<'ctx>: BasicType<'ctx> {
    /// The value instance of a pointer type.
    type ValueType: PointerMathValue<'ctx>;
    /// The type for pointer to int or pointer vector to int conversions.
    type PtrConvType: IntMathType<'ctx>;
}

trait_type_set! {AnyType: AnyTypeEnum, BasicTypeEnum, IntType, FunctionType, FloatType, PointerType, StructType, ArrayType, VoidType, VectorType}
trait_type_set! {BasicType: BasicTypeEnum, IntType, FloatType, PointerType, StructType, ArrayType, VectorType}

impl<'ctx> IntMathType<'ctx> for IntType<'ctx> {
    type ValueType = IntValue<'ctx>;
    type MathConvType = FloatType<'ctx>;
    type PtrConvType = PointerType<'ctx>;
}

impl<'ctx> IntMathType<'ctx> for VectorType<'ctx> {
    type ValueType = VectorValue<'ctx>;
    type MathConvType = VectorType<'ctx>;
    type PtrConvType = VectorType<'ctx>;
}

impl<'ctx> FloatMathType<'ctx> for FloatType<'ctx> {
    type ValueType = FloatValue<'ctx>;
    type MathConvType = IntType<'ctx>;
}

impl<'ctx> FloatMathType<'ctx> for VectorType<'ctx> {
    type ValueType = VectorValue<'ctx>;
    type MathConvType = VectorType<'ctx>;
}

impl<'ctx> PointerMathType<'ctx> for PointerType<'ctx> {
    type ValueType = PointerValue<'ctx>;
    type PtrConvType = IntType<'ctx>;
}

impl<'ctx> PointerMathType<'ctx> for VectorType<'ctx> {
    type ValueType = VectorValue<'ctx>;
    type PtrConvType = VectorType<'ctx>;
}
<|endoftext|>


<commit_before>use grain_capnp::{PowerboxCapability, UiView, UiSession};
use web_session_capnp::{WebSession};

use collections::hashmap::HashMap;
use capnp::capability::{ClientHook, FromServer};
use capnp::AnyPointer;
use capnp_rpc::rpc::{RpcConnectionState, SturdyRefRestorer};
use capnp_rpc::capability::{LocalClient};

use sqlite3;

pub struct UiViewImpl;

impl PowerboxCapability::Server for UiViewImpl {
    fn get_powerbox_info(&mut self, context : PowerboxCapability::GetPowerboxInfoContext) {
        context.done()
    }
}

impl UiView::Server for UiViewImpl {
    fn get_view_info(&mut self, context : UiView::GetViewInfoContext) {
        context.done()
    }

    fn new_session(&mut self, mut context : UiView::NewSessionContext) {
        println!("asked for a new session!");
        let (_, results) = context.get();

        let client : WebSession::Client = FromServer::new(None::<LocalClient>, ~WebSessionImpl::new());
        // we need to do this dance to upcast.
        results.set_session(UiSession::Client { client : client.client});

        context.done()
    }
}

pub struct WebSessionImpl {
    db : sqlite3::Database,
}

impl WebSessionImpl {
    pub fn new() -> WebSessionImpl {
        WebSessionImpl {
            db : sqlite3::open("/var/data.db").unwrap(),
        }
    }
}

impl UiSession::Server for WebSessionImpl {

}

struct Path {
    path : ~str,
    query : HashMap<~str, ~str>,
}

impl Path {
    fn new() -> Path {
        Path { path : ~"", query : HashMap::new() }
    }
}

fn parse_path(path : &str) -> Path {
    let mut result = Path::new();

    let v : ~[&str] = path.splitn('?', 2).collect();
    if v.len() == 0 {
        return result;
    }
    result.path = v[0].into_owned();
    if v.len() == 1 {
        return result;
    }
    for attr in v[1].split('&') {
        let a : ~[&str] = attr.splitn('=', 2).collect();
        if a.len() == 2 {
            result.query.insert(a[0].into_owned(),
                                a[1].into_owned());
        }
    }
    return result;
}

impl WebSessionImpl {

    fn checked<T>(&self, result : sqlite3::SqliteResult<T>) -> T {
        match result {
            Err(e) => {fail!("database error: {}, {:?}", e, self.db.get_errmsg()) }
            Ok(v) => { return v; }
        }
    }

    fn is_word(&self, word : &str) -> sqlite3::SqliteResult<bool> {

        if ! word.is_alphanumeric() { return Ok(false); }

        let cursor = try!(self.db.prepare(
            format!("SELECT * FROM Words WHERE Word = \"{}\";", word),
            &None));

        return Ok(try!(cursor.step_row()).is_some());
    }

    fn validate_def(&self, word : &str, definition : &[&str]) -> sqlite3::SqliteResult<bool> {

        if definition.len() != word.len() { return Ok(false); }

        let mut idx = 0;
        for &d in definition.iter() {
            if !(try!(self.is_word(d)) && d.len() > 0 && d[0] == word[idx]) {
                return Ok(false);
            }

            idx += 1;
        }

        return Ok(true);
    }

    fn write_def(&self, word : &str, definition : &[&str]) -> sqlite3::SqliteResult<()> {
        let mut query = StrBuf::new();
        query.push_str(format!("BEGIN; DELETE FROM Definitions WHERE Definee =\"{}\"; ", word));
        query.push_str("INSERT INTO Definitions(Definee, Idx, Definer) VALUES");
        let mut idx = 0;
        for &d in definition.iter() {
            if idx != 0 { query.push_str(","); }
            query.push_str(format!("(\"{}\", {}, \"{}\")", word, idx, d));
            idx += 1;
        }
        query.push_str("; COMMIT;");

        println!("query: {}", query);

        try!(self.db.exec(query.as_slice()));

        return Ok(());
    }

    fn get_def(&self, word : &str) -> sqlite3::SqliteResult<~str> {

        let cursor = try!(self.db.prepare(
            format!("SELECT * FROM Definitions WHERE Definee = \"{}\";", word),
            &None));

        let mut map = HashMap::<int, ~str>::new();

        loop {
            match try!(cursor.step_row()) {
                None => break,
                Some(row) => {
                    let definer = match row.get(&~"Definer") { &sqlite3::Text(ref t) => t.clone(), _ => fail!(), };
                    let idx = match row.get(&~"Idx") { &sqlite3::Integer(ref i) => i.clone(), _ => fail!(), };

                    map.insert(idx, definer);
                }
            }
        }

        if map.len() != word.len() {
            return Ok(~"
this word has no definition yet
");
        } else {

            let mut result = StrBuf::new();
            result.push_str("
");
            for idx in range::<int>(0, word.len() as int) {
                let definer : &str = map.get(&idx).as_slice();
                result.push_str(format!(" {word} ", word=definer));
            }
            result.push_str("
");
            return Ok(result.into_owned());
        }
    }

}

static main_css : &'static str =
    "body { font-family: Helvetica, Sans, Arial;
            font-size: medium;
             margin-left: auto;
             margin-right: auto;
             width: 600px;
             text-align: center;
     }
    .word {
        text-align: center;
        font-size: 500%;
     }
     .err {
       font-size: 90%;
       color: #AA0000;
     }
     .title {
       text-align: center;
       font-size:500%;
     }
     ";

static header : &'static str =
  r#"<title> acronymy </title><link rel="stylesheet" type="text/css" href="main.css" >
 <meta http-equiv="Content-Type" content="text/html;charset=utf-8" >
  "#;

static lookup_form : &'static str =
      r#"<form action="define" method="get">
          <input name="word"/><button>go</button></form>"#;

fn define_form(word :&str) -> ~str {
       format!("<form action=\"define\" method=\"get\">
               <input name=\"word\" value=\"{word}\" type=\"hidden\"/>
               <input name=\"definition\"/><button>define</button></form>", word=word)
}

enum PageData<'a> {
    NoWord,
    WordAndDef(&'a str, &'a str, Option<&'a str>),
    HomePage,
}

fn construct_html(page_data : PageData) -> ~str {
    let mut result = StrBuf::new();
    result.push_str(format!("{}", header));
    match page_data {
        NoWord => {
            result.push_str("
 that's not a word
");
        }
        WordAndDef(word, def_div, _err) => {
            result.push_str(format!("
{}
", word));

            result.push_str(def_div);
            result.push_str(define_form(word));
        }
        HomePage => {
            result.push_str("
Acronymy
");
            result.push_str("
A user-editable dictionary.
");
        }
    }

    result.push_str(lookup_form);

    result.push_str("");
    result.into_owned()
}

impl WebSession::Server for WebSessionImpl {
    fn get(&mut self, mut context : WebSession::GetContext) {
        println!("GET");
        let (params, results) = context.get();
        let raw_path = params.get_path();
        let content = results.init_content();
        content.set_mime_type("text/html");

        let path = parse_path(raw_path);
        println!("path = {}", raw_path);

        if raw_path == "main.css" {
            content.get_body().set_bytes(main_css.as_bytes())
        } else if path.path.as_slice() == "define" {
            let word : ~str = match path.query.find(&~"word") {
                Some(w) if self.checked(self.is_word(*w)) => {
                    w.clone()
                }
                _ => {
                    content.get_body().set_bytes(construct_html(NoWord).as_bytes());
                    return context.done();
                }
            };

            match path.query.find(&~"definition") {
                None => {
                    let def_div = self.checked(self.get_def(word));

                    content.get_body().set_bytes(construct_html(WordAndDef(word.as_slice(),
                                                                           def_div.as_slice(),
                                                                           None)).as_bytes());
                }
                Some(def_query) => {

                    let definition : ~[&str] = def_query.split('+').collect();

                    if self.checked(self.validate_def(word, definition)) {

                        self.checked(self.write_def(word, definition));
                        let def_div = self.checked(self.get_def(word));
                        content.get_body().set_bytes(
                            construct_html(WordAndDef(word.as_slice(),
                                                      def_div.as_slice(),
                                                      None)).as_bytes());

                    } else {

                        let def_div = self.checked(self.get_def(word));

                        content.get_body().set_bytes(
                            construct_html(WordAndDef(word.as_slice(),
                                                      def_div.as_slice(),
                                                      Some("invalid definition"))).as_bytes());
                    }
                }
            }

        } else {
            content.get_body().set_bytes(construct_html(HomePage).as_bytes());
        }
        context.done()
    }
    fn post(&mut self, context : WebSession::PostContext) {
        println!("POST");
        context.done()
    }
    fn put(&mut self, context : WebSession::PutContext) {
        println!("PUT");
        context.done()
    }
    fn delete(&mut self, context : WebSession::DeleteContext) {
        println!("DELETE");
        context.done()
    }
    fn open_web_socket(&mut self, context : WebSession::OpenWebSocketContext) {
        println!("OPEN WEB SOCKET");
        context.done()
    }
}

pub struct FdStream {
    inner : ~::std::rt::rtio::RtioFileStream:Send,
}

impl FdStream {
    pub fn new(fd : ::libc::c_int) -> ::std::io::IoResult<FdStream> {
        ::std::rt::rtio::LocalIo::maybe_raise(|io| {
            Ok (FdStream { inner : io.fs_from_raw_fd(fd, ::std::rt::rtio::DontClose) })
        })
    }
}

impl Reader for FdStream {
    fn read(&mut self, buf : &mut [u8]) -> ::std::io::IoResult<uint> {
        self.inner.read(buf).map(|i| i as uint)
    }
}

impl Writer for FdStream {
    fn write(&mut self, buf : &[u8]) -> ::std::io::IoResult<()> {
        self.inner.write(buf)
    }
}

pub struct Restorer;

impl SturdyRefRestorer for Restorer {
    fn restore(&self, obj_id : AnyPointer::Reader) -> Option<~ClientHook:Send> {
        if obj_id.is_null() {
            let client : UiView::Client = FromServer::new(None::<LocalClient>, ~UiViewImpl);
            Some(client.client.hook)
        } else {
            None
        }
    }
}

pub fn main() -> ::std::io::IoResult<()> {

    let args = ::std::os::args();

    if args.len() == 4 && args[1].as_slice() == "--init" {
        println!("initializing...");
        let initdb_path = ::std::path::Path::new(args[2].as_slice());
        let proddb_path = ::std::path::Path::new(args[3].as_slice());
        println!("copying database from {} to {}", args[2], args[3]);
        try!(::std::io::fs::copy(&initdb_path, &proddb_path));
        println!("success!");
    }

    let ifs = try!(FdStream::new(3));
    let ofs = try!(FdStream::new(3));

    let connection_state = RpcConnectionState::new();
    connection_state.run(ifs, ofs, Restorer);

    Ok(())
}

<commit_msg>shuffling the links<commit_after>use grain_capnp::{PowerboxCapability, UiView, UiSession};
use web_session_capnp::{WebSession};

use collections::hashmap::HashMap;
use capnp::capability::{ClientHook, FromServer};
use capnp::AnyPointer;
use capnp_rpc::rpc::{RpcConnectionState, SturdyRefRestorer};
use capnp_rpc::capability::{LocalClient};

use sqlite3;

pub struct UiViewImpl;

impl PowerboxCapability::Server for UiViewImpl {
    fn get_powerbox_info(&mut self, context : PowerboxCapability::GetPowerboxInfoContext) {
        context.done()
    }
}

impl UiView::Server for UiViewImpl {
    fn get_view_info(&mut self, context : UiView::GetViewInfoContext) {
        context.done()
    }

    fn new_session(&mut self, mut context : UiView::NewSessionContext) {
        println!("asked for a new session!");
        let (_, results) = context.get();

        let client : WebSession::Client = FromServer::new(None::<LocalClient>, ~WebSessionImpl::new());
        // we need to do this dance to upcast.
        results.set_session(UiSession::Client { client : client.client});

        context.done()
    }
}

pub struct WebSessionImpl {
    db : sqlite3::Database,
}

impl WebSessionImpl {
    pub fn new() -> WebSessionImpl {
        WebSessionImpl {
            db : sqlite3::open("/var/data.db").unwrap(),
        }
    }
}

impl UiSession::Server for WebSessionImpl {

}

struct Path {
    path : ~str,
    query : HashMap<~str, ~str>,
}

impl Path {
    fn new() -> Path {
        Path { path : ~"", query : HashMap::new() }
    }
}

fn parse_path(path : &str) -> Path {
    let mut result = Path::new();

    let v : ~[&str] = path.splitn('?', 2).collect();
    if v.len() == 0 {
        return result;
    }
    result.path = v[0].into_owned();
    if v.len() == 1 {
        return result;
    }
    for attr in v[1].split('&') {
        let a : ~[&str] = attr.splitn('=', 2).collect();
        if a.len() == 2 {
            result.query.insert(a[0].into_owned(),
                                a[1].into_owned());
        }
    }
    return result;
}

impl WebSessionImpl {

    fn checked<T>(&self, result : sqlite3::SqliteResult<T>) -> T {
        match result {
            Err(e) => {fail!("database error: {}, {:?}", e, self.db.get_errmsg()) }
            Ok(v) => { return v; }
        }
    }

    fn is_word(&self, word : &str) -> sqlite3::SqliteResult<bool> {

        if ! word.is_alphanumeric() { return Ok(false); }

        let cursor = try!(self.db.prepare(
            format!("SELECT * FROM Words WHERE Word = \"{}\";", word),
            &None));

        return Ok(try!(cursor.step_row()).is_some());
    }

    fn validate_def(&self, word : &str, definition : &[&str]) -> sqlite3::SqliteResult<bool> {

        if definition.len() != word.len() { return Ok(false); }

        let mut idx = 0;
        for &d in definition.iter() {
            if !(try!(self.is_word(d)) && d.len() > 0 && d[0] == word[idx]) {
                return Ok(false);
            }

            idx += 1;
        }

        return Ok(true);
    }

    fn write_def(&self, word : &str, definition : &[&str]) -> sqlite3::SqliteResult<()> {
        let mut query = StrBuf::new();
        query.push_str(format!("BEGIN; DELETE FROM Definitions WHERE Definee =\"{}\"; ", word));
        query.push_str("INSERT INTO Definitions(Definee, Idx, Definer) VALUES");
        let mut idx = 0;
        for &d in definition.iter() {
            if idx != 0 { query.push_str(","); }
            query.push_str(format!("(\"{}\", {}, \"{}\")", word, idx, d));
            idx += 1;
        }
        query.push_str("; COMMIT;");

        println!("query: {}", query);

        try!(self.db.exec(query.as_slice()));

        return Ok(());
    }

    fn get_def(&self, word : &str) -> sqlite3::SqliteResult<~str> {

        let cursor = try!(self.db.prepare(
            format!("SELECT * FROM Definitions WHERE Definee = \"{}\";", word),
            &None));

        let mut map = HashMap::<int, ~str>::new();

        loop {
            match try!(cursor.step_row()) {
                None => break,
                Some(row) => {
                    let definer = match row.get(&~"Definer") { &sqlite3::Text(ref t) => t.clone(), _ => fail!(), };
                    let idx = match row.get(&~"Idx") { &sqlite3::Integer(ref i) => i.clone(), _ => fail!(), };

                    map.insert(idx, definer);
                }
            }
        }

        if map.len() != word.len() {
            return Ok(~"
this word has no definition yet
");
        } else {

            let mut result = StrBuf::new();
            result.push_str("
");
            for idx in range::<int>(0, word.len() as int) {
                let definer : &str = map.get(&idx).as_slice();
                result.push_str(format!(" {word} ", word=definer));
            }
            result.push_str("
");
            return Ok(result.into_owned());
        }
    }

}

static main_css : &'static str =
    "body { font-family: Helvetica, Sans, Arial;
            font-size: medium;
             margin-left: auto;
             margin-right: auto;
             width: 600px;
             text-align: center;
     }
    .word {
        text-align: center;
        font-size: 500%;
     }
     .err {
       font-size: 90%;
       color: #AA0000;
     }
     .title {
       text-align: center;
       font-size:500%;
     }
     ";

static header : &'static str =
  r#"<title> acronymy </title><link rel="stylesheet" type="text/css" href="main.css" >
 <meta http-equiv="Content-Type" content="text/html;charset=utf-8" >
  "#;

static lookup_form : &'static str =
      r#"<form action="define" method="get">
          <input name="word"/><button>find word</button></form>"#;

fn define_form(word :&str) -> ~str {
       format!("<form action=\"define\" method=\"get\">
               <input name=\"word\" value=\"{word}\" type=\"hidden\"/>
               <input name=\"definition\"/><button>submit definition</button></form>", word=word)
}

enum PageData<'a> {
    NoWord,
    WordAndDef(&'a str, &'a str, Option<&'a str>),
    HomePage,
}

fn construct_html(page_data : PageData) -> ~str {
    let mut result = StrBuf::new();
    result.push_str(format!("{}", header));
    match page_data {
        NoWord => {
            result.push_str("
 that's not a word
");
            result.push_str(lookup_form);
            result.push_str("home");
        }
        WordAndDef(word, def_div, _err) => {
            result.push_str(format!("
{}
", word));

            result.push_str(def_div);
            result.push_str(define_form(word));
            result.push_str("home");
        }
        HomePage => {
            result.push_str("
Acronymy
");
            result.push_str("
A user-editable dictionary.
");
            result.push_str(lookup_form);
        }
    }

    result.push_str("");
    result.into_owned()
}

impl WebSession::Server for WebSessionImpl {
    fn get(&mut self, mut context : WebSession::GetContext) {
        println!("GET");
        let (params, results) = context.get();
        let raw_path = params.get_path();
        let content = results.init_content();
        content.set_mime_type("text/html");

        let path = parse_path(raw_path);
        println!("path = {}", raw_path);

        if raw_path == "main.css" {
            content.get_body().set_bytes(main_css.as_bytes())
        } else if path.path.as_slice() == "define" {
            let word : ~str = match path.query.find(&~"word") {
                Some(w) if self.checked(self.is_word(*w)) => {
                    w.clone()
                }
                _ => {
                    content.get_body().set_bytes(construct_html(NoWord).as_bytes());
                    return context.done();
                }
            };

            match path.query.find(&~"definition") {
                None => {
                    let def_div = self.checked(self.get_def(word));

                    content.get_body().set_bytes(construct_html(WordAndDef(word.as_slice(),
                                                                           def_div.as_slice(),
                                                                           None)).as_bytes());
                }
                Some(def_query) => {

                    let definition : ~[&str] = def_query.split('+').collect();

                    if self.checked(self.validate_def(word, definition)) {

                        self.checked(self.write_def(word, definition));
                        let def_div = self.checked(self.get_def(word));
                        content.get_body().set_bytes(
                            construct_html(WordAndDef(word.as_slice(),
                                                      def_div.as_slice(),
                                                      None)).as_bytes());

                    } else {

                        let def_div = self.checked(self.get_def(word));

                        content.get_body().set_bytes(
                            construct_html(WordAndDef(word.as_slice(),
                                                      def_div.as_slice(),
                                                      Some("invalid definition"))).as_bytes());
                    }
                }
            }

        } else {
            content.get_body().set_bytes(construct_html(HomePage).as_bytes());
        }
        context.done()
    }
    fn post(&mut self, context : WebSession::PostContext) {
        println!("POST");
        context.done()
    }
    fn put(&mut self, context : WebSession::PutContext) {
        println!("PUT");
        context.done()
    }
    fn delete(&mut self, context : WebSession::DeleteContext) {
        println!("DELETE");
        context.done()
    }
    fn open_web_socket(&mut self, context : WebSession::OpenWebSocketContext) {
        println!("OPEN WEB SOCKET");
        context.done()
    }
}

pub struct FdStream {
    inner : ~::std::rt::rtio::RtioFileStream:Send,
}

impl FdStream {
    pub fn new(fd : ::libc::c_int) -> ::std::io::IoResult<FdStream> {
        ::std::rt::rtio::LocalIo::maybe_raise(|io| {
            Ok (FdStream { inner : io.fs_from_raw_fd(fd, ::std::rt::rtio::DontClose) })
        })
    }
}

impl Reader for FdStream {
    fn read(&mut self, buf : &mut [u8]) -> ::std::io::IoResult<uint> {
        self.inner.read(buf).map(|i| i as uint)
    }
}

impl Writer for FdStream {
    fn write(&mut self, buf : &[u8]) -> ::std::io::IoResult<()> {
        self.inner.write(buf)
    }
}

pub struct Restorer;

impl SturdyRefRestorer for Restorer {
    fn restore(&self, obj_id : AnyPointer::Reader) -> Option<~ClientHook:Send> {
        if obj_id.is_null() {
            let client : UiView::Client = FromServer::new(None::<LocalClient>, ~UiViewImpl);
            Some(client.client.hook)
        } else {
            None
        }
    }
}

pub fn main() -> ::std::io::IoResult<()> {

    let args = ::std::os::args();

    if args.len() == 4 && args[1].as_slice() == "--init" {
        println!("initializing...");
        let initdb_path = ::std::path::Path::new(args[2].as_slice());
        let proddb_path = ::std::path::Path::new(args[3].as_slice());
        println!("copying database from {} to {}", args[2], args[3]);
        try!(::std::io::fs::copy(&initdb_path, &proddb_path));
        println!("success!");
    }

    // sandstorm launches us with a connection file descriptor 3
    let ifs = try!(FdStream::new(3));
    let ofs = try!(FdStream::new(3));

    let connection_state = RpcConnectionState::new();
    connection_state.run(ifs, ofs, Restorer);

    Ok(())
}

<|endoftext|>