<commit_before>#[macro_use]
extern crate lazy_static;
extern crate nats_client;
extern crate openssl;

use std::process::Command;
use std::sync::Arc;
use std::sync::Mutex;
use std::sync::mpsc;
use std::thread;
use std::time::Duration;
use std::path::Path;

use openssl::ssl::SslContext;
use openssl::ssl::SslMethod;

use nats_client::NatsConn;
use nats_client::Config;

lazy_static! {
    static ref LOCK: Arc<Mutex<()>> = Arc::new(Mutex::new(()));
    static ref WAIT: Duration = Duration::new(0, 10000000);
}

#[test]
#[ignore]
fn test_connect() {
    let l = LOCK.lock().unwrap();
    let mut gnatsd = Command::new("gnatsd").spawn().unwrap();
    thread::sleep(*WAIT);

    let config = Config::default();
    NatsConn::new(config).unwrap();

    gnatsd.kill().unwrap();
    thread::sleep(*WAIT);
}

#[test]
#[ignore]
fn test_pub_sub_channel() {
    let l = LOCK.lock().unwrap();
    let mut gnatsd = Command::new("gnatsd").spawn().unwrap();
    thread::sleep(*WAIT);

    let config = Config::default();
    let mut conn = NatsConn::new(config).unwrap();
    let sub = conn.subscribe_channel("topic1", None).unwrap();
    conn.publish("topic1", None, b"data").unwrap();
    conn.flush().unwrap();

    thread::sleep(Duration::new(1, 0));
    assert_eq!(b"data", sub.receiver.try_recv().unwrap().data.as_slice());
    conn.unsubscribe(&sub).unwrap();

    conn.publish("topic1", None, b"data").unwrap();
    thread::sleep(Duration::new(1, 0));
    assert!(sub.receiver.try_recv().is_err());

    gnatsd.kill().unwrap();
    thread::sleep(*WAIT);
}

#[test]
#[ignore]
fn test_pub_sub_callback() {
    let l = LOCK.lock().unwrap();
    let mut gnatsd = Command::new("gnatsd").spawn().unwrap();
    thread::sleep(*WAIT);

    let config = Config::default();
    let mut conn = NatsConn::new(config).unwrap();

    let num = Arc::new(Mutex::new(47));
    let num2 = num.clone();

    let sub = conn.subscribe_async("topic2", None, move |_| {
        *num2.lock().unwrap() = 72;
    }).unwrap();
    conn.publish("topic2", None, b"data").unwrap();
    conn.flush().unwrap();

    thread::sleep(Duration::new(1, 0));
    assert_eq!(72, *num.lock().unwrap());
    conn.unsubscribe(&sub).unwrap();

    gnatsd.kill().unwrap();
    thread::sleep(*WAIT);
}

#[test]
#[ignore]
fn test_reconnect() {
    let l = LOCK.lock().unwrap();
    let mut gnatsd = Command::new("gnatsd").spawn().unwrap();
    thread::sleep(*WAIT);

    let mut config = Config::default();
    config.hosts.push("nats://localhost:4223".to_owned());
    let mut conn = NatsConn::new(config).unwrap();

    let sub = conn.subscribe_channel("reconnect_topic", None).unwrap();
    conn.publish("reconnect_topic", None, b"data1").unwrap();
    conn.flush().unwrap();

    thread::sleep(Duration::new(1, 0));
    assert_eq!(b"data1", sub.receiver.try_recv().unwrap().data.as_slice());
    gnatsd.kill().unwrap();
    thread::sleep(*WAIT);

    let (tx, rx) = mpsc::channel();

    let gnatsd2_handle = thread::spawn(move || {
        thread::sleep(Duration::new(5, 0));
        let mut gnatsd2 = Command::new("gnatsd")
            .arg("-p")
            .arg("4223")
            .spawn().unwrap();
        rx.recv().unwrap();
        gnatsd2.kill().unwrap();
    });

    conn.publish("reconnect_topic", None, b"data2").unwrap();
    conn.flush().unwrap();

    thread::sleep(Duration::new(1, 0));
    assert_eq!(b"data2", sub.receiver.try_recv().unwrap().data.as_slice());
    tx.send(()).unwrap();
    gnatsd2_handle.join().unwrap();
}

#[test]
#[ignore]
fn test_ssl() {
    let l = LOCK.lock().unwrap();
    let mut gnatsd = Command::new("gnatsd")
        .arg("--tls")
        .arg("--tlscert")
        .arg("tests/certs/server.pem")
        .arg("--tlskey")
        .arg("tests/certs/key.pem")
        .spawn().unwrap();
    thread::sleep(*WAIT);

    let mut ssl_context = SslContext::new(SslMethod::Tlsv1_2).unwrap();
    let path = Path::new("tests/certs/ca.pem");
    ssl_context.set_CA_file(&path).unwrap();
    let config = Config {ssl_context: Some(ssl_context), ..Default::default()};

    let mut conn = NatsConn::new(config).unwrap();
    let sub = conn.subscribe_channel("topic1", None).unwrap();
    conn.publish("topic1", None, b"data").unwrap();
    conn.flush().unwrap();

    thread::sleep(Duration::new(1, 0));
    assert_eq!(b"data", sub.receiver.try_recv().unwrap().data.as_slice());
    conn.unsubscribe(&sub).unwrap();

    gnatsd.kill().unwrap();
    thread::sleep(*WAIT);
}
<commit_msg>add comment to tests<commit_after>#![allow(unused_variables)]

#[macro_use]
extern crate lazy_static;
extern crate nats_client;
extern crate openssl;

use std::process::Command;
use std::sync::Arc;
use std::sync::Mutex;
use std::sync::mpsc;
use std::thread;
use std::time::Duration;
use std::path::Path;

use openssl::ssl::SslContext;
use openssl::ssl::SslMethod;

use nats_client::NatsConn;
use nats_client::Config;

/// General strategy:
/// Grab lock to make sure only one test can run at a time
/// Start nats server and interact with it
/// TODO start gnatsd on unique port so lock isn't needed

lazy_static! {
    static ref LOCK: Arc<Mutex<()>> = Arc::new(Mutex::new(()));
    static ref WAIT: Duration = Duration::new(0, 10000000);
}

#[test]
#[ignore]
fn test_connect() {
    let l = LOCK.lock().unwrap();
    let mut gnatsd = Command::new("gnatsd").spawn().unwrap();
    thread::sleep(*WAIT);

    let config = Config::default();
    NatsConn::new(config).unwrap();

    gnatsd.kill().unwrap();
    thread::sleep(*WAIT);
}

#[test]
#[ignore]
fn test_pub_sub_channel() {
    let l = LOCK.lock().unwrap();
    let mut gnatsd = Command::new("gnatsd").spawn().unwrap();
    thread::sleep(*WAIT);

    let config = Config::default();
    let mut conn = NatsConn::new(config).unwrap();
    let sub = conn.subscribe_channel("topic1", None).unwrap();
    conn.publish("topic1", None, b"data").unwrap();
    conn.flush().unwrap();

    thread::sleep(Duration::new(1, 0));
    assert_eq!(b"data", sub.receiver.try_recv().unwrap().data.as_slice());
    conn.unsubscribe(&sub).unwrap();

    conn.publish("topic1", None, b"data").unwrap();
    thread::sleep(Duration::new(1, 0));
    assert!(sub.receiver.try_recv().is_err());

    gnatsd.kill().unwrap();
    thread::sleep(*WAIT);
}

#[test]
#[ignore]
fn test_pub_sub_callback() {
    let l = LOCK.lock().unwrap();
    let mut gnatsd = Command::new("gnatsd").spawn().unwrap();
    thread::sleep(*WAIT);

    let config = Config::default();
    let mut conn = NatsConn::new(config).unwrap();

    let num = Arc::new(Mutex::new(47));
    let num2 = num.clone();

    let sub = conn.subscribe_async("topic2", None, move |_| {
        *num2.lock().unwrap() = 72;
    }).unwrap();
    conn.publish("topic2", None, b"data").unwrap();
    conn.flush().unwrap();

    thread::sleep(Duration::new(1, 0));
    assert_eq!(72, *num.lock().unwrap());
    conn.unsubscribe(&sub).unwrap();

    gnatsd.kill().unwrap();
    thread::sleep(*WAIT);
}

#[test]
#[ignore]
fn test_reconnect() {
    let l = LOCK.lock().unwrap();
    let mut gnatsd = Command::new("gnatsd").spawn().unwrap();
    thread::sleep(*WAIT);

    let mut config = Config::default();
    config.hosts.push("nats://localhost:4223".to_owned());
    let mut conn = NatsConn::new(config).unwrap();

    let sub = conn.subscribe_channel("reconnect_topic", None).unwrap();
    conn.publish("reconnect_topic", None, b"data1").unwrap();
    conn.flush().unwrap();

    thread::sleep(Duration::new(1, 0));
    assert_eq!(b"data1", sub.receiver.try_recv().unwrap().data.as_slice());
    gnatsd.kill().unwrap();
    thread::sleep(*WAIT);

    let (tx, rx) = mpsc::channel();

    let gnatsd2_handle = thread::spawn(move || {
        thread::sleep(Duration::new(5, 0));
        let mut gnatsd2 = Command::new("gnatsd")
            .arg("-p")
            .arg("4223")
            .spawn().unwrap();
        rx.recv().unwrap();
        gnatsd2.kill().unwrap();
    });

    conn.publish("reconnect_topic", None, b"data2").unwrap();
    conn.flush().unwrap();

    thread::sleep(Duration::new(1, 0));
    assert_eq!(b"data2", sub.receiver.try_recv().unwrap().data.as_slice());
    tx.send(()).unwrap();
    gnatsd2_handle.join().unwrap();
}

#[test]
#[ignore]
fn test_ssl() {
    let l = LOCK.lock().unwrap();
    let mut gnatsd = Command::new("gnatsd")
        .arg("--tls")
        .arg("--tlscert")
        .arg("tests/certs/server.pem")
        .arg("--tlskey")
        .arg("tests/certs/key.pem")
        .spawn().unwrap();
    thread::sleep(*WAIT);

    let mut ssl_context = SslContext::new(SslMethod::Tlsv1_2).unwrap();
    let path = Path::new("tests/certs/ca.pem");
    ssl_context.set_CA_file(&path).unwrap();
    let config = Config {ssl_context: Some(ssl_context), ..Default::default()};

    let mut conn = NatsConn::new(config).unwrap();
    let sub = conn.subscribe_channel("topic1", None).unwrap();
    conn.publish("topic1", None, b"data").unwrap();
    conn.flush().unwrap();

    thread::sleep(Duration::new(1, 0));
    assert_eq!(b"data", sub.receiver.try_recv().unwrap().data.as_slice());
    conn.unsubscribe(&sub).unwrap();

    gnatsd.kill().unwrap();
    thread::sleep(*WAIT);
}
<|endoftext|>


<commit_before>extern crate cards;

use cards::deck::{Deck};

#[test]
fn draw_a_card() {
    let mut deck = Deck::new();
    let _card = deck.draw();
    //println!("The card is: {}", _card);
}

#[test]
fn draw_a_few_card() {
    let mut deck = Deck::new();
    let _cards = deck.draw_n(5);
    //println!("The cards are: {:?}", _cards.iter().map(|x| x.short_string()).collect::<Vec<String>>());

    //use std::str::{StrVector};
    //http://doc.rust-lang.org/0.12.0/std/str/trait.StrVector.html
    //println!("The cards are: {}", cards.iter().map(|x| x.short_string()).collect::<StrVector>().connect(" "));
}

#[test]
fn draw_all_cards() {
    let mut deck = Deck::new();
    deck.draw_n(52);
}

#[test]
#[should_panic]
fn draw_too_many_cards() {
    let mut deck = Deck::new();
    deck.draw_n(53);
}

#[test]
fn reset_deck() {
    let mut deck = Deck::new();
    deck.draw_n(52);
    deck.reset();
    deck.draw_n(52);
}
<commit_msg>Fixed tests, is borrowing really a good thing here?<commit_after>extern crate cards;

use cards::deck::{Deck};

#[test]
fn draw_a_card() {
    let mut deck = Deck::new();
    let _card = deck.draw();
    //println!("The card is: {}", _card);
}

#[test]
fn draw_a_few_card() {
    let mut deck = Deck::new();
    let _cards = deck.draw_n(&5);
    //println!("The cards are: {:?}", _cards.iter().map(|x| x.short_string()).collect::<Vec<String>>());

    //use std::str::{StrVector};
    //http://doc.rust-lang.org/0.12.0/std/str/trait.StrVector.html
    //println!("The cards are: {}", cards.iter().map(|x| x.short_string()).collect::<StrVector>().connect(" "));
}

#[test]
fn draw_all_cards() {
    let mut deck = Deck::new();
    deck.draw_n(&52);
}

#[test]
#[should_panic]
fn draw_too_many_cards() {
    let mut deck = Deck::new();
    deck.draw_n(&53);
}

#[test]
fn reset_deck() {
    let mut deck = Deck::new();
    deck.draw_n(&52);
    deck.reset();
    deck.draw_n(&52);
}
<|endoftext|>


<commit_before>// mrusty. mruby bindings for Rust
// Copyright (C) 2016  Dragoș Tiselice
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.

#[macro_use]
extern crate mrusty;

use mrusty::*;

mod api;

use api::Scalar;
use api::Vector;

#[test]
fn test_api_init() {
    let mruby = MRuby::new();

    Scalar::require(mruby.clone());
    Vector::require(mruby.clone());

    let scalar = mruby.run("Scalar.new 2.3").unwrap();
    let vector = mruby.run("Vector.new 1.0, 2.0, 3.0").unwrap();

    assert_eq!(*scalar.to_obj::<Scalar>().unwrap(), Scalar::new(2.3));
    assert_eq!(*vector.to_obj::<Vector>().unwrap(), Vector::new(1.0, 2.0, 3.0));
}

#[test]
fn test_api_getters() {
    let mruby = MRuby::new();

    Scalar::require(mruby.clone());
    Vector::require(mruby.clone());

    let scalar = mruby.run("Scalar.new 2.3").unwrap();
    let vector = mruby.run("Vector.new 1.0, 2.0, 3.0").unwrap();

    assert_eq!(scalar.to_obj::<Scalar>().unwrap().value, 2.3);

    assert_eq!(vector.to_obj::<Vector>().unwrap().x, 1.0);
    assert_eq!(vector.to_obj::<Vector>().unwrap().y, 2.0);
    assert_eq!(vector.to_obj::<Vector>().unwrap().z, 3.0);
}

#[test]
fn test_api_mul() {
    let mruby = MRuby::new();

    Scalar::require(mruby.clone());
    Vector::require(mruby.clone());

    let vector = mruby.run("Scalar.new(2.0) * Vector.new(1.0, 2.0, 3.0)").unwrap();

    assert_eq!(*vector.to_obj::<Vector>().unwrap(), Vector::new(2.0, 4.0, 6.0));
}

#[test]
fn test_api_array() {
    let mruby = MRuby::new();

    Scalar::require(mruby.clone());
    Vector::require(mruby.clone());

    let result = mruby.run("Vector.new(1.0, 2.0, 3.0).to_a.last").unwrap();

    assert_eq!(result.to_f64().unwrap(), 3.0);
}

#[test]
fn test_api_vec() {
    let mruby = MRuby::new();

    Scalar::require(mruby.clone());
    Vector::require(mruby.clone());

    let result = mruby.run("Vector.from_a [1.0, 2.0, 3.0]").unwrap();

    assert_eq!(*result.to_obj::<Vector>().unwrap(), Vector::new(1.0, 2.0, 3.0));
}

#[test]
fn test_api_require() {
    let mruby = MRuby::new();

    mruby.def_file::<Vector>("math");

    let result = mruby.run("
        require 'math'

        Vector.new(1.0, 2.0, 3.0)
    ").unwrap();

    assert_eq!(*result.to_obj::<Vector>().unwrap(), Vector::new(1.0, 2.0, 3.0));
}

#[test]
fn test_api_dup() {
    static mut DROPPED: bool = false;

    struct Cont {
        value: i32
    }

    impl Drop for Cont {
        fn drop(&mut self) {
            unsafe {
                DROPPED = true;
            }
        }
    }

    unsafe {
        {
            let mruby = MRuby::new();

            mruby.def_class::<Cont>("Container");

            {
                let orig = Cont { value: 3 };

                {
                    let obj = mruby.obj(orig);
                    let dup = obj.call("dup", vec![]).unwrap().to_obj::<Cont>().unwrap();

                    assert_eq!(dup.value, 3);

                    assert_eq!(DROPPED, false);
                }

                assert_eq!(DROPPED, false);
            }

            assert_eq!(DROPPED, false);
        }

        assert_eq!(DROPPED, true);
    }
}
<commit_msg>Added require file test.<commit_after>// mrusty. mruby bindings for Rust
// Copyright (C) 2016  Dragoș Tiselice
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.

#[macro_use]
extern crate mrusty;

use mrusty::*;

mod api;

use api::Scalar;
use api::Vector;

#[test]
fn test_api_init() {
    let mruby = MRuby::new();

    Scalar::require(mruby.clone());
    Vector::require(mruby.clone());

    let scalar = mruby.run("Scalar.new 2.3").unwrap();
    let vector = mruby.run("Vector.new 1.0, 2.0, 3.0").unwrap();

    assert_eq!(*scalar.to_obj::<Scalar>().unwrap(), Scalar::new(2.3));
    assert_eq!(*vector.to_obj::<Vector>().unwrap(), Vector::new(1.0, 2.0, 3.0));
}

#[test]
fn test_api_getters() {
    let mruby = MRuby::new();

    Scalar::require(mruby.clone());
    Vector::require(mruby.clone());

    let scalar = mruby.run("Scalar.new 2.3").unwrap();
    let vector = mruby.run("Vector.new 1.0, 2.0, 3.0").unwrap();

    assert_eq!(scalar.to_obj::<Scalar>().unwrap().value, 2.3);

    assert_eq!(vector.to_obj::<Vector>().unwrap().x, 1.0);
    assert_eq!(vector.to_obj::<Vector>().unwrap().y, 2.0);
    assert_eq!(vector.to_obj::<Vector>().unwrap().z, 3.0);
}

#[test]
fn test_api_mul() {
    let mruby = MRuby::new();

    Scalar::require(mruby.clone());
    Vector::require(mruby.clone());

    let vector = mruby.run("Scalar.new(2.0) * Vector.new(1.0, 2.0, 3.0)").unwrap();

    assert_eq!(*vector.to_obj::<Vector>().unwrap(), Vector::new(2.0, 4.0, 6.0));
}

#[test]
fn test_api_array() {
    let mruby = MRuby::new();

    Scalar::require(mruby.clone());
    Vector::require(mruby.clone());

    let result = mruby.run("Vector.new(1.0, 2.0, 3.0).to_a.last").unwrap();

    assert_eq!(result.to_f64().unwrap(), 3.0);
}

#[test]
fn test_api_vec() {
    let mruby = MRuby::new();

    Scalar::require(mruby.clone());
    Vector::require(mruby.clone());

    let result = mruby.run("Vector.from_a [1.0, 2.0, 3.0]").unwrap();

    assert_eq!(*result.to_obj::<Vector>().unwrap(), Vector::new(1.0, 2.0, 3.0));
}

#[test]
fn test_api_require() {
    let mruby = MRuby::new();

    mruby.def_file::<Vector>("math");

    let result = mruby.run("
        require 'math'

        Vector.new(1.0, 2.0, 3.0)
    ").unwrap();

    assert_eq!(*result.to_obj::<Vector>().unwrap(), Vector::new(1.0, 2.0, 3.0));
}

#[test]
fn test_api_require_file() {
    use std::fs::File;
    use std::io::Write;

    let mruby = MRuby::new();

    let mut file = File::create("/tmp/some.rb").unwrap();

    file.write_all(b"class Some; end").unwrap();

    mruby.run("
        require '/tmp/some'

        Some.new
    ").unwrap();
}

#[test]
fn test_api_dup() {
    static mut DROPPED: bool = false;

    struct Cont {
        value: i32
    }

    impl Drop for Cont {
        fn drop(&mut self) {
            unsafe {
                DROPPED = true;
            }
        }
    }

    unsafe {
        {
            let mruby = MRuby::new();

            mruby.def_class::<Cont>("Container");

            {
                let orig = Cont { value: 3 };

                {
                    let obj = mruby.obj(orig);
                    let dup = obj.call("dup", vec![]).unwrap().to_obj::<Cont>().unwrap();

                    assert_eq!(dup.value, 3);

                    assert_eq!(DROPPED, false);
                }

                assert_eq!(DROPPED, false);
            }

            assert_eq!(DROPPED, false);
        }

        assert_eq!(DROPPED, true);
    }
}
<|endoftext|>


<commit_before>extern crate nom_sqlp;

use std::fs::File;
use std::io::Read;

fn parse_queryset(queries: Vec<String>) {
    let mut parsed_ok = Vec::new();
    let mut parsed_err = 0;
    for query in queries.iter() {
        match nom_sqlp::parser::parse_query(&query) {
            Ok(_) => {
                parsed_ok.push(query);
            }
            Err(_) => parsed_err += 1,
        }
    }

    println!("Parsing failed: {} queries", parsed_err);
    println!("Parsed successfully: {} queries", parsed_ok.len());
    println!("\nSuccessfully parsed queries:");
    for q in parsed_ok.iter() {
        println!("{:?}", q);
    }
}

#[test]
fn hotcrp_queries() {
    let mut f = File::open("tests/hotcrp-queries.txt").unwrap();
    let mut s = String::new();

    // Load HotCRP queries
    f.read_to_string(&mut s).unwrap();
    let lines: Vec<String> = s.lines()
        .filter(|l| !l.starts_with("#"))
        .map(|l| {
            if !(l.ends_with("\n") || l.ends_with(";")) {
                String::from(l) + "\n"
            } else {
                String::from(l)
            }
        })
        .collect();
    println!("Loaded {} HotCRP queries", lines.len());

    // Try parsing them all
    parse_queryset(lines);
}

#[test]
fn hyrise_test_queries() {
    let mut f = File::open("tests/hyrise-test-queries.txt").unwrap();
    let mut s = String::new();

    // Load HyRise queries
    f.read_to_string(&mut s).unwrap();
    let lines: Vec<String> = s.lines()
        .filter(|l| !l.starts_with("#"))
        .map(|l| {
            if !(l.ends_with("\n") || l.ends_with(";")) {
                String::from(l) + "\n"
            } else {
                String::from(l)
            }
        })
        .collect();
    println!("Loaded {} Hyrise queries", lines.len());

    // Try parsing them all
    parse_queryset(lines);
}
<commit_msg>Fix crate name in tests.<commit_after>extern crate nom_sql;

use std::fs::File;
use std::io::Read;

fn parse_queryset(queries: Vec<String>) {
    let mut parsed_ok = Vec::new();
    let mut parsed_err = 0;
    for query in queries.iter() {
        match nom_sqlp::parser::parse_query(&query) {
            Ok(_) => {
                parsed_ok.push(query);
            }
            Err(_) => parsed_err += 1,
        }
    }

    println!("Parsing failed: {} queries", parsed_err);
    println!("Parsed successfully: {} queries", parsed_ok.len());
    println!("\nSuccessfully parsed queries:");
    for q in parsed_ok.iter() {
        println!("{:?}", q);
    }
}

#[test]
fn hotcrp_queries() {
    let mut f = File::open("tests/hotcrp-queries.txt").unwrap();
    let mut s = String::new();

    // Load HotCRP queries
    f.read_to_string(&mut s).unwrap();
    let lines: Vec<String> = s.lines()
        .filter(|l| !l.starts_with("#"))
        .map(|l| {
            if !(l.ends_with("\n") || l.ends_with(";")) {
                String::from(l) + "\n"
            } else {
                String::from(l)
            }
        })
        .collect();
    println!("Loaded {} HotCRP queries", lines.len());

    // Try parsing them all
    parse_queryset(lines);
}

#[test]
fn hyrise_test_queries() {
    let mut f = File::open("tests/hyrise-test-queries.txt").unwrap();
    let mut s = String::new();

    // Load HyRise queries
    f.read_to_string(&mut s).unwrap();
    let lines: Vec<String> = s.lines()
        .filter(|l| !l.starts_with("#"))
        .map(|l| {
            if !(l.ends_with("\n") || l.ends_with(";")) {
                String::from(l) + "\n"
            } else {
                String::from(l)
            }
        })
        .collect();
    println!("Loaded {} Hyrise queries", lines.len());

    // Try parsing them all
    parse_queryset(lines);
}
<|endoftext|>


<commit_before>extern crate alacritty;
extern crate serde_json;

/// ref tests
mod reference {
    use std::fs::File;
    use std::io::Read;
    use std::path::Path;

    use serde_json as json;

    use alacritty::Grid;
    use alacritty::Term;
    use alacritty::term::Cell;
    use alacritty::term::SizeInfo;
    use alacritty::ansi;

    macro_rules! ref_file {
        ($ref_name:ident, $file:expr) => {
            concat!(
                env!("CARGO_MANIFEST_DIR"),
                "/tests/ref/", stringify!($ref_name), "/", $file
            )
        }
    }

    fn read_u8<P>(path: P) -> Vec<u8>
        where P: AsRef<Path>
    {
        let mut res = Vec::new();
        File::open(path.as_ref()).unwrap()
            .read_to_end(&mut res).unwrap();

        res
    }

    fn read_string<P>(path: P) -> String
        where P: AsRef<Path>
    {
        let mut res = String::new();
        File::open(path.as_ref()).unwrap()
            .read_to_string(&mut res).unwrap();

        res
    }

    macro_rules! ref_test {
        ($name:ident) => {
            #[test]
            fn $name() {
                let recording = read_u8(ref_file!($name, "alacritty.recording"));
                let serialized_size = read_string(ref_file!($name, "size.json"));
                let serialized_grid = read_string(ref_file!($name, "grid.json"));

                let size: SizeInfo = json::from_str(&serialized_size[..]).unwrap();
                let grid: Grid<Cell> = json::from_str(&serialized_grid[..]).unwrap();

                let mut terminal = Term::new(size);
                let mut parser = ansi::Processor::new();

                for byte in recording {
                    parser.advance(&mut terminal, byte);
                }

                assert_eq!(grid, *terminal.grid());
            }
        };

        ($( $name:ident ),*) => {
            $(
                ref_test! { $name }
            )*
        };
    }

    // Ref tests!
    ref_test! {
        ll,
        vim_simple_edit,
        tmux_htop,
        tmux_git_log
    }
}
<commit_msg>Remove unnecessary slicing<commit_after>extern crate alacritty;
extern crate serde_json;

/// ref tests
mod reference {
    use std::fs::File;
    use std::io::Read;
    use std::path::Path;

    use serde_json as json;

    use alacritty::Grid;
    use alacritty::Term;
    use alacritty::term::Cell;
    use alacritty::term::SizeInfo;
    use alacritty::ansi;

    macro_rules! ref_file {
        ($ref_name:ident, $file:expr) => {
            concat!(
                env!("CARGO_MANIFEST_DIR"),
                "/tests/ref/", stringify!($ref_name), "/", $file
            )
        }
    }

    fn read_u8<P>(path: P) -> Vec<u8>
        where P: AsRef<Path>
    {
        let mut res = Vec::new();
        File::open(path.as_ref()).unwrap()
            .read_to_end(&mut res).unwrap();

        res
    }

    fn read_string<P>(path: P) -> String
        where P: AsRef<Path>
    {
        let mut res = String::new();
        File::open(path.as_ref()).unwrap()
            .read_to_string(&mut res).unwrap();

        res
    }

    macro_rules! ref_test {
        ($name:ident) => {
            #[test]
            fn $name() {
                let recording = read_u8(ref_file!($name, "alacritty.recording"));
                let serialized_size = read_string(ref_file!($name, "size.json"));
                let serialized_grid = read_string(ref_file!($name, "grid.json"));

                let size: SizeInfo = json::from_str(&serialized_size).unwrap();
                let grid: Grid<Cell> = json::from_str(&serialized_grid).unwrap();

                let mut terminal = Term::new(size);
                let mut parser = ansi::Processor::new();

                for byte in recording {
                    parser.advance(&mut terminal, byte);
                }

                assert_eq!(grid, *terminal.grid());
            }
        };

        ($( $name:ident ),*) => {
            $(
                ref_test! { $name }
            )*
        };
    }

    // Ref tests!
    ref_test! {
        ll,
        vim_simple_edit,
        tmux_htop,
        tmux_git_log
    }
}
<|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/. */

#![crate_id = "github.com/mozilla/servo"]
#![comment = "The Servo Parallel Browser Project"]
#![license = "MPL"]

#![feature(globs, macro_rules, phase, thread_local)]

#![feature(phase)]
#[phase(syntax, link)]
extern crate log;

extern crate alert;
extern crate azure;
extern crate geom;
extern crate gfx;
#[cfg(not(target_os="android"))]
extern crate glfw;
#[cfg(target_os="android")]
extern crate glut;
extern crate js;
extern crate layers;
extern crate opengles;
extern crate png;
extern crate rustuv;
extern crate script;
#[phase(syntax)]
extern crate servo_macros = "macros";
extern crate servo_net = "net";
extern crate servo_msg = "msg";
extern crate servo_util = "util";
extern crate style;
extern crate sharegl;
extern crate stb_image;

extern crate collections;
extern crate green;
extern crate libc;
extern crate native;
extern crate serialize;
extern crate sync;
extern crate time;
extern crate url;

#[cfg(target_os="macos")]
extern crate core_graphics;
#[cfg(target_os="macos")]
extern crate core_text;

#[cfg(not(test))]
use compositing::{CompositorChan, CompositorTask};
#[cfg(not(test))]
use constellation::Constellation;
#[cfg(not(test))]
use servo_msg::constellation_msg::{ConstellationChan, InitLoadUrlMsg};

#[cfg(not(test))]
use servo_net::image_cache_task::{ImageCacheTask, SyncImageCacheTask};
#[cfg(not(test))]
use servo_net::resource_task::ResourceTask;
#[cfg(not(test))]
use servo_util::time::Profiler;

#[cfg(not(test))]
use servo_util::opts;
#[cfg(not(test))]
use servo_util::url::parse_url;

#[cfg(not(test), not(target_os="android"))]
use std::os;
#[cfg(not(test), target_os="android")]
use std::str;
#[cfg(not(test))]
use std::task::TaskOpts;
#[cfg(not(test))]
use url::Url;

#[path="compositing/compositor_task.rs"]
pub mod compositing;

pub mod css {
    mod node_util;

    pub mod select;
    pub mod matching;
    pub mod node_style;
}

pub mod constellation;
pub mod pipeline;

pub mod layout {
    pub mod block;
    pub mod box_;
    pub mod construct;
    pub mod context;
    pub mod floats;
    pub mod flow;
    pub mod flow_list;
    pub mod layout_task;
    pub mod inline;
    pub mod model;
    pub mod parallel;
    pub mod table_wrapper;
    pub mod table;
    pub mod table_caption;
    pub mod table_colgroup;
    pub mod table_rowgroup;
    pub mod table_row;
    pub mod table_cell;
    pub mod text;
    pub mod util;
    pub mod incremental;
    pub mod wrapper;
    pub mod extra;
}

pub mod windowing;

#[path="platform/mod.rs"]
pub mod platform;

#[cfg(not(test), target_os="linux")]
#[cfg(not(test), target_os="macos")]
#[start]
fn start(argc: int, argv: **u8) -> int {
    native::start(argc, argv, proc() {
        opts::from_cmdline_args(os::args()).map(run);
    })
}

#[cfg(not(test), target_os="android")]
#[no_mangle]
pub extern "C" fn android_start(argc: int, argv: **u8) -> int {
    native::start(argc, argv, proc() {
        let mut args: Vec<~str> = vec!();
        for i in range(0u, argc as uint) {
            unsafe {
                args.push(str::raw::from_c_str(*argv.offset(i as int) as *i8));
            }
        }

        let mut opts = opts::from_cmdline_args(args.as_slice());
        match opts {
            Some(mut o) => {
                // Always use CPU rendering on android.
                o.cpu_painting = true;
                run(o);
            },
            None => {}
        }
    })
}

#[cfg(not(test))]
fn run(opts: opts::Opts) {
    let mut pool_config = green::PoolConfig::new();
    pool_config.event_loop_factory = rustuv::event_loop;
    let mut pool = green::SchedPool::new(pool_config);

    let (compositor_port, compositor_chan) = CompositorChan::new();
    let profiler_chan = Profiler::create(opts.profiler_period);

    let opts_clone = opts.clone();
    let profiler_chan_clone = profiler_chan.clone();

    let (result_chan, result_port) = channel();
    pool.spawn(TaskOpts::new(), proc() {
        let opts = &opts_clone;
        // Create a Servo instance.
        let resource_task = ResourceTask();
        // If we are emitting an output file, then we need to block on
        // image load or we risk emitting an output file missing the
        // image.
        let image_cache_task = if opts.output_file.is_some() {
                SyncImageCacheTask(resource_task.clone())
            } else {
                ImageCacheTask(resource_task.clone())
            };
        let constellation_chan = Constellation::start(compositor_chan,
                                                      opts,
                                                      resource_task,
                                                      image_cache_task,
                                                      profiler_chan_clone);

        // Send the URL command to the constellation.
        for filename in opts.urls.iter() {
            let url = if filename.starts_with("data:") {
                // As a hack for easier command-line testing,
                // assume that data URLs are not URL-encoded.
                Url::new("data".to_owned(), None, "".to_owned(), None,
                    filename.slice_from(5).to_owned(), vec!(), None)
            } else {
                parse_url(*filename, None)
            };

            let ConstellationChan(ref chan) = constellation_chan;
            chan.send(InitLoadUrlMsg(url));
        }

        // Send the constallation Chan as the result
        result_chan.send(constellation_chan);
    });

    let constellation_chan = result_port.recv();

    debug!("preparing to enter main loop");
    CompositorTask::create(opts,
                           compositor_port,
                           constellation_chan,
                           profiler_chan);

    pool.shutdown();
}

<commit_msg>auto merge of #2371 : zwarich/servo/start-dead-code, r=metajack<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/. */

#![crate_id = "github.com/mozilla/servo"]
#![comment = "The Servo Parallel Browser Project"]
#![license = "MPL"]

#![feature(globs, macro_rules, phase, thread_local)]

#![feature(phase)]
#[phase(syntax, link)]
extern crate log;

extern crate alert;
extern crate azure;
extern crate geom;
extern crate gfx;
#[cfg(not(target_os="android"))]
extern crate glfw;
#[cfg(target_os="android")]
extern crate glut;
extern crate js;
extern crate layers;
extern crate opengles;
extern crate png;
extern crate rustuv;
extern crate script;
#[phase(syntax)]
extern crate servo_macros = "macros";
extern crate servo_net = "net";
extern crate servo_msg = "msg";
extern crate servo_util = "util";
extern crate style;
extern crate sharegl;
extern crate stb_image;

extern crate collections;
extern crate green;
extern crate libc;
extern crate native;
extern crate serialize;
extern crate sync;
extern crate time;
extern crate url;

#[cfg(target_os="macos")]
extern crate core_graphics;
#[cfg(target_os="macos")]
extern crate core_text;

#[cfg(not(test))]
use compositing::{CompositorChan, CompositorTask};
#[cfg(not(test))]
use constellation::Constellation;
#[cfg(not(test))]
use servo_msg::constellation_msg::{ConstellationChan, InitLoadUrlMsg};

#[cfg(not(test))]
use servo_net::image_cache_task::{ImageCacheTask, SyncImageCacheTask};
#[cfg(not(test))]
use servo_net::resource_task::ResourceTask;
#[cfg(not(test))]
use servo_util::time::Profiler;

#[cfg(not(test))]
use servo_util::opts;
#[cfg(not(test))]
use servo_util::url::parse_url;

#[cfg(not(test), not(target_os="android"))]
use std::os;
#[cfg(not(test), target_os="android")]
use std::str;
#[cfg(not(test))]
use std::task::TaskOpts;
#[cfg(not(test))]
use url::Url;

#[path="compositing/compositor_task.rs"]
pub mod compositing;

pub mod css {
    mod node_util;

    pub mod select;
    pub mod matching;
    pub mod node_style;
}

pub mod constellation;
pub mod pipeline;

pub mod layout {
    pub mod block;
    pub mod box_;
    pub mod construct;
    pub mod context;
    pub mod floats;
    pub mod flow;
    pub mod flow_list;
    pub mod layout_task;
    pub mod inline;
    pub mod model;
    pub mod parallel;
    pub mod table_wrapper;
    pub mod table;
    pub mod table_caption;
    pub mod table_colgroup;
    pub mod table_rowgroup;
    pub mod table_row;
    pub mod table_cell;
    pub mod text;
    pub mod util;
    pub mod incremental;
    pub mod wrapper;
    pub mod extra;
}

pub mod windowing;

#[path="platform/mod.rs"]
pub mod platform;

#[cfg(not(test), target_os="linux")]
#[cfg(not(test), target_os="macos")]
#[start]
#[allow(dead_code)]
fn start(argc: int, argv: **u8) -> int {
    native::start(argc, argv, proc() {
        opts::from_cmdline_args(os::args()).map(run);
    })
}

#[cfg(not(test), target_os="android")]
#[no_mangle]
#[allow(dead_code)]
pub extern "C" fn android_start(argc: int, argv: **u8) -> int {
    native::start(argc, argv, proc() {
        let mut args: Vec<~str> = vec!();
        for i in range(0u, argc as uint) {
            unsafe {
                args.push(str::raw::from_c_str(*argv.offset(i as int) as *i8));
            }
        }

        let mut opts = opts::from_cmdline_args(args.as_slice());
        match opts {
            Some(mut o) => {
                // Always use CPU rendering on android.
                o.cpu_painting = true;
                run(o);
            },
            None => {}
        }
    })
}

#[cfg(not(test))]
fn run(opts: opts::Opts) {
    let mut pool_config = green::PoolConfig::new();
    pool_config.event_loop_factory = rustuv::event_loop;
    let mut pool = green::SchedPool::new(pool_config);

    let (compositor_port, compositor_chan) = CompositorChan::new();
    let profiler_chan = Profiler::create(opts.profiler_period);

    let opts_clone = opts.clone();
    let profiler_chan_clone = profiler_chan.clone();

    let (result_chan, result_port) = channel();
    pool.spawn(TaskOpts::new(), proc() {
        let opts = &opts_clone;
        // Create a Servo instance.
        let resource_task = ResourceTask();
        // If we are emitting an output file, then we need to block on
        // image load or we risk emitting an output file missing the
        // image.
        let image_cache_task = if opts.output_file.is_some() {
                SyncImageCacheTask(resource_task.clone())
            } else {
                ImageCacheTask(resource_task.clone())
            };
        let constellation_chan = Constellation::start(compositor_chan,
                                                      opts,
                                                      resource_task,
                                                      image_cache_task,
                                                      profiler_chan_clone);

        // Send the URL command to the constellation.
        for filename in opts.urls.iter() {
            let url = if filename.starts_with("data:") {
                // As a hack for easier command-line testing,
                // assume that data URLs are not URL-encoded.
                Url::new("data".to_owned(), None, "".to_owned(), None,
                    filename.slice_from(5).to_owned(), vec!(), None)
            } else {
                parse_url(*filename, None)
            };

            let ConstellationChan(ref chan) = constellation_chan;
            chan.send(InitLoadUrlMsg(url));
        }

        // Send the constallation Chan as the result
        result_chan.send(constellation_chan);
    });

    let constellation_chan = result_port.recv();

    debug!("preparing to enter main loop");
    CompositorTask::create(opts,
                           compositor_port,
                           constellation_chan,
                           profiler_chan);

    pool.shutdown();
}

<|endoftext|>


<commit_before>use proc_macro2::{Span, TokenStream};
use syn;
use syn::{Data, DeriveInput, Field, Fields, Ident};

use util::*;

#[derive(Default, Debug)]
struct ObjAttrs {
    name: Option<String>,
    description: Option<String>,
    context: Option<Ident>,
    scalar: Option<Ident>,
}

impl ObjAttrs {
    fn from_input(input: &DeriveInput) -> ObjAttrs {
        let mut res = ObjAttrs::default();

        // Check doc comments for description.
        res.description = get_doc_comment(&input.attrs);

        // Check attributes for name and description.
        if let Some(items) = get_graphql_attr(&input.attrs) {
            for item in items {
                if let Some(AttributeValue::String(val)) =
                    keyed_item_value(&item, "name", AttributeValidation::String)
                {
                    if is_valid_name(&*val) {
                        res.name = Some(val);
                        continue;
                    } else {
                        panic!(
                            "Names must match /^[_a-zA-Z][_a-zA-Z0-9]*$/ but \"{}\" does not",
                            &*val
                        );
                    }
                }
                if let Some(AttributeValue::String(val)) =
                    keyed_item_value(&item, "description", AttributeValidation::String)
                {
                    res.description = Some(val);
                    continue;
                }
                if let Some(AttributeValue::String(scalar)) =
                    keyed_item_value(&item, "scalar", AttributeValidation::String)
                {
                    res.scalar = Some(Ident::new(&scalar as &str, Span::call_site()));
                    continue;
                }
                if let Some(AttributeValue::String(ctx)) = keyed_item_value(&item, "Context", AttributeValidation::String) {
                    res.context = Some(Ident::new(&ctx as &str, Span::call_site()));
                    continue;
                }
                panic!(format!(
                    "Unknown struct attribute for #[derive(GraphQLObject)]: {:?}",
                    item
                ));
            }
        }
        res
    }
}

#[derive(Default)]
struct ObjFieldAttrs {
    name: Option<String>,
    description: Option<String>,
    deprecation: Option<DeprecationAttr>,
    skip: bool,
}

impl ObjFieldAttrs {
    fn from_input(variant: &Field) -> ObjFieldAttrs {
        let mut res = ObjFieldAttrs::default();

        // Check doc comments for description.
        res.description = get_doc_comment(&variant.attrs);

        // Check builtin deprecated attribute for deprecation.
        res.deprecation = get_deprecated(&variant.attrs);

        // Check attributes.
        if let Some(items) = get_graphql_attr(&variant.attrs) {
            for item in items {
                if let Some(AttributeValue::String(val)) =
                    keyed_item_value(&item, "name", AttributeValidation::String)
                {
                    if is_valid_name(&*val) {
                        res.name = Some(val);
                        continue;
                    } else {
                        panic!(
                            "Names must match /^[_a-zA-Z][_a-zA-Z0-9]*$/ but \"{}\" does not",
                            &*val
                        );
                    }
                }
                if let Some(AttributeValue::String(val)) =
                    keyed_item_value(&item, "description", AttributeValidation::String)
                {
                    res.description = Some(val);
                    continue;
                }
                if let Some(AttributeValue::String(val)) =
                    keyed_item_value(&item, "deprecation", AttributeValidation::String)
                {
                    res.deprecation = Some(DeprecationAttr { reason: Some(val) });
                    continue;
                }
                match keyed_item_value(&item, "deprecated", AttributeValidation::String) {
                    Some(AttributeValue::String(val)) => {
                        res.deprecation = Some(DeprecationAttr { reason: Some(val) });
                        continue;
                    }
                    Some(AttributeValue::Bare) => {
                        res.deprecation = Some(DeprecationAttr { reason: None });
                        continue;
                    }
                    None => {}
                }
                if let Some(_) = keyed_item_value(&item, "skip", AttributeValidation::Bare) {
                    res.skip = true;
                    continue;
                }
                panic!(format!(
                    "Unknown field attribute for #[derive(GraphQLObject)]: {:?}",
                    item
                ));
            }
        }
        res
    }
}

pub fn impl_object(ast: &syn::DeriveInput) -> TokenStream {
    let fields = match ast.data {
        Data::Struct(ref data) => match data.fields {
            Fields::Named(ref fields) => fields.named.iter().collect::<Vec<_>>(),
            _ => {
                panic!("#[derive(GraphQLObject)] may only be used on regular structs with fields");
            }
        },
        _ => {
            panic!("#[derive(GraphlQLObject)] may only be applied to structs, not to enums");
        }
    };

    // Parse attributes.
    let ident = &ast.ident;
    let generics = &ast.generics;
    let ident_name = ident.to_string();
    let attrs = ObjAttrs::from_input(ast);
    let name = attrs.name.unwrap_or(ast.ident.to_string());
    let build_description = match attrs.description {
        Some(s) => quote! { builder.description(#s)  },
        None => quote! { builder },
    };

    let mut meta_fields = TokenStream::new();
    let mut resolvers = TokenStream::new();

    for field in fields {
        let field_ty = &field.ty;
        let field_attrs = ObjFieldAttrs::from_input(field);
        let field_ident = field.ident.as_ref().unwrap();

        // Check if we should skip this field.
        if field_attrs.skip {
            continue;
        }

        // Build value.
        let name = match field_attrs.name {
            Some(ref name) => {
                // Custom name specified.
                name.to_string()
            }
            None => {
                // Note: auto camel casing when no custom name specified.
                ::util::to_camel_case(&field_ident.to_string())
            }
        };
        let build_description = match field_attrs.description {
            Some(s) => quote! { field.description(#s)  },
            None => quote! { field },
        };

        let build_deprecation = match field_attrs.deprecation {
            Some(DeprecationAttr { reason: Some(s) }) => quote! { field.deprecated(Some(#s)) },
            Some(DeprecationAttr { reason: None }) => quote! { field.deprecated(None) },
            None => quote! { field },
        };

        meta_fields.extend(quote! {
            {
                let field = registry.field::<#field_ty>(#name, &());
                let field = #build_description;
                let field = #build_deprecation;
                field
            },
        });

        // Build from_input clause.

        resolvers.extend(quote! {
            #name => executor.resolve_with_ctx(&(), &self.#field_ident),
        });
    }

    let (_, ty_generics, _) = generics.split_for_impl();

    let mut generics = generics.clone();

    if attrs.scalar.is_none() {
        generics.params.push(parse_quote!(__S));
        {
            let where_clause = generics.where_clause.get_or_insert(parse_quote!(where));
            where_clause
                .predicates
                .push(parse_quote!(__S: juniper::ScalarValue));
            where_clause
                .predicates
                .push(parse_quote!(for<'__b> &'__b __S: juniper::ScalarRefValue<'__b>));
        }
    }

    let scalar = attrs
        .scalar
        .unwrap_or_else(|| Ident::new("__S", Span::call_site()));

    let ctx = attrs.context.map(|ident| quote!( #ident )).unwrap_or(quote!( () ));

    let (impl_generics, _, where_clause) = generics.split_for_impl();

    let body = quote! {
        impl#impl_generics juniper::GraphQLType<#scalar> for #ident #ty_generics
            #where_clause
        {
            type Context = #ctx;
            type TypeInfo = ();

            fn name(_: &()) -> Option<&str> {
                Some(#name)
            }

            fn concrete_type_name(&self, _: &Self::Context, _: &()) -> String {
                #name.to_string()
            }

            fn meta<'r>(
                _: &(),
                registry: &mut juniper::Registry<'r, #scalar>
            ) -> juniper::meta::MetaType<'r, #scalar>
                where #scalar: 'r
            {
                let fields = &[
                    #(#meta_fields)*
                ];
                let builder = registry.build_object_type::<#ident>(&(), fields);
                let builder = #build_description;
                builder.into_meta()
            }

            fn resolve_field(
                &self,
                _: &(),
                field_name: &str,
                _: &juniper::Arguments<#scalar>,
                executor: &juniper::Executor<Self::Context, #scalar>
            ) -> juniper::ExecutionResult<#scalar>
            {

                match field_name {
                    #(#resolvers)*
                    _ => panic!("Field {} not found on type {}", field_name, #ident_name),
                }

            }
        }
    };
    body
}
<commit_msg>Formatting...<commit_after>use proc_macro2::{Span, TokenStream};
use syn;
use syn::{Data, DeriveInput, Field, Fields, Ident};

use util::*;

#[derive(Default, Debug)]
struct ObjAttrs {
    name: Option<String>,
    description: Option<String>,
    context: Option<Ident>,
    scalar: Option<Ident>,
}

impl ObjAttrs {
    fn from_input(input: &DeriveInput) -> ObjAttrs {
        let mut res = ObjAttrs::default();

        // Check doc comments for description.
        res.description = get_doc_comment(&input.attrs);

        // Check attributes for name and description.
        if let Some(items) = get_graphql_attr(&input.attrs) {
            for item in items {
                if let Some(AttributeValue::String(val)) =
                    keyed_item_value(&item, "name", AttributeValidation::String)
                {
                    if is_valid_name(&*val) {
                        res.name = Some(val);
                        continue;
                    } else {
                        panic!(
                            "Names must match /^[_a-zA-Z][_a-zA-Z0-9]*$/ but \"{}\" does not",
                            &*val
                        );
                    }
                }
                if let Some(AttributeValue::String(val)) =
                    keyed_item_value(&item, "description", AttributeValidation::String)
                {
                    res.description = Some(val);
                    continue;
                }
                if let Some(AttributeValue::String(scalar)) =
                    keyed_item_value(&item, "scalar", AttributeValidation::String)
                {
                    res.scalar = Some(Ident::new(&scalar as &str, Span::call_site()));
                    continue;
                }
                if let Some(AttributeValue::String(ctx)) =
                    keyed_item_value(&item, "Context", AttributeValidation::String)
                {
                    res.context = Some(Ident::new(&ctx as &str, Span::call_site()));
                    continue;
                }
                panic!(format!(
                    "Unknown struct attribute for #[derive(GraphQLObject)]: {:?}",
                    item
                ));
            }
        }
        res
    }
}

#[derive(Default)]
struct ObjFieldAttrs {
    name: Option<String>,
    description: Option<String>,
    deprecation: Option<DeprecationAttr>,
    skip: bool,
}

impl ObjFieldAttrs {
    fn from_input(variant: &Field) -> ObjFieldAttrs {
        let mut res = ObjFieldAttrs::default();

        // Check doc comments for description.
        res.description = get_doc_comment(&variant.attrs);

        // Check builtin deprecated attribute for deprecation.
        res.deprecation = get_deprecated(&variant.attrs);

        // Check attributes.
        if let Some(items) = get_graphql_attr(&variant.attrs) {
            for item in items {
                if let Some(AttributeValue::String(val)) =
                    keyed_item_value(&item, "name", AttributeValidation::String)
                {
                    if is_valid_name(&*val) {
                        res.name = Some(val);
                        continue;
                    } else {
                        panic!(
                            "Names must match /^[_a-zA-Z][_a-zA-Z0-9]*$/ but \"{}\" does not",
                            &*val
                        );
                    }
                }
                if let Some(AttributeValue::String(val)) =
                    keyed_item_value(&item, "description", AttributeValidation::String)
                {
                    res.description = Some(val);
                    continue;
                }
                if let Some(AttributeValue::String(val)) =
                    keyed_item_value(&item, "deprecation", AttributeValidation::String)
                {
                    res.deprecation = Some(DeprecationAttr { reason: Some(val) });
                    continue;
                }
                match keyed_item_value(&item, "deprecated", AttributeValidation::String) {
                    Some(AttributeValue::String(val)) => {
                        res.deprecation = Some(DeprecationAttr { reason: Some(val) });
                        continue;
                    }
                    Some(AttributeValue::Bare) => {
                        res.deprecation = Some(DeprecationAttr { reason: None });
                        continue;
                    }
                    None => {}
                }
                if let Some(_) = keyed_item_value(&item, "skip", AttributeValidation::Bare) {
                    res.skip = true;
                    continue;
                }
                panic!(format!(
                    "Unknown field attribute for #[derive(GraphQLObject)]: {:?}",
                    item
                ));
            }
        }
        res
    }
}

pub fn impl_object(ast: &syn::DeriveInput) -> TokenStream {
    let fields = match ast.data {
        Data::Struct(ref data) => match data.fields {
            Fields::Named(ref fields) => fields.named.iter().collect::<Vec<_>>(),
            _ => {
                panic!("#[derive(GraphQLObject)] may only be used on regular structs with fields");
            }
        },
        _ => {
            panic!("#[derive(GraphlQLObject)] may only be applied to structs, not to enums");
        }
    };

    // Parse attributes.
    let ident = &ast.ident;
    let generics = &ast.generics;
    let ident_name = ident.to_string();
    let attrs = ObjAttrs::from_input(ast);
    let name = attrs.name.unwrap_or(ast.ident.to_string());
    let build_description = match attrs.description {
        Some(s) => quote! { builder.description(#s)  },
        None => quote! { builder },
    };

    let mut meta_fields = TokenStream::new();
    let mut resolvers = TokenStream::new();

    for field in fields {
        let field_ty = &field.ty;
        let field_attrs = ObjFieldAttrs::from_input(field);
        let field_ident = field.ident.as_ref().unwrap();

        // Check if we should skip this field.
        if field_attrs.skip {
            continue;
        }

        // Build value.
        let name = match field_attrs.name {
            Some(ref name) => {
                // Custom name specified.
                name.to_string()
            }
            None => {
                // Note: auto camel casing when no custom name specified.
                ::util::to_camel_case(&field_ident.to_string())
            }
        };
        let build_description = match field_attrs.description {
            Some(s) => quote! { field.description(#s)  },
            None => quote! { field },
        };

        let build_deprecation = match field_attrs.deprecation {
            Some(DeprecationAttr { reason: Some(s) }) => quote! { field.deprecated(Some(#s)) },
            Some(DeprecationAttr { reason: None }) => quote! { field.deprecated(None) },
            None => quote! { field },
        };

        meta_fields.extend(quote! {
            {
                let field = registry.field::<#field_ty>(#name, &());
                let field = #build_description;
                let field = #build_deprecation;
                field
            },
        });

        // Build from_input clause.

        resolvers.extend(quote! {
            #name => executor.resolve_with_ctx(&(), &self.#field_ident),
        });
    }

    let (_, ty_generics, _) = generics.split_for_impl();

    let mut generics = generics.clone();

    if attrs.scalar.is_none() {
        generics.params.push(parse_quote!(__S));
        {
            let where_clause = generics.where_clause.get_or_insert(parse_quote!(where));
            where_clause
                .predicates
                .push(parse_quote!(__S: juniper::ScalarValue));
            where_clause
                .predicates
                .push(parse_quote!(for<'__b> &'__b __S: juniper::ScalarRefValue<'__b>));
        }
    }

    let scalar = attrs
        .scalar
        .unwrap_or_else(|| Ident::new("__S", Span::call_site()));

    let ctx = attrs
        .context
        .map(|ident| quote!( #ident ))
        .unwrap_or(quote!(()));

    let (impl_generics, _, where_clause) = generics.split_for_impl();

    let body = quote! {
        impl#impl_generics juniper::GraphQLType<#scalar> for #ident #ty_generics
            #where_clause
        {
            type Context = #ctx;
            type TypeInfo = ();

            fn name(_: &()) -> Option<&str> {
                Some(#name)
            }

            fn concrete_type_name(&self, _: &Self::Context, _: &()) -> String {
                #name.to_string()
            }

            fn meta<'r>(
                _: &(),
                registry: &mut juniper::Registry<'r, #scalar>
            ) -> juniper::meta::MetaType<'r, #scalar>
                where #scalar: 'r
            {
                let fields = &[
                    #(#meta_fields)*
                ];
                let builder = registry.build_object_type::<#ident>(&(), fields);
                let builder = #build_description;
                builder.into_meta()
            }

            fn resolve_field(
                &self,
                _: &(),
                field_name: &str,
                _: &juniper::Arguments<#scalar>,
                executor: &juniper::Executor<Self::Context, #scalar>
            ) -> juniper::ExecutionResult<#scalar>
            {

                match field_name {
                    #(#resolvers)*
                    _ => panic!("Field {} not found on type {}", field_name, #ident_name),
                }

            }
        }
    };
    body
}
<|endoftext|>


<commit_before>use super::error::{ErrorKind, Result};
use super::header;
use super::util::tcpconnection;
use super::{ServicePair, ServiceResult};
use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt};
use rosmsg::{encode_str, RosMsg};
use std;
use std::collections::HashMap;
use std::io;
use std::net::TcpListener;
use std::sync::Arc;
use std::thread;

pub struct Service {
    pub api: String,
    pub msg_type: String,
    pub service: String,
    _raii: tcpconnection::Raii,
}

impl Service {
    pub fn new<T, F>(
        hostname: &str,
        port: u16,
        service: &str,
        node_name: &str,
        handler: F,
    ) -> Result<Service>
    where
        T: ServicePair,
        F: Fn(T::Request) -> ServiceResult<T::Response> + Send + Sync + 'static,
    {
        let listener = TcpListener::bind((hostname, port))?;
        let socket_address = listener.local_addr()?;
        let api = format!("rosrpc://{}:{}", hostname, socket_address.port());
        let (raii, listener) = tcpconnection::iterate(listener, format!("service '{}'", service));
        Ok(Service::wrap_stream::<T, _, _, _>(
            service, node_name, handler, raii, listener, &api,
        ))
    }

    fn wrap_stream<T, U, V, F>(
        service: &str,
        node_name: &str,
        handler: F,
        raii: tcpconnection::Raii,
        listener: V,
        api: &str,
    ) -> Service
    where
        T: ServicePair,
        U: std::io::Read + std::io::Write + Send + 'static,
        V: Iterator<Item = U> + Send + 'static,
        F: Fn(T::Request) -> ServiceResult<T::Response> + Send + Sync + 'static,
    {
        let service_name = String::from(service);
        let node_name = String::from(node_name);
        thread::spawn(move || {
            listen_for_clients::<T, _, _, _>(&service_name, &node_name, handler, listener)
        });
        Service {
            api: String::from(api),
            msg_type: T::msg_type(),
            service: String::from(service),
            _raii: raii,
        }
    }
}

fn listen_for_clients<T, U, V, F>(service: &str, node_name: &str, handler: F, connections: V)
where
    T: ServicePair,
    U: std::io::Read + std::io::Write + Send + 'static,
    V: Iterator<Item = U>,
    F: Fn(T::Request) -> ServiceResult<T::Response> + Send + Sync + 'static,
{
    let handler = Arc::new(handler);
    for mut stream in connections {
        // Service request starts by exchanging connection headers
        if let Err(err) = exchange_headers::<T, _>(&mut stream, service, node_name) {
            // Connection can be closed when a client checks for a service.
            if !err.is_closed_connection() {
                error!(
                    "Failed to exchange headers for service '{}': {}",
                    service, err
                );
            }
            continue;
        }

        // Spawn a thread for handling requests
        spawn_request_handler::<T, U, F>(stream, Arc::clone(&handler));
    }
}

fn exchange_headers<T, U>(stream: &mut U, service: &str, node_name: &str) -> Result<()>
where
    T: ServicePair,
    U: std::io::Write + std::io::Read,
{
    read_request::<T, U>(stream, service)?;
    write_response::<T, U>(stream, node_name)
}

fn read_request<T: ServicePair, U: std::io::Read>(stream: &mut U, service: &str) -> Result<()> {
    let fields = header::decode(stream)?;
    header::match_field(&fields, "service", service)?;
    if fields.get("callerid").is_none() {
        bail!(ErrorKind::HeaderMissingField("callerid".into()));
    }
    if header::match_field(&fields, "probe", "1").is_ok() {
        return Ok(());
    }
    header::match_field(&fields, "md5sum", &T::md5sum())
}

fn write_response<T, U>(stream: &mut U, node_name: &str) -> Result<()>
where
    T: ServicePair,
    U: std::io::Write,
{
    let mut fields = HashMap::<String, String>::new();
    fields.insert(String::from("callerid"), String::from(node_name));
    fields.insert(String::from("md5sum"), T::md5sum());
    fields.insert(String::from("type"), T::msg_type());
    header::encode(stream, &fields)?;
    Ok(())
}

fn spawn_request_handler<T, U, F>(stream: U, handler: Arc<F>)
where
    T: ServicePair,
    U: std::io::Read + std::io::Write + Send + 'static,
    F: Fn(T::Request) -> ServiceResult<T::Response> + Send + Sync + 'static,
{
    thread::spawn(move || {
        if let Err(err) = handle_request_loop::<T, U, F>(stream, &handler) {
            if !err.is_closed_connection() {
                let info = err
                    .iter()
                    .map(|v| format!("{}", v))
                    .collect::<Vec<_>>()
                    .join("\nCaused by:");
                error!("{}", info);
            }
        }
    });
}

fn handle_request_loop<T, U, F>(mut stream: U, handler: &F) -> Result<()>
where
    T: ServicePair,
    U: std::io::Read + std::io::Write,
    F: Fn(T::Request) -> ServiceResult<T::Response>,
{
    // Receive request from client
    // TODO: validate message length
    let _length = stream.read_u32::<LittleEndian>();
    // Break out of loop in case of failure to read request
    while let Ok(req) = RosMsg::decode(&mut stream) {
        // Call function that handles request and returns response
        match handler(req) {
            Ok(res) => {
                // Send True flag and response in case of success
                stream.write_u8(1)?;
                let mut writer = io::Cursor::new(Vec::with_capacity(128));
                // skip the first 4 bytes that will contain the message length
                writer.set_position(4);

                res.encode(&mut writer)?;

                // write the message length to the start of the header
                let message_length = (writer.position() - 4) as u32;
                writer.set_position(0);
                message_length.encode(&mut writer)?;

                stream.write_all(&writer.into_inner())?;
            }
            Err(message) => {
                // Send False flag and error message string in case of failure
                stream.write_u8(0)?;
                RosMsg::encode(&message, &mut stream)?;
            }
        };
    }

    // Upon failure to read request, send client failure message
    // This can be caused by actual issues or by the client stopping the connection
    stream.write_u8(0)?;
    encode_str("Failed to parse passed arguments", &mut stream)?;
    Ok(())
}
<commit_msg>Fix service behavior when the service is an empty input - Change decoding of service request from a while loop to explicit if statement - Do not call service handler on tcp probe connection<commit_after>use super::error::{ErrorKind, Result};
use super::header;
use super::util::tcpconnection;
use super::{ServicePair, ServiceResult};
use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt};
use rosmsg::{encode_str, RosMsg};
use std;
use std::collections::HashMap;
use std::io;
use std::net::TcpListener;
use std::sync::Arc;
use std::thread;

pub struct Service {
    pub api: String,
    pub msg_type: String,
    pub service: String,
    _raii: tcpconnection::Raii,
}

impl Service {
    pub fn new<T, F>(
        hostname: &str,
        port: u16,
        service: &str,
        node_name: &str,
        handler: F,
    ) -> Result<Service>
    where
        T: ServicePair,
        F: Fn(T::Request) -> ServiceResult<T::Response> + Send + Sync + 'static,
    {
        let listener = TcpListener::bind((hostname, port))?;
        let socket_address = listener.local_addr()?;
        let api = format!("rosrpc://{}:{}", hostname, socket_address.port());
        let (raii, listener) = tcpconnection::iterate(listener, format!("service '{}'", service));
        Ok(Service::wrap_stream::<T, _, _, _>(
            service, node_name, handler, raii, listener, &api,
        ))
    }

    fn wrap_stream<T, U, V, F>(
        service: &str,
        node_name: &str,
        handler: F,
        raii: tcpconnection::Raii,
        listener: V,
        api: &str,
    ) -> Service
    where
        T: ServicePair,
        U: std::io::Read + std::io::Write + Send + 'static,
        V: Iterator<Item = U> + Send + 'static,
        F: Fn(T::Request) -> ServiceResult<T::Response> + Send + Sync + 'static,
    {
        let service_name = String::from(service);
        let node_name = String::from(node_name);
        thread::spawn(move || {
            listen_for_clients::<T, _, _, _>(&service_name, &node_name, handler, listener)
        });
        Service {
            api: String::from(api),
            msg_type: T::msg_type(),
            service: String::from(service),
            _raii: raii,
        }
    }
}

enum RequestType {
    Probe,
    Action,
}

fn listen_for_clients<T, U, V, F>(service: &str, node_name: &str, handler: F, connections: V)
where
    T: ServicePair,
    U: std::io::Read + std::io::Write + Send + 'static,
    V: Iterator<Item = U>,
    F: Fn(T::Request) -> ServiceResult<T::Response> + Send + Sync + 'static,
{
    let handler = Arc::new(handler);
    for mut stream in connections {
        // Service request starts by exchanging connection headers
        match exchange_headers::<T, _>(&mut stream, service, node_name) {
            Err(err) => {
                // Connection can be closed when a client checks for a service.
                if !err.is_closed_connection() {
                    error!(
                        "Failed to exchange headers for service '{}': {}",
                        service, err
                    );
                }
                continue;
            }

            // Spawn a thread for handling requests
            Ok(RequestType::Action) => {
                spawn_request_handler::<T, U, F>(stream, Arc::clone(&handler))
            }
            Ok(RequestType::Probe) => (),
        }
    }
}

fn exchange_headers<T, U>(stream: &mut U, service: &str, node_name: &str) -> Result<RequestType>
where
    T: ServicePair,
    U: std::io::Write + std::io::Read,
{
    let req_type = read_request::<T, U>(stream, service)?;
    write_response::<T, U>(stream, node_name)?;
    Ok(req_type)
}

fn read_request<T: ServicePair, U: std::io::Read>(
    stream: &mut U,
    service: &str,
) -> Result<RequestType> {
    let fields = header::decode(stream)?;
    header::match_field(&fields, "service", service)?;
    if fields.get("callerid").is_none() {
        bail!(ErrorKind::HeaderMissingField("callerid".into()));
    }
    if header::match_field(&fields, "probe", "1").is_ok() {
        return Ok(RequestType::Probe);
    }
    header::match_field(&fields, "md5sum", &T::md5sum())?;
    Ok(RequestType::Action)
}

fn write_response<T, U>(stream: &mut U, node_name: &str) -> Result<()>
where
    T: ServicePair,
    U: std::io::Write,
{
    let mut fields = HashMap::<String, String>::new();
    fields.insert(String::from("callerid"), String::from(node_name));
    fields.insert(String::from("md5sum"), T::md5sum());
    fields.insert(String::from("type"), T::msg_type());
    header::encode(stream, &fields)?;
    Ok(())
}

fn spawn_request_handler<T, U, F>(stream: U, handler: Arc<F>)
where
    T: ServicePair,
    U: std::io::Read + std::io::Write + Send + 'static,
    F: Fn(T::Request) -> ServiceResult<T::Response> + Send + Sync + 'static,
{
    thread::spawn(move || {
        if let Err(err) = handle_request_loop::<T, U, F>(stream, &handler) {
            if !err.is_closed_connection() {
                let info = err
                    .iter()
                    .map(|v| format!("{}", v))
                    .collect::<Vec<_>>()
                    .join("\nCaused by:");
                error!("{}", info);
            }
        }
    });
}

fn handle_request_loop<T, U, F>(mut stream: U, handler: &F) -> Result<()>
where
    T: ServicePair,
    U: std::io::Read + std::io::Write,
    F: Fn(T::Request) -> ServiceResult<T::Response>,
{
    // Receive request from client
    // TODO: validate message length
    let _length = stream.read_u32::<LittleEndian>();
    // Break out of loop in case of failure to read request
    if let Ok(req) = RosMsg::decode(&mut stream) {
        // Call function that handles request and returns response
        match handler(req) {
            Ok(res) => {
                // Send True flag and response in case of success
                stream.write_u8(1)?;
                let mut writer = io::Cursor::new(Vec::with_capacity(128));
                // skip the first 4 bytes that will contain the message length
                writer.set_position(4);

                res.encode(&mut writer)?;

                // write the message length to the start of the header
                let message_length = (writer.position() - 4) as u32;
                writer.set_position(0);
                message_length.encode(&mut writer)?;

                stream.write_all(&writer.into_inner())?;
            }
            Err(message) => {
                // Send False flag and error message string in case of failure
                stream.write_u8(0)?;
                RosMsg::encode(&message, &mut stream)?;
            }
        };
    }

    // Upon failure to read request, send client failure message
    // This can be caused by actual issues or by the client stopping the connection
    stream.write_u8(0)?;
    encode_str("Failed to parse passed arguments", &mut stream)?;
    Ok(())
}
<|endoftext|>


<commit_before>//! Endpoint for searching and discovery functionality

use diesel_full_text_search::*;

use controllers::helpers::Paginate;
use controllers::prelude::*;
use views::EncodableCrate;
use models::{Crate, CrateBadge, OwnerKind, Version};
use schema::*;

use models::krate::{canon_crate_name, ALL_COLUMNS};

/// Handles the `GET /crates` route.
/// Returns a list of crates. Called in a variety of scenarios in the
/// front end, including:
/// - Alphabetical listing of crates
/// - List of crates under a specific owner
/// - Listing a user's followed crates
///
/// Notes:
/// The different use cases this function covers is handled through passing
/// in parameters in the GET request.
///
/// We would like to stop adding functionality in here. It was built like
/// this to keep the number of database queries low, though given Rust's
/// low performance overhead, this is a soft goal to have, and can afford
/// more database transactions if it aids understandability.
///
/// All of the edge cases for this function are not currently covered
/// in testing, and if they fail, it is difficult to determine what
/// caused the break. In the future, we should look at splitting this
/// function out to cover the different use cases, and create unit tests
/// for them.
pub fn search(req: &mut Request) -> CargoResult<Response> {
    use diesel::sql_types::Bool;

    let conn = req.db_conn()?;
    let (offset, limit) = req.pagination(10, 100)?;
    let params = req.query();
    let sort = params
        .get("sort")
        .map(|s| &**s)
        .unwrap_or("recent-downloads");

    let mut query = crates::table
        .left_join(recent_crate_downloads::table)
        .select((
            ALL_COLUMNS,
            false.into_sql::<Bool>(),
            recent_crate_downloads::downloads.nullable(),
        ))
        .into_boxed();

    if let Some(q_string) = params.get("q") {
        let sort = params.get("sort").map(|s| &**s).unwrap_or("relevance");
        let q = plainto_tsquery(q_string);
        query = query.filter(
            q.matches(crates::textsearchable_index_col)
                .or(Crate::with_name(q_string)),
        );

        query = query.select((
            ALL_COLUMNS,
            Crate::with_name(q_string),
            recent_crate_downloads::downloads.nullable(),
        ));
        query = query.order(Crate::with_name(q_string).desc());

        if sort == "relevance" {
            let rank = ts_rank_cd(crates::textsearchable_index_col, q);
            query = query.then_order_by(rank.desc())
        }
    }

    if let Some(cat) = params.get("category") {
        query = query.filter(
            crates::id.eq_any(
                crates_categories::table
                    .select(crates_categories::crate_id)
                    .inner_join(categories::table)
                    .filter(
                        categories::slug
                            .eq(cat)
                            .or(categories::slug.like(format!("{}::%", cat))),
                    ),
            ),
        );
    }

    if let Some(kw) = params.get("keyword") {
        query = query.filter(
            crates::id.eq_any(
                crates_keywords::table
                    .select(crates_keywords::crate_id)
                    .inner_join(keywords::table)
                    .filter(::lower(keywords::keyword).eq(::lower(kw))),
            ),
        );
    } else if let Some(letter) = params.get("letter") {
        let pattern = format!(
            "{}%",
            letter
                .chars()
                .next()
                .unwrap()
                .to_lowercase()
                .collect::<String>()
        );
        query = query.filter(canon_crate_name(crates::name).like(pattern));
    } else if let Some(user_id) = params.get("user_id").and_then(|s| s.parse::<i32>().ok()) {
        query = query.filter(
            crates::id.eq_any(
                crate_owners::table
                    .select(crate_owners::crate_id)
                    .filter(crate_owners::owner_id.eq(user_id))
                    .filter(crate_owners::deleted.eq(false))
                    .filter(crate_owners::owner_kind.eq(OwnerKind::User as i32)),
            ),
        );
    } else if let Some(team_id) = params.get("team_id").and_then(|s| s.parse::<i32>().ok()) {
        query = query.filter(
            crates::id.eq_any(
                crate_owners::table
                    .select(crate_owners::crate_id)
                    .filter(crate_owners::owner_id.eq(team_id))
                    .filter(crate_owners::deleted.eq(false))
                    .filter(crate_owners::owner_kind.eq(OwnerKind::Team as i32)),
            ),
        );
    } else if params.get("following").is_some() {
        query = query.filter(
            crates::id.eq_any(
                follows::table
                    .select(follows::crate_id)
                    .filter(follows::user_id.eq(req.user()?.id)),
            ),
        );
    }

    if sort == "downloads" {
        query = query.then_order_by(crates::downloads.desc())
    } else if sort == "recent-downloads" {
        query = query.then_order_by(recent_crate_downloads::downloads.desc().nulls_last())
    } else {
        query = query.then_order_by(crates::name.asc())
    }

    // The database query returns a tuple within a tuple, with the root
    // tuple containing 3 items.
    let data = query
        .paginate(limit, offset)
        .load::<((Crate, bool, Option<i64>), i64)>(&*conn)?;
    let total = data.first().map(|&(_, t)| t).unwrap_or(0);
    let perfect_matches = data.iter().map(|&((_, b, _), _)| b).collect::<Vec<_>>();
    let recent_downloads = data.iter()
        .map(|&((_, _, s), _)| s.unwrap_or(0))
        .collect::<Vec<_>>();
    let crates = data.into_iter().map(|((c, _, _), _)| c).collect::<Vec<_>>();

    let versions = Version::belonging_to(&crates)
        .load::<Version>(&*conn)?
        .grouped_by(&crates)
        .into_iter()
        .map(|versions| Version::max(versions.into_iter().map(|v| v.num)));

    let badges = CrateBadge::belonging_to(&crates)
        .select((badges::crate_id, badges::all_columns))
        .load::<CrateBadge>(&conn)?
        .grouped_by(&crates)
        .into_iter()
        .map(|badges| badges.into_iter().map(|cb| cb.badge).collect());

    let crates = versions
        .zip(crates)
        .zip(perfect_matches)
        .zip(recent_downloads)
        .zip(badges)
        .map(
            |((((max_version, krate), perfect_match), recent_downloads), badges)| {
                Ok(krate.minimal_encodable(
                    &max_version,
                    Some(badges),
                    perfect_match,
                    Some(recent_downloads),
                ))
            },
        )
        .collect::<Result<_, ::diesel::result::Error>>()?;

    #[derive(Serialize)]
    struct R {
        crates: Vec<EncodableCrate>,
        meta: Meta,
    }
    #[derive(Serialize)]
    struct Meta {
        total: i64,
    }

    Ok(req.json(&R {
        crates,
        meta: Meta { total },
    }))
}
<commit_msg>Remove uneccessary result wrapping<commit_after>//! Endpoint for searching and discovery functionality

use diesel_full_text_search::*;

use controllers::helpers::Paginate;
use controllers::prelude::*;
use views::EncodableCrate;
use models::{Crate, CrateBadge, OwnerKind, Version};
use schema::*;

use models::krate::{canon_crate_name, ALL_COLUMNS};

/// Handles the `GET /crates` route.
/// Returns a list of crates. Called in a variety of scenarios in the
/// front end, including:
/// - Alphabetical listing of crates
/// - List of crates under a specific owner
/// - Listing a user's followed crates
///
/// Notes:
/// The different use cases this function covers is handled through passing
/// in parameters in the GET request.
///
/// We would like to stop adding functionality in here. It was built like
/// this to keep the number of database queries low, though given Rust's
/// low performance overhead, this is a soft goal to have, and can afford
/// more database transactions if it aids understandability.
///
/// All of the edge cases for this function are not currently covered
/// in testing, and if they fail, it is difficult to determine what
/// caused the break. In the future, we should look at splitting this
/// function out to cover the different use cases, and create unit tests
/// for them.
pub fn search(req: &mut Request) -> CargoResult<Response> {
    use diesel::sql_types::Bool;

    let conn = req.db_conn()?;
    let (offset, limit) = req.pagination(10, 100)?;
    let params = req.query();
    let sort = params
        .get("sort")
        .map(|s| &**s)
        .unwrap_or("recent-downloads");

    let mut query = crates::table
        .left_join(recent_crate_downloads::table)
        .select((
            ALL_COLUMNS,
            false.into_sql::<Bool>(),
            recent_crate_downloads::downloads.nullable(),
        ))
        .into_boxed();

    if let Some(q_string) = params.get("q") {
        let sort = params.get("sort").map(|s| &**s).unwrap_or("relevance");
        let q = plainto_tsquery(q_string);
        query = query.filter(
            q.matches(crates::textsearchable_index_col)
                .or(Crate::with_name(q_string)),
        );

        query = query.select((
            ALL_COLUMNS,
            Crate::with_name(q_string),
            recent_crate_downloads::downloads.nullable(),
        ));
        query = query.order(Crate::with_name(q_string).desc());

        if sort == "relevance" {
            let rank = ts_rank_cd(crates::textsearchable_index_col, q);
            query = query.then_order_by(rank.desc())
        }
    }

    if let Some(cat) = params.get("category") {
        query = query.filter(
            crates::id.eq_any(
                crates_categories::table
                    .select(crates_categories::crate_id)
                    .inner_join(categories::table)
                    .filter(
                        categories::slug
                            .eq(cat)
                            .or(categories::slug.like(format!("{}::%", cat))),
                    ),
            ),
        );
    }

    if let Some(kw) = params.get("keyword") {
        query = query.filter(
            crates::id.eq_any(
                crates_keywords::table
                    .select(crates_keywords::crate_id)
                    .inner_join(keywords::table)
                    .filter(::lower(keywords::keyword).eq(::lower(kw))),
            ),
        );
    } else if let Some(letter) = params.get("letter") {
        let pattern = format!(
            "{}%",
            letter
                .chars()
                .next()
                .unwrap()
                .to_lowercase()
                .collect::<String>()
        );
        query = query.filter(canon_crate_name(crates::name).like(pattern));
    } else if let Some(user_id) = params.get("user_id").and_then(|s| s.parse::<i32>().ok()) {
        query = query.filter(
            crates::id.eq_any(
                crate_owners::table
                    .select(crate_owners::crate_id)
                    .filter(crate_owners::owner_id.eq(user_id))
                    .filter(crate_owners::deleted.eq(false))
                    .filter(crate_owners::owner_kind.eq(OwnerKind::User as i32)),
            ),
        );
    } else if let Some(team_id) = params.get("team_id").and_then(|s| s.parse::<i32>().ok()) {
        query = query.filter(
            crates::id.eq_any(
                crate_owners::table
                    .select(crate_owners::crate_id)
                    .filter(crate_owners::owner_id.eq(team_id))
                    .filter(crate_owners::deleted.eq(false))
                    .filter(crate_owners::owner_kind.eq(OwnerKind::Team as i32)),
            ),
        );
    } else if params.get("following").is_some() {
        query = query.filter(
            crates::id.eq_any(
                follows::table
                    .select(follows::crate_id)
                    .filter(follows::user_id.eq(req.user()?.id)),
            ),
        );
    }

    if sort == "downloads" {
        query = query.then_order_by(crates::downloads.desc())
    } else if sort == "recent-downloads" {
        query = query.then_order_by(recent_crate_downloads::downloads.desc().nulls_last())
    } else {
        query = query.then_order_by(crates::name.asc())
    }

    // The database query returns a tuple within a tuple, with the root
    // tuple containing 3 items.
    let data = query
        .paginate(limit, offset)
        .load::<((Crate, bool, Option<i64>), i64)>(&*conn)?;
    let total = data.first().map(|&(_, t)| t).unwrap_or(0);
    let perfect_matches = data.iter().map(|&((_, b, _), _)| b).collect::<Vec<_>>();
    let recent_downloads = data.iter()
        .map(|&((_, _, s), _)| s.unwrap_or(0))
        .collect::<Vec<_>>();
    let crates = data.into_iter().map(|((c, _, _), _)| c).collect::<Vec<_>>();

    let versions = Version::belonging_to(&crates)
        .load::<Version>(&*conn)?
        .grouped_by(&crates)
        .into_iter()
        .map(|versions| Version::max(versions.into_iter().map(|v| v.num)));

    let badges = CrateBadge::belonging_to(&crates)
        .select((badges::crate_id, badges::all_columns))
        .load::<CrateBadge>(&conn)?
        .grouped_by(&crates)
        .into_iter()
        .map(|badges| badges.into_iter().map(|cb| cb.badge).collect());

    let crates = versions
        .zip(crates)
        .zip(perfect_matches)
        .zip(recent_downloads)
        .zip(badges)
        .map(
            |((((max_version, krate), perfect_match), recent_downloads), badges)| {
                krate.minimal_encodable(
                    &max_version,
                    Some(badges),
                    perfect_match,
                    Some(recent_downloads),
                )
            },
        )
        .collect();

    #[derive(Serialize)]
    struct R {
        crates: Vec<EncodableCrate>,
        meta: Meta,
    }
    #[derive(Serialize)]
    struct Meta {
        total: i64,
    }

    Ok(req.json(&R {
        crates,
        meta: Meta { total },
    }))
}
<|endoftext|>