<commit_before>use serde::{de::Deserializer, ser::Serializer};
use serde::{Deserialize, Serialize};
use std::{fmt, ops::Deref, result::Result as StdResult, sync::Arc};

const CUTOFF: usize = std::mem::size_of::<&[u8]>() - 1;
type Inner = [u8; CUTOFF];

/// A buffer that may either be inline or remote and protected
/// by an Arc
#[derive(Clone)]
pub struct IVec(IVecInner);

#[derive(Clone)]
enum IVecInner {
    Inline(u8, Inner),
    Remote(Arc<[u8]>),
}

impl Serialize for IVec {
    fn serialize<S: Serializer>(
        &self,
        serializer: S,
    ) -> StdResult<S::Ok, S::Error> {
        serde_bytes::serialize(self.as_ref(), serializer)
    }
}

impl<'de> Deserialize<'de> for IVec {
    fn deserialize<D: Deserializer<'de>>(
        deserializer: D,
    ) -> StdResult<Self, D::Error> {
        let bytes: StdResult<Box<[u8]>, D::Error> =
            serde_bytes::deserialize(deserializer);
        bytes.map(IVec::from)
    }
}

const fn is_inline_candidate(length: usize) -> bool {
    length <= CUTOFF
}

impl IVec {
    fn inline(slice: &[u8]) -> IVec {
        assert!(is_inline_candidate(slice.len()));

        let mut data = Inner::default();

        unsafe {
            std::ptr::copy_nonoverlapping(
                slice.as_ptr(),
                data.as_mut_ptr(),
                slice.len(),
            );
        }

        IVec(IVecInner::Inline(slice.len() as u8, data))
    }

    fn remote(arc: Arc<[u8]>) -> IVec {
        IVec(IVecInner::Remote(arc))
    }

    #[inline]
    pub(crate) fn size_in_bytes(&self) -> u64 {
        if let IVecInner::Inline(..) = self.0 {
            std::mem::size_of::<IVec>() as u64
        } else {
            let sz = std::mem::size_of::<IVec>() as u64;
            sz.saturating_add(self.len() as u64)
        }
    }
}

impl From<Box<[u8]>> for IVec {
    fn from(b: Box<[u8]>) -> IVec {
        if is_inline_candidate(b.len()) {
            IVec::inline(&b)
        } else {
            // rely on the Arc From specialization
            // for Box<T>, which may improve
            // over time
            IVec::remote(Arc::from(b))
        }
    }
}

impl From<&[u8]> for IVec {
    fn from(slice: &[u8]) -> IVec {
        if is_inline_candidate(slice.len()) {
            IVec::inline(slice)
        } else {
            IVec::remote(Arc::from(slice))
        }
    }
}

impl From<Arc<[u8]>> for IVec {
    fn from(arc: Arc<[u8]>) -> IVec {
        IVec::remote(arc)
    }
}

impl From<&str> for IVec {
    fn from(s: &str) -> IVec {
        IVec::from(s.as_bytes())
    }
}

impl From<&IVec> for IVec {
    fn from(v: &IVec) -> IVec {
        v.clone()
    }
}

impl From<Vec<u8>> for IVec {
    fn from(v: Vec<u8>) -> IVec {
        if is_inline_candidate(v.len()) {
            IVec::inline(&v)
        } else {
            // rely on the Arc From specialization
            // for Vec<T>, which may improve
            // over time
            IVec::remote(Arc::from(v))
        }
    }
}

impl Deref for IVec {
    type Target = [u8];

    #[inline]
    fn deref(&self) -> &[u8] {
        self.as_ref()
    }
}

impl AsRef<[u8]> for IVec {
    #[inline]
    fn as_ref(&self) -> &[u8] {
        match &self.0 {
            IVecInner::Inline(sz, buf) => {
                unsafe { buf.get_unchecked(..*sz as usize) }
            },
            IVecInner::Remote(buf) => buf,
        }
    }
}

impl Ord for IVec {
    fn cmp(&self, other: &IVec) -> std::cmp::Ordering {
        self.as_ref().cmp(other.as_ref())
    }
}

impl PartialOrd for IVec {
    fn partial_cmp(&self, other: &IVec) -> Option<std::cmp::Ordering> {
        Some(self.cmp(other))
    }
}

impl<T: AsRef<[u8]>> PartialEq<T> for IVec {
    fn eq(&self, other: &T) -> bool {
        self.as_ref() == other.as_ref()
    }
}

impl PartialEq<[u8]> for IVec {
    fn eq(&self, other: &[u8]) -> bool {
        self.as_ref() == other
    }
}

impl Eq for IVec { }

impl fmt::Debug for IVec {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        self.as_ref().fmt(f)
    }
}

#[test]
fn ivec_usage() {
    let iv1 = IVec::from(vec![1, 2, 3]);
    assert_eq!(iv1, vec![1, 2, 3]);
    let iv2 = IVec::from(&[4; 128][..]);
    assert_eq!(iv2, vec![4; 128]);
}
<commit_msg>Implement Into Arc<[u8]> on IVec<commit_after>use serde::{de::Deserializer, ser::Serializer};
use serde::{Deserialize, Serialize};
use std::{fmt, ops::Deref, result::Result as StdResult, sync::Arc};

const CUTOFF: usize = std::mem::size_of::<&[u8]>() - 1;
type Inner = [u8; CUTOFF];

/// A buffer that may either be inline or remote and protected
/// by an Arc
#[derive(Clone)]
pub struct IVec(IVecInner);

#[derive(Clone)]
enum IVecInner {
    Inline(u8, Inner),
    Remote(Arc<[u8]>),
}

impl Serialize for IVec {
    fn serialize<S: Serializer>(
        &self,
        serializer: S,
    ) -> StdResult<S::Ok, S::Error> {
        serde_bytes::serialize(self.as_ref(), serializer)
    }
}

impl<'de> Deserialize<'de> for IVec {
    fn deserialize<D: Deserializer<'de>>(
        deserializer: D,
    ) -> StdResult<Self, D::Error> {
        let bytes: StdResult<Box<[u8]>, D::Error> =
            serde_bytes::deserialize(deserializer);
        bytes.map(IVec::from)
    }
}

const fn is_inline_candidate(length: usize) -> bool {
    length <= CUTOFF
}

impl IVec {
    fn inline(slice: &[u8]) -> IVec {
        assert!(is_inline_candidate(slice.len()));

        let mut data = Inner::default();

        unsafe {
            std::ptr::copy_nonoverlapping(
                slice.as_ptr(),
                data.as_mut_ptr(),
                slice.len(),
            );
        }

        IVec(IVecInner::Inline(slice.len() as u8, data))
    }

    fn remote(arc: Arc<[u8]>) -> IVec {
        IVec(IVecInner::Remote(arc))
    }

    #[inline]
    pub(crate) fn size_in_bytes(&self) -> u64 {
        if let IVecInner::Inline(..) = self.0 {
            std::mem::size_of::<IVec>() as u64
        } else {
            let sz = std::mem::size_of::<IVec>() as u64;
            sz.saturating_add(self.len() as u64)
        }
    }
}

impl From<Box<[u8]>> for IVec {
    fn from(b: Box<[u8]>) -> IVec {
        if is_inline_candidate(b.len()) {
            IVec::inline(&b)
        } else {
            // rely on the Arc From specialization
            // for Box<T>, which may improve
            // over time
            IVec::remote(Arc::from(b))
        }
    }
}

impl From<&[u8]> for IVec {
    fn from(slice: &[u8]) -> IVec {
        if is_inline_candidate(slice.len()) {
            IVec::inline(slice)
        } else {
            IVec::remote(Arc::from(slice))
        }
    }
}

impl From<Arc<[u8]>> for IVec {
    fn from(arc: Arc<[u8]>) -> IVec {
        IVec::remote(arc)
    }
}

impl From<&str> for IVec {
    fn from(s: &str) -> IVec {
        IVec::from(s.as_bytes())
    }
}

impl From<&IVec> for IVec {
    fn from(v: &IVec) -> IVec {
        v.clone()
    }
}

impl From<Vec<u8>> for IVec {
    fn from(v: Vec<u8>) -> IVec {
        if is_inline_candidate(v.len()) {
            IVec::inline(&v)
        } else {
            // rely on the Arc From specialization
            // for Vec<T>, which may improve
            // over time
            IVec::remote(Arc::from(v))
        }
    }
}

impl Into<Arc<[u8]>> for IVec {
    fn into(self) -> Arc<[u8]> {
        match self.0 {
            IVecInner::Inline(..) => Arc::from(self.as_ref()),
            IVecInner::Remote(arc) => arc,
        }
    }
}

impl Deref for IVec {
    type Target = [u8];

    #[inline]
    fn deref(&self) -> &[u8] {
        self.as_ref()
    }
}

impl AsRef<[u8]> for IVec {
    #[inline]
    fn as_ref(&self) -> &[u8] {
        match &self.0 {
            IVecInner::Inline(sz, buf) => {
                unsafe { buf.get_unchecked(..*sz as usize) }
            },
            IVecInner::Remote(buf) => buf,
        }
    }
}

impl Ord for IVec {
    fn cmp(&self, other: &IVec) -> std::cmp::Ordering {
        self.as_ref().cmp(other.as_ref())
    }
}

impl PartialOrd for IVec {
    fn partial_cmp(&self, other: &IVec) -> Option<std::cmp::Ordering> {
        Some(self.cmp(other))
    }
}

impl<T: AsRef<[u8]>> PartialEq<T> for IVec {
    fn eq(&self, other: &T) -> bool {
        self.as_ref() == other.as_ref()
    }
}

impl PartialEq<[u8]> for IVec {
    fn eq(&self, other: &[u8]) -> bool {
        self.as_ref() == other
    }
}

impl Eq for IVec { }

impl fmt::Debug for IVec {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        self.as_ref().fmt(f)
    }
}

#[test]
fn ivec_usage() {
    let iv1 = IVec::from(vec![1, 2, 3]);
    assert_eq!(iv1, vec![1, 2, 3]);
    let iv2 = IVec::from(&[4; 128][..]);
    assert_eq!(iv2, vec![4; 128]);
}
<|endoftext|>


<commit_before>#[macro_use]
extern crate lazy_static;
#[macro_use]
extern crate log;
extern crate log4rs;
extern crate r2d2;
extern crate r2d2_postgres;
extern crate iron;
extern crate persistent;
extern crate potboiler_common;
extern crate logger;
extern crate serde_json;
extern crate hyper;
extern crate router;
extern crate uuid;

use iron::prelude::{Chain, Iron, IronError, IronResult, Request, Response};
use iron::status;
use logger::Logger;
use persistent::Read as PRead;
use potboiler_common::db;
use potboiler_common::types::Log;
use std::env;
use std::ops::Deref;

mod types;

pub type PostgresConnection = r2d2::PooledConnection<r2d2_postgres::PostgresConnectionManager>;

lazy_static! {
    static ref SERVER_URL: String = env::var("SERVER_URL").expect("Needed SERVER_URL");
}

fn iron_str_error<T: std::error::Error + std::marker::Send + 'static>(se: T) -> iron::IronError {
    let desc = format!("{:?}", se);
    return IronError::new(se, (status::BadRequest, desc));
}

fn string_from_body<T: std::io::Read>(body: &mut T) -> IronResult<String> {
    let mut result = String::new();
    try!(body.read_to_string(&mut result).map_err(iron_str_error));
    Ok(result)
}

fn json_from_body(req: &mut Request) -> IronResult<serde_json::Value> {
    let body_string = try!(string_from_body(&mut req.body));
    let json: serde_json::Value = match serde_json::de::from_str(&body_string) {
        Ok(val) => val,
        Err(err) => return Err(IronError::new(err, (status::BadRequest, "Bad JSON"))),
    };
    return Ok(json);
}

fn add_queue_operation(op: types::QueueOperation) -> IronResult<Response> {
    let client = hyper::client::Client::new();
    let mut res = client.post(SERVER_URL.deref())
        .body(&serde_json::ser::to_string(&op).unwrap())
        .send()
        .expect("sender ok");
    assert_eq!(res.status, hyper::status::StatusCode::Created);
    let data = try!(string_from_body(&mut res));
    Ok(Response::with((status::Ok, data)))
}

fn create_queue(req: &mut Request) -> IronResult<Response> {
    let json = try!(json_from_body(req));
    let op = try!(serde_json::from_value::<types::QueueCreate>(json).map_err(iron_str_error));
    return add_queue_operation(types::QueueOperation::Create(op));
}

fn new_event(req: &mut Request) -> IronResult<Response> {
    let json = try!(json_from_body(req));
    let log = try!(serde_json::from_value::<Log>(json).map_err(iron_str_error));
    info!("body: {:?}", log);
    let op = try!(serde_json::from_value::<types::QueueOperation>(log.data).map_err(iron_str_error));
    info!("op: {:?}", op);
    Ok(Response::with(status::NoContent))
}

fn make_queue_table(conn: &PostgresConnection) {
    conn.execute("CREATE TABLE IF NOT EXISTS queues (key VARCHAR(1024) PRIMARY KEY, config JSONB)",
                 &[])
        .expect("make queue table worked");
}

fn main() {
    log4rs::init_file("log.yaml", Default::default()).expect("log config ok");
    let client = hyper::client::Client::new();

    let mut map: serde_json::Map<String, String> = serde_json::Map::new();
    let host: &str = &env::var("HOST").unwrap_or("localhost".to_string());
    map.insert("url".to_string(),
               format!("http://{}:8000/event", host).to_string());
    let res = client.post(&format!("{}/register", SERVER_URL.deref()))
        .body(&serde_json::ser::to_string(&map).unwrap())
        .send()
        .expect("Register ok");
    assert_eq!(res.status, hyper::status::StatusCode::NoContent);

    let db_url: &str = &env::var("DATABASE_URL").expect("Needed DATABASE_URL");
    let pool = db::get_pool(db_url);
    let conn = pool.get().unwrap();
    make_queue_table(&conn);
    let (logger_before, logger_after) = Logger::new(None);
    let mut router = router::Router::new();
    router.post("/create", create_queue);
    router.post("/event", new_event);
    let mut chain = Chain::new(router);
    chain.link_before(logger_before);
    chain.link_after(logger_after);
    chain.link(PRead::<db::PostgresDB>::both(pool));
    info!("Pigtail booted");
    Iron::new(chain).http("0.0.0.0:8000").unwrap();
}
<commit_msg>Return new queue URLs from create queue<commit_after>#[macro_use]
extern crate lazy_static;
#[macro_use]
extern crate log;
extern crate log4rs;
extern crate r2d2;
extern crate r2d2_postgres;
extern crate iron;
extern crate persistent;
extern crate potboiler_common;
extern crate logger;
extern crate serde_json;
extern crate hyper;
extern crate router;
extern crate uuid;

use iron::modifiers::Redirect;
use iron::prelude::{Chain, Iron, IronError, IronResult, Request, Response};
use iron::status;
use logger::Logger;
use persistent::Read as PRead;
use potboiler_common::db;
use potboiler_common::types::Log;
use std::env;
use std::ops::Deref;

mod types;

pub type PostgresConnection = r2d2::PooledConnection<r2d2_postgres::PostgresConnectionManager>;

lazy_static! {
    static ref SERVER_URL: String = env::var("SERVER_URL").expect("Needed SERVER_URL");
    static ref HOST: String = env::var("HOST").expect("Needed HOST");
}

fn iron_str_error<T: std::error::Error + std::marker::Send + 'static>(se: T) -> iron::IronError {
    let desc = format!("{:?}", se);
    return IronError::new(se, (status::BadRequest, desc));
}

fn string_from_body<T: std::io::Read>(body: &mut T) -> IronResult<String> {
    let mut result = String::new();
    try!(body.read_to_string(&mut result).map_err(iron_str_error));
    Ok(result)
}

fn json_from_body(req: &mut Request) -> IronResult<serde_json::Value> {
    let body_string = try!(string_from_body(&mut req.body));
    let json: serde_json::Value = match serde_json::de::from_str(&body_string) {
        Ok(val) => val,
        Err(err) => return Err(IronError::new(err, (status::BadRequest, "Bad JSON"))),
    };
    return Ok(json);
}

fn add_queue_operation(op: types::QueueOperation) -> IronResult<String> {
    let client = hyper::client::Client::new();
    let mut res = client.post(SERVER_URL.deref())
        .body(&serde_json::ser::to_string(&op).unwrap())
        .send()
        .expect("sender ok");
    assert_eq!(res.status, hyper::status::StatusCode::Created);
    let data = try!(string_from_body(&mut res));
    Ok(data)
}

fn create_queue(req: &mut Request) -> IronResult<Response> {
    let json = try!(json_from_body(req));
    let op = try!(serde_json::from_value::<types::QueueCreate>(json).map_err(iron_str_error));
    match add_queue_operation(types::QueueOperation::Create(op)) {
        Ok(data) => {
            let new_url = format!("http://{}:8000/queue/{}", HOST.deref(), &data);
            Ok(Response::with((status::Created,
                               Redirect(iron::Url::parse(&new_url).expect("URL parsed ok")))))
        }
        Err(val) => Err(val),
    }
}

fn new_event(req: &mut Request) -> IronResult<Response> {
    let json = try!(json_from_body(req));
    let log = try!(serde_json::from_value::<Log>(json).map_err(iron_str_error));
    info!("body: {:?}", log);
    let op = try!(serde_json::from_value::<types::QueueOperation>(log.data).map_err(iron_str_error));
    info!("op: {:?}", op);
    Ok(Response::with(status::NoContent))
}

fn make_queue_table(conn: &PostgresConnection) {
    conn.execute("CREATE TABLE IF NOT EXISTS queues (key VARCHAR(1024) PRIMARY KEY, config JSONB)",
                 &[])
        .expect("make queue table worked");
}

fn main() {
    log4rs::init_file("log.yaml", Default::default()).expect("log config ok");
    let client = hyper::client::Client::new();

    let mut map: serde_json::Map<String, String> = serde_json::Map::new();
    map.insert("url".to_string(),
               format!("http://{}:8000/event", HOST.deref()).to_string());
    let res = client.post(&format!("{}/register", SERVER_URL.deref()))
        .body(&serde_json::ser::to_string(&map).unwrap())
        .send()
        .expect("Register ok");
    assert_eq!(res.status, hyper::status::StatusCode::NoContent);

    let db_url: &str = &env::var("DATABASE_URL").expect("Needed DATABASE_URL");
    let pool = db::get_pool(db_url);
    let conn = pool.get().unwrap();
    make_queue_table(&conn);
    let (logger_before, logger_after) = Logger::new(None);
    let mut router = router::Router::new();
    router.post("/create", create_queue);
    router.post("/event", new_event);
    let mut chain = Chain::new(router);
    chain.link_before(logger_before);
    chain.link_after(logger_after);
    chain.link(PRead::<db::PostgresDB>::both(pool));
    info!("Pigtail booted");
    Iron::new(chain).http("0.0.0.0:8000").unwrap();
}
<|endoftext|>


<commit_before>#![feature(plugin_registrar, quote, rustc_private, box_patterns)]

extern crate rustc;
extern crate syntax;

use syntax::ast;
use syntax::codemap;
use syntax::ext::base::{ExtCtxt, MacResult, MacEager, DummyResult};
use syntax::parse;
use syntax::parse::token;
use syntax::fold::Folder;
use syntax::util::small_vector::SmallVector;
use rustc::plugin::Registry;
use std::io::Read;
use std::fs::File;
use std::path::Path;

use rustast::{AstBuilder, DUMMY_SP};

mod translate;
mod grammar;
mod rustast;

#[plugin_registrar]
pub fn plugin_registrar(reg: &mut Registry) {
    reg.register_syntax_extension(
            token::intern("peg"),
            syntax::ext::base::IdentTT(Box::new(expand_peg_str), None, false));

    reg.register_syntax_extension(
            token::intern("peg_file"),
            syntax::ext::base::IdentTT(Box::new(expand_peg_file), None, false));
}

fn expand_peg_str<'s>(cx: &'s mut ExtCtxt, sp: codemap::Span, ident: ast::Ident, tts: Vec<ast::TokenTree>) -> Box<MacResult + 's> {
    let source = match parse_arg(cx, &tts) {
        Some(source) => source,
        None => return DummyResult::any(sp),
    };

    expand_peg(cx, sp, ident, &source)
}

fn expand_peg_file<'s>(cx: &'s mut ExtCtxt, sp: codemap::Span, ident: ast::Ident, tts: Vec<ast::TokenTree>) -> Box<MacResult + 's> {
    let fname = match parse_arg(cx, &tts) {
        Some(fname) => fname,
        None => return DummyResult::any(sp),
    };

    let path = Path::new(&cx.codemap().span_to_filename(sp)).parent().unwrap().join(&fname);

    let mut source = String::new();
    if let Err(e) = File::open(&path).map(|mut f| f.read_to_string(&mut source)) {
        cx.span_err(sp, &e.to_string());
        return DummyResult::any(sp);
    }

    cx.codemap().new_filemap(format!("{}", path.display()), "".to_string());

    expand_peg(cx, sp, ident, &source)
}

fn expand_peg(cx: &mut ExtCtxt, sp: codemap::Span, ident: ast::Ident, source: &str) -> Box<MacResult + 'static> {
    let grammar_def = grammar::grammar(source);

    let grammar_def = match grammar_def {
      Ok(grammar_def) => grammar_def,
      Err(msg) => {
        cx.span_err(sp, &format!("{}", msg));
        return DummyResult::any(sp)
      }
    };

    let ast = translate::compile_grammar(cx, &grammar_def);

    // #![allow(non_snake_case, unused)]
    let allow = cx.attribute(DUMMY_SP, cx.meta_list(DUMMY_SP, token::InternedString::new("allow"), vec![
        cx.meta_word(DUMMY_SP, token::InternedString::new("non_snake_case")),
        cx.meta_word(DUMMY_SP, token::InternedString::new("unused")),
    ]));

    MacEager::items(SmallVector::one(cx.item_mod(sp, sp, ident, vec![allow], ast.items.clone())))
}

fn parse_arg(cx: &mut ExtCtxt, tts: &[ast::TokenTree]) -> Option<String> {
    use syntax::print::pprust;

    let mut parser = parse::new_parser_from_tts(cx.parse_sess(), cx.cfg(),
                                                tts.to_vec());
    // The `expand_expr` method is called so that any macro calls in the
    // parsed expression are expanded.
    let arg = cx.expander().fold_expr(parser.parse_expr().unwrap_or_else(|e| panic!(e)));
    match arg.node {
        ast::ExprLit(ref spanned) => {
            match spanned.node {
                ast::LitStr(ref n, _) => {
                    if !parser.eat(&token::Eof).unwrap_or_else(|e| panic!(e)) {
                        cx.span_err(parser.span,
                                    "expected only one string literal");
                        return None
                    }
                    return Some(n.to_string())
                }
                _ => {}
            }
        }
        _ => {}
    }

    let err = format!("expected string literal but got `{}`",
                      pprust::expr_to_string(&*arg));
    cx.span_err(parser.span, &err);
    None
}
<commit_msg>rust: rust::plugin -> rustc_plugin;<commit_after>#![feature(plugin_registrar, quote, rustc_private, box_patterns)]

extern crate rustc_plugin;
extern crate syntax;

use syntax::ast;
use syntax::codemap;
use syntax::ext::base::{ExtCtxt, MacResult, MacEager, DummyResult};
use syntax::parse;
use syntax::parse::token;
use syntax::fold::Folder;
use syntax::util::small_vector::SmallVector;
use rustc_plugin::Registry;
use std::io::Read;
use std::fs::File;
use std::path::Path;

use rustast::{AstBuilder, DUMMY_SP};

mod translate;
mod grammar;
mod rustast;

#[plugin_registrar]
pub fn plugin_registrar(reg: &mut Registry) {
    reg.register_syntax_extension(
            token::intern("peg"),
            syntax::ext::base::IdentTT(Box::new(expand_peg_str), None, false));

    reg.register_syntax_extension(
            token::intern("peg_file"),
            syntax::ext::base::IdentTT(Box::new(expand_peg_file), None, false));
}

fn expand_peg_str<'s>(cx: &'s mut ExtCtxt, sp: codemap::Span, ident: ast::Ident, tts: Vec<ast::TokenTree>) -> Box<MacResult + 's> {
    let source = match parse_arg(cx, &tts) {
        Some(source) => source,
        None => return DummyResult::any(sp),
    };

    expand_peg(cx, sp, ident, &source)
}

fn expand_peg_file<'s>(cx: &'s mut ExtCtxt, sp: codemap::Span, ident: ast::Ident, tts: Vec<ast::TokenTree>) -> Box<MacResult + 's> {
    let fname = match parse_arg(cx, &tts) {
        Some(fname) => fname,
        None => return DummyResult::any(sp),
    };

    let path = Path::new(&cx.codemap().span_to_filename(sp)).parent().unwrap().join(&fname);

    let mut source = String::new();
    if let Err(e) = File::open(&path).map(|mut f| f.read_to_string(&mut source)) {
        cx.span_err(sp, &e.to_string());
        return DummyResult::any(sp);
    }

    cx.codemap().new_filemap(format!("{}", path.display()), "".to_string());

    expand_peg(cx, sp, ident, &source)
}

fn expand_peg(cx: &mut ExtCtxt, sp: codemap::Span, ident: ast::Ident, source: &str) -> Box<MacResult + 'static> {
    let grammar_def = grammar::grammar(source);

    let grammar_def = match grammar_def {
      Ok(grammar_def) => grammar_def,
      Err(msg) => {
        cx.span_err(sp, &format!("{}", msg));
        return DummyResult::any(sp)
      }
    };

    let ast = translate::compile_grammar(cx, &grammar_def);

    // #![allow(non_snake_case, unused)]
    let allow = cx.attribute(DUMMY_SP, cx.meta_list(DUMMY_SP, token::InternedString::new("allow"), vec![
        cx.meta_word(DUMMY_SP, token::InternedString::new("non_snake_case")),
        cx.meta_word(DUMMY_SP, token::InternedString::new("unused")),
    ]));

    MacEager::items(SmallVector::one(cx.item_mod(sp, sp, ident, vec![allow], ast.items.clone())))
}

fn parse_arg(cx: &mut ExtCtxt, tts: &[ast::TokenTree]) -> Option<String> {
    use syntax::print::pprust;

    let mut parser = parse::new_parser_from_tts(cx.parse_sess(), cx.cfg(),
                                                tts.to_vec());
    // The `expand_expr` method is called so that any macro calls in the
    // parsed expression are expanded.
    let arg = cx.expander().fold_expr(parser.parse_expr().unwrap_or_else(|e| panic!(e)));
    match arg.node {
        ast::ExprLit(ref spanned) => {
            match spanned.node {
                ast::LitStr(ref n, _) => {
                    if !parser.eat(&token::Eof).unwrap_or_else(|e| panic!(e)) {
                        cx.span_err(parser.span,
                                    "expected only one string literal");
                        return None
                    }
                    return Some(n.to_string())
                }
                _ => {}
            }
        }
        _ => {}
    }

    let err = format!("expected string literal but got `{}`",
                      pprust::expr_to_string(&*arg));
    cx.span_err(parser.span, &err);
    None
}
<|endoftext|>


<commit_before>use std::cmp::Ordering;

use itertools::Itertools;

use syntax::{
    ast::{self, NameOwner},
    ted, AstNode, TextRange,
};

use crate::{utils::get_methods, AssistContext, AssistId, AssistKind, Assists};

// Assist: sort_items
//
pub(crate) fn sort_items(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
    if let Some(trait_ast) = ctx.find_node_at_offset::<ast::Trait>() {
        add_sort_methods_assist(acc, trait_ast.assoc_item_list()?)
    } else if let Some(impl_ast) = ctx.find_node_at_offset::<ast::Impl>() {
        add_sort_methods_assist(acc, impl_ast.assoc_item_list()?)
    } else if let Some(struct_ast) = ctx.find_node_at_offset::<ast::Struct>() {
        match struct_ast.field_list() {
            Some(ast::FieldList::RecordFieldList(it)) => add_sort_fields_assist(acc, it),
            _ => {
                cov_mark::hit!(not_applicable_if_sorted_or_empty_or_single);
                None
            }
        }
    } else if let Some(union_ast) = ctx.find_node_at_offset::<ast::Union>() {
        add_sort_fields_assist(acc, union_ast.record_field_list()?)
    } else if let Some(enum_struct_variant_ast) = ctx.find_node_at_offset::<ast::RecordFieldList>()
    {
        // should be above enum and below struct
        add_sort_fields_assist(acc, enum_struct_variant_ast)
    } else if let Some(enum_ast) = ctx.find_node_at_offset::<ast::Enum>() {
        add_sort_variants_assist(acc, enum_ast.variant_list()?)
    } else {
        None
    }
}

trait AddRewrite {
    fn add_rewrite<T: AstNode>(
        &mut self,
        label: &str,
        old: Vec<T>,
        new: Vec<T>,
        target: TextRange,
    ) -> Option<()>;
}

impl AddRewrite for Assists {
    fn add_rewrite<T: AstNode>(
        &mut self,
        label: &str,
        old: Vec<T>,
        new: Vec<T>,
        target: TextRange,
    ) -> Option<()> {
        self.add(AssistId("sort_items", AssistKind::RefactorRewrite), label, target, |builder| {
            let mutable: Vec<_> = old.into_iter().map(|it| builder.make_mut(it)).collect();
            mutable
                .into_iter()
                .zip(new)
                .for_each(|(old, new)| ted::replace(old.syntax(), new.clone_for_update().syntax()));
        })
    }
}

fn add_sort_methods_assist(acc: &mut Assists, item_list: ast::AssocItemList) -> Option<()> {
    let methods = get_methods(&item_list);
    let sorted = sort_by_name(&methods);

    if methods == sorted {
        cov_mark::hit!(not_applicable_if_sorted_or_empty_or_single);
        return None;
    }

    acc.add_rewrite("Sort methods alphabetically", methods, sorted, item_list.syntax().text_range())
}

fn add_sort_fields_assist(
    acc: &mut Assists,
    record_field_list: ast::RecordFieldList,
) -> Option<()> {
    let fields: Vec<_> = record_field_list.fields().collect();
    let sorted = sort_by_name(&fields);

    if fields == sorted {
        cov_mark::hit!(not_applicable_if_sorted_or_empty_or_single);
        return None;
    }

    acc.add_rewrite(
        "Sort fields alphabetically",
        fields,
        sorted,
        record_field_list.syntax().text_range(),
    )
}

fn add_sort_variants_assist(acc: &mut Assists, variant_list: ast::VariantList) -> Option<()> {
    let variants: Vec<_> = variant_list.variants().collect();
    let sorted = sort_by_name(&variants);

    if variants == sorted {
        cov_mark::hit!(not_applicable_if_sorted_or_empty_or_single);
        return None;
    }

    acc.add_rewrite(
        "Sort variants alphabetically",
        variants,
        sorted,
        variant_list.syntax().text_range(),
    )
}

fn sort_by_name<T: NameOwner + Clone>(initial: &[T]) -> Vec<T> {
    initial
        .iter()
        .cloned()
        .sorted_by(|a, b| match (a.name(), b.name()) {
            (Some(a), Some(b)) => Ord::cmp(&a.to_string(), &b.to_string()),

            // unexpected, but just in case
            (None, None) => Ordering::Equal,
            (None, Some(_)) => Ordering::Less,
            (Some(_), None) => Ordering::Greater,
        })
        .collect()
}

#[cfg(test)]
mod tests {
    use crate::tests::{check_assist, check_assist_not_applicable};

    use super::*;

    #[test]
    fn not_applicable_if_trait_empty() {
        cov_mark::check!(not_applicable_if_sorted_or_empty_or_single);

        check_assist_not_applicable(
            sort_items,
            r#"
t$0rait Bar {
}
        "#,
        )
    }

    #[test]
    fn not_applicable_if_impl_empty() {
        cov_mark::check!(not_applicable_if_sorted_or_empty_or_single);

        check_assist_not_applicable(
            sort_items,
            r#"
struct Bar;
$0impl Bar {
}
        "#,
        )
    }

    #[test]
    fn not_applicable_if_struct_empty() {
        cov_mark::check!(not_applicable_if_sorted_or_empty_or_single);

        check_assist_not_applicable(
            sort_items,
            r#"
$0struct Bar;
        "#,
        )
    }

    #[test]
    fn not_applicable_if_struct_empty2() {
        cov_mark::check!(not_applicable_if_sorted_or_empty_or_single);

        check_assist_not_applicable(
            sort_items,
            r#"
$0struct Bar { };
        "#,
        )
    }

    #[test]
    fn not_applicable_if_enum_empty() {
        cov_mark::check!(not_applicable_if_sorted_or_empty_or_single);

        check_assist_not_applicable(
            sort_items,
            r#"
$0enum ZeroVariants {};
        "#,
        )
    }

    #[test]
    fn not_applicable_if_trait_sorted() {
        cov_mark::check!(not_applicable_if_sorted_or_empty_or_single);

        check_assist_not_applicable(
            sort_items,
            r#"
t$0rait Bar {
    fn a() {}
    fn b() {}
    fn c() {}
}
        "#,
        )
    }

    #[test]
    fn not_applicable_if_impl_sorted() {
        cov_mark::check!(not_applicable_if_sorted_or_empty_or_single);

        check_assist_not_applicable(
            sort_items,
            r#"
struct Bar;
$0impl Bar {
    fn a() {}
    fn b() {}
    fn c() {}
}
        "#,
        )
    }

    #[test]
    fn not_applicable_if_struct_sorted() {
        cov_mark::check!(not_applicable_if_sorted_or_empty_or_single);

        check_assist_not_applicable(
            sort_items,
            r#"
$0struct Bar {
    a: u32,
    b: u8,
    c: u64,
}
        "#,
        )
    }

    #[test]
    fn not_applicable_if_union_sorted() {
        cov_mark::check!(not_applicable_if_sorted_or_empty_or_single);

        check_assist_not_applicable(
            sort_items,
            r#"
$0union Bar {
    a: u32,
    b: u8,
    c: u64,
}
        "#,
        )
    }

    #[test]
    fn not_applicable_if_enum_sorted() {
        cov_mark::check!(not_applicable_if_sorted_or_empty_or_single);

        check_assist_not_applicable(
            sort_items,
            r#"
$0enum Bar {
    a,
    b,
    c,
}
        "#,
        )
    }

    #[test]
    fn sort_trait() {
        check_assist(
            sort_items,
            r#"
$0trait Bar {
    fn a() {}
    fn c() {}
    fn z() {}
    fn b() {}
}
        "#,
            r#"
trait Bar {
    fn a() {}
    fn b() {}
    fn c() {}
    fn z() {}
}
        "#,
        )
    }

    #[test]
    fn sort_impl() {
        check_assist(
            sort_items,
            r#"
struct Bar;
$0impl Bar {
    fn c() {}
    fn a() {}
    fn z() {}
    fn d() {}
}
        "#,
            r#"
struct Bar;
impl Bar {
    fn a() {}
    fn c() {}
    fn d() {}
    fn z() {}
}
        "#,
        )
    }

    #[test]
    fn sort_struct() {
        check_assist(
            sort_items,
            r#"
$0struct Bar {
    b: u8,
    a: u32,
    c: u64,
}
        "#,
            r#"
struct Bar {
    a: u32,
    b: u8,
    c: u64,
}
        "#,
        )
    }

    #[test]
    fn sort_generic_struct_with_lifetime() {
        check_assist(
            sort_items,
            r#"
$0struct Bar<'a, T> {
    d: &'a str,
    b: u8,
    a: T,
    c: u64,
}
        "#,
            r#"
struct Bar<'a, T> {
    a: T,
    b: u8,
    c: u64,
    d: &'a str,
}
        "#,
        )
    }

    #[test]
    fn sort_struct_fields_diff_len() {
        check_assist(
            sort_items,
            r#"
$0struct Bar {
    aaa: u8,
    a: usize,
    b: u8,
}
        "#,
            r#"
struct Bar {
    a: usize,
    aaa: u8,
    b: u8,
}
        "#,
        )
    }

    #[test]
    fn sort_union() {
        check_assist(
            sort_items,
            r#"
$0union Bar {
    b: u8,
    a: u32,
    c: u64,
}
        "#,
            r#"
union Bar {
    a: u32,
    b: u8,
    c: u64,
}
        "#,
        )
    }

    #[test]
    fn sort_enum() {
        check_assist(
            sort_items,
            r#"
$0enum Bar {
    d{ first: u32, second: usize},
    b = 14,
    a,
    c(u32, usize),
}
        "#,
            r#"
enum Bar {
    a,
    b = 14,
    c(u32, usize),
    d{ first: u32, second: usize},
}
        "#,
        )
    }

    #[test]
    fn sort_struct_enum_variant() {
        check_assist(
            sort_items,
            r#"
enum Bar {
    d$0{ second: usize, first: u32 },
    b = 14,
    a,
    c(u32, usize),
}
        "#,
            r#"
enum Bar {
    d{ first: u32, second: usize },
    b = 14,
    a,
    c(u32, usize),
}
        "#,
        )
    }
}
<commit_msg>Some comment tests<commit_after>use std::cmp::Ordering;

use itertools::Itertools;

use syntax::{
    ast::{self, NameOwner},
    ted, AstNode, TextRange,
};

use crate::{utils::get_methods, AssistContext, AssistId, AssistKind, Assists};

// Assist: sort_items
//
pub(crate) fn sort_items(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
    if let Some(trait_ast) = ctx.find_node_at_offset::<ast::Trait>() {
        add_sort_methods_assist(acc, trait_ast.assoc_item_list()?)
    } else if let Some(impl_ast) = ctx.find_node_at_offset::<ast::Impl>() {
        add_sort_methods_assist(acc, impl_ast.assoc_item_list()?)
    } else if let Some(struct_ast) = ctx.find_node_at_offset::<ast::Struct>() {
        match struct_ast.field_list() {
            Some(ast::FieldList::RecordFieldList(it)) => add_sort_fields_assist(acc, it),
            _ => {
                cov_mark::hit!(not_applicable_if_sorted_or_empty_or_single);
                None
            }
        }
    } else if let Some(union_ast) = ctx.find_node_at_offset::<ast::Union>() {
        add_sort_fields_assist(acc, union_ast.record_field_list()?)
    } else if let Some(enum_struct_variant_ast) = ctx.find_node_at_offset::<ast::RecordFieldList>()
    {
        // should be above enum and below struct
        add_sort_fields_assist(acc, enum_struct_variant_ast)
    } else if let Some(enum_ast) = ctx.find_node_at_offset::<ast::Enum>() {
        add_sort_variants_assist(acc, enum_ast.variant_list()?)
    } else {
        None
    }
}

trait AddRewrite {
    fn add_rewrite<T: AstNode>(
        &mut self,
        label: &str,
        old: Vec<T>,
        new: Vec<T>,
        target: TextRange,
    ) -> Option<()>;
}

impl AddRewrite for Assists {
    fn add_rewrite<T: AstNode>(
        &mut self,
        label: &str,
        old: Vec<T>,
        new: Vec<T>,
        target: TextRange,
    ) -> Option<()> {
        self.add(AssistId("sort_items", AssistKind::RefactorRewrite), label, target, |builder| {
            let mutable: Vec<_> = old.into_iter().map(|it| builder.make_mut(it)).collect();
            mutable
                .into_iter()
                .zip(new)
                .for_each(|(old, new)| ted::replace(old.syntax(), new.clone_for_update().syntax()));
        })
    }
}

fn add_sort_methods_assist(acc: &mut Assists, item_list: ast::AssocItemList) -> Option<()> {
    let methods = get_methods(&item_list);
    let sorted = sort_by_name(&methods);

    if methods == sorted {
        cov_mark::hit!(not_applicable_if_sorted_or_empty_or_single);
        return None;
    }

    acc.add_rewrite("Sort methods alphabetically", methods, sorted, item_list.syntax().text_range())
}

fn add_sort_fields_assist(
    acc: &mut Assists,
    record_field_list: ast::RecordFieldList,
) -> Option<()> {
    let fields: Vec<_> = record_field_list.fields().collect();
    let sorted = sort_by_name(&fields);

    if fields == sorted {
        cov_mark::hit!(not_applicable_if_sorted_or_empty_or_single);
        return None;
    }

    acc.add_rewrite(
        "Sort fields alphabetically",
        fields,
        sorted,
        record_field_list.syntax().text_range(),
    )
}

fn add_sort_variants_assist(acc: &mut Assists, variant_list: ast::VariantList) -> Option<()> {
    let variants: Vec<_> = variant_list.variants().collect();
    let sorted = sort_by_name(&variants);

    if variants == sorted {
        cov_mark::hit!(not_applicable_if_sorted_or_empty_or_single);
        return None;
    }

    acc.add_rewrite(
        "Sort variants alphabetically",
        variants,
        sorted,
        variant_list.syntax().text_range(),
    )
}

fn sort_by_name<T: NameOwner + Clone>(initial: &[T]) -> Vec<T> {
    initial
        .iter()
        .cloned()
        .sorted_by(|a, b| match (a.name(), b.name()) {
            (Some(a), Some(b)) => Ord::cmp(&a.to_string(), &b.to_string()),

            // unexpected, but just in case
            (None, None) => Ordering::Equal,
            (None, Some(_)) => Ordering::Less,
            (Some(_), None) => Ordering::Greater,
        })
        .collect()
}

#[cfg(test)]
mod tests {
    use crate::tests::{check_assist, check_assist_not_applicable};

    use super::*;

    #[test]
    fn not_applicable_if_trait_empty() {
        cov_mark::check!(not_applicable_if_sorted_or_empty_or_single);

        check_assist_not_applicable(
            sort_items,
            r#"
t$0rait Bar {
}
        "#,
        )
    }

    #[test]
    fn not_applicable_if_impl_empty() {
        cov_mark::check!(not_applicable_if_sorted_or_empty_or_single);

        check_assist_not_applicable(
            sort_items,
            r#"
struct Bar;
$0impl Bar {
}
        "#,
        )
    }

    #[test]
    fn not_applicable_if_struct_empty() {
        cov_mark::check!(not_applicable_if_sorted_or_empty_or_single);

        check_assist_not_applicable(
            sort_items,
            r#"
$0struct Bar;
        "#,
        )
    }

    #[test]
    fn not_applicable_if_struct_empty2() {
        cov_mark::check!(not_applicable_if_sorted_or_empty_or_single);

        check_assist_not_applicable(
            sort_items,
            r#"
$0struct Bar { };
        "#,
        )
    }

    #[test]
    fn not_applicable_if_enum_empty() {
        cov_mark::check!(not_applicable_if_sorted_or_empty_or_single);

        check_assist_not_applicable(
            sort_items,
            r#"
$0enum ZeroVariants {};
        "#,
        )
    }

    #[test]
    fn not_applicable_if_trait_sorted() {
        cov_mark::check!(not_applicable_if_sorted_or_empty_or_single);

        check_assist_not_applicable(
            sort_items,
            r#"
t$0rait Bar {
    fn a() {}
    fn b() {}
    fn c() {}
}
        "#,
        )
    }

    #[test]
    fn not_applicable_if_impl_sorted() {
        cov_mark::check!(not_applicable_if_sorted_or_empty_or_single);

        check_assist_not_applicable(
            sort_items,
            r#"
struct Bar;
$0impl Bar {
    fn a() {}
    fn b() {}
    fn c() {}
}
        "#,
        )
    }

    #[test]
    fn not_applicable_if_struct_sorted() {
        cov_mark::check!(not_applicable_if_sorted_or_empty_or_single);

        check_assist_not_applicable(
            sort_items,
            r#"
$0struct Bar {
    a: u32,
    b: u8,
    c: u64,
}
        "#,
        )
    }

    #[test]
    fn not_applicable_if_union_sorted() {
        cov_mark::check!(not_applicable_if_sorted_or_empty_or_single);

        check_assist_not_applicable(
            sort_items,
            r#"
$0union Bar {
    a: u32,
    b: u8,
    c: u64,
}
        "#,
        )
    }

    #[test]
    fn not_applicable_if_enum_sorted() {
        cov_mark::check!(not_applicable_if_sorted_or_empty_or_single);

        check_assist_not_applicable(
            sort_items,
            r#"
$0enum Bar {
    a,
    b,
    c,
}
        "#,
        )
    }

    #[test]
    fn sort_trait() {
        check_assist(
            sort_items,
            r#"
$0trait Bar {
    fn a() {

    }

    // comment for c
    fn c() {}
    fn z() {}
    fn b() {}
}
        "#,
            r#"
trait Bar {
    fn a() {

    }

    fn b() {}
    // comment for c
    fn c() {}
    fn z() {}
}
        "#,
        )
    }

    #[test]
    fn sort_impl() {
        check_assist(
            sort_items,
            r#"
struct Bar;
$0impl Bar {
    fn c() {}
    fn a() {}
    /// long
    /// doc
    /// comment
    fn z() {}
    fn d() {}
}
        "#,
            r#"
struct Bar;
impl Bar {
    fn a() {}
    fn c() {}
    fn d() {}
    /// long
    /// doc
    /// comment
    fn z() {}
}
        "#,
        )
    }

    #[test]
    fn sort_struct() {
        check_assist(
            sort_items,
            r#"
$0struct Bar {
    b: u8,
    a: u32,
    c: u64,
}
        "#,
            r#"
struct Bar {
    a: u32,
    b: u8,
    c: u64,
}
        "#,
        )
    }

    #[test]
    fn sort_generic_struct_with_lifetime() {
        check_assist(
            sort_items,
            r#"
$0struct Bar<'a, T> {
    d: &'a str,
    b: u8,
    a: T,
    c: u64,
}
        "#,
            r#"
struct Bar<'a, T> {
    a: T,
    b: u8,
    c: u64,
    d: &'a str,
}
        "#,
        )
    }

    #[test]
    fn sort_struct_fields_diff_len() {
        check_assist(
            sort_items,
            r#"
$0struct Bar {
    aaa: u8,
    a: usize,
    b: u8,
}
        "#,
            r#"
struct Bar {
    a: usize,
    aaa: u8,
    b: u8,
}
        "#,
        )
    }

    #[test]
    fn sort_union() {
        check_assist(
            sort_items,
            r#"
$0union Bar {
    b: u8,
    a: u32,
    c: u64,
}
        "#,
            r#"
union Bar {
    a: u32,
    b: u8,
    c: u64,
}
        "#,
        )
    }

    #[test]
    fn sort_enum() {
        check_assist(
            sort_items,
            r#"
$0enum Bar {
    d{ first: u32, second: usize},
    b = 14,
    a,
    c(u32, usize),
}
        "#,
            r#"
enum Bar {
    a,
    b = 14,
    c(u32, usize),
    d{ first: u32, second: usize},
}
        "#,
        )
    }

    #[test]
    fn sort_struct_enum_variant() {
        check_assist(
            sort_items,
            r#"
enum Bar {
    d$0{ second: usize, first: u32 },
    b = 14,
    a,
    c(u32, usize),
}
        "#,
            r#"
enum Bar {
    d{ first: u32, second: usize },
    b = 14,
    a,
    c(u32, usize),
}
        "#,
        )
    }
}
<|endoftext|>


<commit_before>// enum with implicit discriminator (starts at 0)
enum Day {
    Monday,
    Tuesday,
    Wednesday,
    Thursday,
    Friday,
    Saturday,
    Sunday,
}

impl Day {
    fn mood(&self) {
        println!("{}", match *self {
            Friday => "it's friday!",
            Saturday | Sunday => "weekend :-)",
            _ => "weekday...",
        })
    }
}

// enum with explicit discriminator
enum Color {
    Red = 0xff0000,
    Green = 0x00ff00,
    Blue = 0x0000ff,
}

fn main() {
    let today = Monday;

    today.mood();

    // enums can be casted into integers
    println!("roses are \\#{:06x}", Red as int);
    println!("violets are \\#{:06x}", Blue as int);
}
<commit_msg>enum/c-like: fix formatting<commit_after>// enum with implicit discriminator (starts at 0)
enum Day {
    Monday,
    Tuesday,
    Wednesday,
    Thursday,
    Friday,
    Saturday,
    Sunday,
}

impl Day {
    fn mood(&self) {
        println!("{}", match *self {
            Friday => "it's friday!",
            Saturday | Sunday => "weekend :-)",
            _ => "weekday...",
        })
    }
}

// enum with explicit discriminator
enum Color {
    Red = 0xff0000,
    Green = 0x00ff00,
    Blue = 0x0000ff,
}

fn main() {
    let today = Monday;

    today.mood();

    // enums can be casted into integers
    println!("roses are #{:06x}", Red as int);
    println!("violets are #{:06x}", Blue as int);
}
<|endoftext|>


<commit_before>// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

// Test a sample usage pattern for regions. Makes use of the
// following features:
//
// - Multiple lifetime parameters
// - Arenas

extern crate arena;
extern crate collections;
extern crate libc;

use TypeStructure::{TypeInt, TypeFunction};
use AstKind::{ExprInt, ExprVar, ExprLambda};
use arena::Arena;
use std::collections::HashMap;
use std::mem;

type Type<'tcx> = &'tcx TypeStructure<'tcx>;

#[derive(Copy, Debug)]
enum TypeStructure<'tcx> {
    TypeInt,
    TypeFunction(Type<'tcx>, Type<'tcx>),
}

impl<'tcx> PartialEq for TypeStructure<'tcx> {
    fn eq(&self, other: &TypeStructure<'tcx>) -> bool {
        match (*self, *other) {
            (TypeInt, TypeInt) => true,
            (TypeFunction(s_a, s_b), TypeFunction(o_a, o_b)) => *s_a == *o_a && *s_b == *o_b,
            _ => false
        }
    }
}

impl<'tcx> Eq for TypeStructure<'tcx> {}

struct TypeContext<'tcx, 'ast> {
    ty_arena: &'tcx Arena,
    types: Vec<Type<'tcx>> ,
    type_table: HashMap<NodeId, Type<'tcx>>,

    ast_arena: &'ast Arena,
    ast_counter: uint,
}

impl<'tcx,'ast> TypeContext<'tcx, 'ast> {
    fn new(ty_arena: &'tcx Arena, ast_arena: &'ast Arena)
           -> TypeContext<'tcx, 'ast> {
        TypeContext { ty_arena: ty_arena,
                      types: Vec::new(),
                      type_table: HashMap::new(),

                      ast_arena: ast_arena,
                      ast_counter: 0 }
    }

    fn add_type(&mut self, s: TypeStructure<'tcx>) -> Type<'tcx> {
        for &ty in &self.types {
            if *ty == s {
                return ty;
            }
        }

        let ty = self.ty_arena.alloc(|| s);
        self.types.push(ty);
        ty
    }

    fn set_type(&mut self, id: NodeId, ty: Type<'tcx>) -> Type<'tcx> {
        self.type_table.insert(id, ty);
        ty
    }

    fn ast(&mut self, a: AstKind<'ast>) -> Ast<'ast> {
        let id = self.ast_counter;
        self.ast_counter += 1;
        self.ast_arena.alloc(|| AstStructure { id: NodeId {id:id}, kind: a })
    }
}

#[derive(Copy, PartialEq, Eq, Hash)]
struct NodeId {
    id: uint
}

type Ast<'ast> = &'ast AstStructure<'ast>;

#[derive(Copy)]
struct AstStructure<'ast> {
    id: NodeId,
    kind: AstKind<'ast>
}

#[derive(Copy)]
enum AstKind<'ast> {
    ExprInt,
    ExprVar(uint),
    ExprLambda(Ast<'ast>),
}

fn compute_types<'tcx,'ast>(tcx: &mut TypeContext<'tcx,'ast>,
                            ast: Ast<'ast>) -> Type<'tcx>
{
    match ast.kind {
        ExprInt | ExprVar(_) => {
            let ty = tcx.add_type(TypeInt);
            tcx.set_type(ast.id, ty)
        }
        ExprLambda(ast) => {
            let arg_ty = tcx.add_type(TypeInt);
            let body_ty = compute_types(tcx, ast);
            let lambda_ty = tcx.add_type(TypeFunction(arg_ty, body_ty));
            tcx.set_type(ast.id, lambda_ty)
        }
    }
}

pub fn main() {
    let ty_arena = arena::Arena::new();
    let ast_arena = arena::Arena::new();
    let mut tcx = TypeContext::new(&ty_arena, &ast_arena);
    let ast = tcx.ast(ExprInt);
    let ty = compute_types(&mut tcx, ast);
    assert_eq!(*ty, TypeInt);
}
<commit_msg>Rollup merge of #21983 - pnkfelix:eschew-untyped-arena-in-regions-mock-tcx, r=huonw<commit_after>// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

// Test a sample usage pattern for regions. Makes use of the
// following features:
//
// - Multiple lifetime parameters
// - Arenas

extern crate arena;
extern crate collections;
extern crate libc;

use TypeStructure::{TypeInt, TypeFunction};
use AstKind::{ExprInt, ExprVar, ExprLambda};
use arena::TypedArena;
use std::collections::HashMap;
use std::mem;

type Type<'tcx> = &'tcx TypeStructure<'tcx>;

#[derive(Copy, Debug)]
enum TypeStructure<'tcx> {
    TypeInt,
    TypeFunction(Type<'tcx>, Type<'tcx>),
}

impl<'tcx> PartialEq for TypeStructure<'tcx> {
    fn eq(&self, other: &TypeStructure<'tcx>) -> bool {
        match (*self, *other) {
            (TypeInt, TypeInt) => true,
            (TypeFunction(s_a, s_b), TypeFunction(o_a, o_b)) => *s_a == *o_a && *s_b == *o_b,
            _ => false
        }
    }
}

impl<'tcx> Eq for TypeStructure<'tcx> {}

type TyArena<'tcx> = TypedArena<TypeStructure<'tcx>>;
type AstArena<'ast> = TypedArena<AstStructure<'ast>>;

struct TypeContext<'tcx, 'ast> {
    ty_arena: &'tcx TyArena<'tcx>,
    types: Vec<Type<'tcx>> ,
    type_table: HashMap<NodeId, Type<'tcx>>,

    ast_arena: &'ast AstArena<'ast>,
    ast_counter: uint,
}

impl<'tcx,'ast> TypeContext<'tcx, 'ast> {
    fn new(ty_arena: &'tcx TyArena<'tcx>, ast_arena: &'ast AstArena<'ast>)
           -> TypeContext<'tcx, 'ast> {
        TypeContext { ty_arena: ty_arena,
                      types: Vec::new(),
                      type_table: HashMap::new(),

                      ast_arena: ast_arena,
                      ast_counter: 0 }
    }

    fn add_type(&mut self, s: TypeStructure<'tcx>) -> Type<'tcx> {
        for &ty in &self.types {
            if *ty == s {
                return ty;
            }
        }

        let ty = self.ty_arena.alloc(s);
        self.types.push(ty);
        ty
    }

    fn set_type(&mut self, id: NodeId, ty: Type<'tcx>) -> Type<'tcx> {
        self.type_table.insert(id, ty);
        ty
    }

    fn ast(&mut self, a: AstKind<'ast>) -> Ast<'ast> {
        let id = self.ast_counter;
        self.ast_counter += 1;
        self.ast_arena.alloc(AstStructure { id: NodeId {id:id}, kind: a })
    }
}

#[derive(Copy, PartialEq, Eq, Hash)]
struct NodeId {
    id: uint
}

type Ast<'ast> = &'ast AstStructure<'ast>;

#[derive(Copy)]
struct AstStructure<'ast> {
    id: NodeId,
    kind: AstKind<'ast>
}

#[derive(Copy)]
enum AstKind<'ast> {
    ExprInt,
    ExprVar(uint),
    ExprLambda(Ast<'ast>),
}

fn compute_types<'tcx,'ast>(tcx: &mut TypeContext<'tcx,'ast>,
                            ast: Ast<'ast>) -> Type<'tcx>
{
    match ast.kind {
        ExprInt | ExprVar(_) => {
            let ty = tcx.add_type(TypeInt);
            tcx.set_type(ast.id, ty)
        }
        ExprLambda(ast) => {
            let arg_ty = tcx.add_type(TypeInt);
            let body_ty = compute_types(tcx, ast);
            let lambda_ty = tcx.add_type(TypeFunction(arg_ty, body_ty));
            tcx.set_type(ast.id, lambda_ty)
        }
    }
}

pub fn main() {
    let ty_arena = TypedArena::new();
    let ast_arena = TypedArena::new();
    let mut tcx = TypeContext::new(&ty_arena, &ast_arena);
    let ast = tcx.ast(ExprInt);
    let ty = compute_types(&mut tcx, ast);
    assert_eq!(*ty, TypeInt);
}
<|endoftext|>


<commit_before>// A variation on cares-event-loop.rs.
//
// Here we:
//
// - Have the event loop be run by a `Resolver`, hiding away the event loop
// details from the writer of `main()`.
//
// - Transform the callback-based c-ares interface into a futures-style.
extern crate c_ares;
extern crate futures;
extern crate mio;
extern crate tokio_core;

use std::collections::HashSet;
use std::error::Error;
use std::sync::{
    Arc,
    Mutex,
};
use std::thread;
use std::time::Duration;

use self::futures::Future;

// The EventLoop will set up a mio::Poll and use it to wait for the following:
//
// -  messages telling it which file descriptors it should be interested in.
//    These file descriptors are then registered (or deregistered) with the
//    mio::Poll as required.
//
// -  events telling it that something has happened on one of these file
//    descriptors.  When this happens, it tells the c_ares::Channel about it.
//
// -  a message telling it to shut down.
struct EventLoop {
    poll: mio::Poll,
    msg_channel: mio::channel::Receiver<Message>,
    tracked_fds: HashSet<c_ares::Socket>,
    ares_channel: Arc<Mutex<c_ares::Channel>>,
    quit: bool,
}

// Messages for the event loop.
#[derive(Debug)]
enum Message {
    // 'Notify me when this file descriptor becomes readable, or writable'.
    // The first bool is for 'readable' and the second is for 'writable'.  It's
    // allowed to set both of these - or neither, meaning 'I am no longer
    // interested in this file descriptor'.
    RegisterInterest(c_ares::Socket, bool, bool),

    // 'Shut down'.
    ShutDown,
}

// A token identifying that the message channel has become available for reading.
//
// We use Token(fd) for file descriptors, so this relies on zero not being a
// valid file descriptor for c-ares to use.  Zero is stdin, so that's true.
const CHANNEL: mio::Token = mio::Token(0);

impl EventLoop {
    // Create a new event loop.
    pub fn new(
        ares_channel: Arc<Mutex<c_ares::Channel>>,
        rx: mio::channel::Receiver<Message>) -> EventLoop {
        let poll = mio::Poll::new().expect("Failed to create poll");
        poll.register(&rx, CHANNEL, mio::Ready::readable(), mio::PollOpt::edge())
            .expect("failed to register channel with poll");

        EventLoop {
            poll: poll,
            msg_channel: rx,
            tracked_fds: HashSet::<c_ares::Socket>::new(),
            ares_channel: ares_channel,
            quit: false,
        }
    }

    // Run the event loop.
    pub fn run(self) -> thread::JoinHandle<()> {
        thread::spawn(|| self.event_loop_thread())
    }

    // Event loop thread - waits for events, and handles them.
    fn event_loop_thread(mut self) {
        let mut events = mio::Events::with_capacity(16);
        loop {
            // Wait for something to happen.
            let timeout = Duration::from_millis(500);
            let results = self.poll
                .poll(&mut events, Some(timeout))
                .expect("poll failed");

            // Process whatever happened.
            match results {
                0 => {
                    // No events - must be a timeout.  Tell c-ares about it.
                    self.ares_channel.lock().unwrap().process_fd(
                        c_ares::SOCKET_BAD,
                        c_ares::SOCKET_BAD);
                },
                _ => {
                    // Process events.  One of them might have asked us to quit.
                    for event in &events {
                        self.handle_event(&event);
                        if self.quit { return }
                    }
                }
            }
        }
    }

    // Handle a single event.
    fn handle_event(&mut self, event: &mio::Event) {
        match event.token() {
            CHANNEL => {
                // The channel is readable.
                self.handle_messages()
            },

            mio::Token(fd) => {
                // Sockets became readable or writable - tell c-ares.
                let rfd = if event.kind().is_readable() {
                    fd as c_ares::Socket
                } else {
                    c_ares::SOCKET_BAD
                };
                let wfd = if event.kind().is_writable() {
                    fd as c_ares::Socket
                } else {
                    c_ares::SOCKET_BAD
                };
                self.ares_channel.lock().unwrap().process_fd(rfd, wfd);
            }
        }
    }

    // Process messages incoming on the channel.
    fn handle_messages(&mut self) {
        loop {
            match self.msg_channel.try_recv() {
                Ok(Message::RegisterInterest(fd, readable, writable)) => {
                    // Instruction to do something with a file descriptor.
                    let efd = mio::unix::EventedFd(&fd);
                    if !readable && !writable {
                        self.tracked_fds.remove(&fd);
                        self.poll
                            .deregister(&efd)
                            .expect("failed to deregister interest");
                    } else {
                        let token = mio::Token(fd as usize);
                        let mut interest = mio::Ready::none();
                        if readable { interest.insert(mio::Ready::readable()) }
                        if writable { interest.insert(mio::Ready::writable()) }
                        let register_result = if !self.tracked_fds.insert(fd) {
                            self.poll
                                .reregister(&efd, token, interest, mio::PollOpt::edge())
                        } else {
                            self.poll
                                .register(&efd, token, interest, mio::PollOpt::edge())
                        };
                        register_result.expect("failed to register interest");
                    }
                },

                Ok(Message::ShutDown) => {
                    // Instruction to shut down.
                    self.quit = true;
                    break
                },

                // No more instructions.
                Err(_) => break,
            }
        }
    }
}

// The Resolver is the interface by which users make DNS queries.
struct Resolver {
    ares_channel: Arc<Mutex<c_ares::Channel>>,
    event_loop_channel: mio::channel::Sender<Message>,
    event_loop_handle: Option<thread::JoinHandle<()>>,
}

impl Resolver {
    // Create a new Resolver.
    pub fn new() -> Resolver {
        // Whenever c-ares tells us what to do with a file descriptor, we'll
        // send that request along, in a message to the event loop thread.
        let (tx, rx) = mio::channel::channel();
        let tx_clone = tx.clone();
        let sock_callback =
            move |fd: c_ares::Socket, readable: bool, writable: bool| {
                let _ = tx_clone.send(
                    Message::RegisterInterest(fd, readable, writable));
            };

        // Create a c_ares::Channel.
        let mut options = c_ares::Options::new();
        options
            .set_socket_state_callback(sock_callback)
            .set_flags(c_ares::flags::STAYOPEN | c_ares::flags::EDNS)
            .set_timeout(500)
            .set_tries(3);
        let mut ares_channel = c_ares::Channel::new(options)
            .expect("Failed to create channel");
        ares_channel.set_servers(&["8.8.8.8"]).expect("Failed to set servers");
        let locked_channel = Arc::new(Mutex::new(ares_channel));

        // Create and run the event loop.
        let channel_clone = locked_channel.clone();
        let event_loop = EventLoop::new(channel_clone, rx);
        let handle = event_loop.run();

        // Return the Resolver.
        Resolver {
            ares_channel: locked_channel,
            event_loop_channel: tx,
            event_loop_handle: Some(handle),
        }
    }

    // A CNAME query.  Returns a future that will resolve to hold the result.
    pub fn query_cname(&self, name: &str)
        -> futures::BoxFuture<c_ares::CNameResults, c_ares::AresError> {
        let (c, p) = futures::oneshot();
        self.ares_channel.lock().unwrap().query_cname(name, move |result| {
            c.complete(result);
        });
        p.map_err(|_| c_ares::AresError::ECANCELLED)
            .and_then(futures::done)
            .boxed()
    }

    // An MX query.  Returns a future that will resolve to hold the result.
    pub fn query_mx(&self, name: &str)
        -> futures::BoxFuture<c_ares::MXResults, c_ares::AresError> {
        let (c, p) = futures::oneshot();
        self.ares_channel.lock().unwrap().query_mx(name, move |result| {
            c.complete(result);
        });
        p.map_err(|_| c_ares::AresError::ECANCELLED)
            .and_then(futures::done)
            .boxed()
    }

    // A NAPTR query.  Returns a future that will resolve to hold the result.
    pub fn query_naptr(&self, name: &str)
        -> futures::BoxFuture<c_ares::NAPTRResults, c_ares::AresError> {
        let (c, p) = futures::oneshot();
        self.ares_channel.lock().unwrap().query_naptr(name, move |result| {
            c.complete(result);
        });
        p.map_err(|_| c_ares::AresError::ECANCELLED)
            .and_then(futures::done)
            .boxed()
    }
}

impl Drop for Resolver {
    fn drop(&mut self) {
        // Shut down the event loop and wait for it to finish.
        self.event_loop_channel
            .send(Message::ShutDown)
            .expect("failed to request event loop to shut down");
        if let Some(handle) = self.event_loop_handle.take() {
           handle.join().expect("failed to shut down event loop");
        }
    }
}

fn print_cname_result(
    result: &Result<c_ares::CNameResults, c_ares::AresError>) {
    match *result {
        Err(ref e) => {
            println!("CNAME lookup failed with error '{}'", e.description());
        }
        Ok(ref cname_results) => {
            println!("Successful CNAME lookup...");
            println!("Hostname: {}", cname_results.hostname());
            for alias in cname_results.aliases() {
                println!("Alias: {}", alias);
            }
        }
    }
}

fn print_mx_results(result: &Result<c_ares::MXResults, c_ares::AresError>) {
    match *result {
        Err(ref e) => {
            println!("MX lookup failed with error '{}'", e.description());
        }
        Ok(ref mx_results) => {
            println!("Successful MX lookup...");
            for mx_result in mx_results {
                println!(
                    "host {}, priority {}",
                    mx_result.host(),
                    mx_result.priority());
            }
        }
    }
}

fn print_naptr_results(
    result: &Result<c_ares::NAPTRResults, c_ares::AresError>) {
    match *result {
        Err(ref e) => {
            println!("NAPTR lookup failed with error '{}'", e.description());
        }
        Ok(ref naptr_results) => {
            println!("Successful NAPTR lookup...");
            for naptr_result in naptr_results {
                println!("flags: {}", naptr_result.flags());
                println!("service name: {}", naptr_result.service_name());
                println!("regular expression: {}", naptr_result.reg_exp());
                println!(
                    "replacement pattern: {}",
                    naptr_result.replacement_pattern());
                println!("order: {}", naptr_result.order());
                println!("preference: {}", naptr_result.preference());
            }
        }
    }
}

pub fn main() {
    // Create a tokio event loop, and a Resolver.  Then make some requests.
    let mut l = tokio_core::reactor::Core::new().unwrap();
    let resolver = Resolver::new();
    let query = resolver.query_cname("dimbleby.github.io");
    let result = l.run(query);
    println!("");
    print_cname_result(&result);

    let query = resolver.query_mx("gmail.com");
    let result = l.run(query);
    println!("");
    print_mx_results(&result);

    let query = resolver.query_naptr("apple.com");
    let result = l.run(query);
    println!("");
    print_naptr_results(&result);
}
<commit_msg>variable name<commit_after>// A variation on cares-event-loop.rs.
//
// Here we:
//
// - Have the event loop be run by a `Resolver`, hiding away the event loop
// details from the writer of `main()`.
//
// - Transform the callback-based c-ares interface into a futures-style.
extern crate c_ares;
extern crate futures;
extern crate mio;
extern crate tokio_core;

use std::collections::HashSet;
use std::error::Error;
use std::sync::{
    Arc,
    Mutex,
};
use std::thread;
use std::time::Duration;

use self::futures::Future;

// The EventLoop will set up a mio::Poll and use it to wait for the following:
//
// -  messages telling it which file descriptors it should be interested in.
//    These file descriptors are then registered (or deregistered) with the
//    mio::Poll as required.
//
// -  events telling it that something has happened on one of these file
//    descriptors.  When this happens, it tells the c_ares::Channel about it.
//
// -  a message telling it to shut down.
struct EventLoop {
    poll: mio::Poll,
    msg_channel: mio::channel::Receiver<Message>,
    tracked_fds: HashSet<c_ares::Socket>,
    ares_channel: Arc<Mutex<c_ares::Channel>>,
    quit: bool,
}

// Messages for the event loop.
#[derive(Debug)]
enum Message {
    // 'Notify me when this file descriptor becomes readable, or writable'.
    // The first bool is for 'readable' and the second is for 'writable'.  It's
    // allowed to set both of these - or neither, meaning 'I am no longer
    // interested in this file descriptor'.
    RegisterInterest(c_ares::Socket, bool, bool),

    // 'Shut down'.
    ShutDown,
}

// A token identifying that the message channel has become available for reading.
//
// We use Token(fd) for file descriptors, so this relies on zero not being a
// valid file descriptor for c-ares to use.  Zero is stdin, so that's true.
const CHANNEL: mio::Token = mio::Token(0);

impl EventLoop {
    // Create a new event loop.
    pub fn new(
        ares_channel: Arc<Mutex<c_ares::Channel>>,
        rx: mio::channel::Receiver<Message>) -> EventLoop {
        let poll = mio::Poll::new().expect("Failed to create poll");
        poll.register(&rx, CHANNEL, mio::Ready::readable(), mio::PollOpt::edge())
            .expect("failed to register channel with poll");

        EventLoop {
            poll: poll,
            msg_channel: rx,
            tracked_fds: HashSet::<c_ares::Socket>::new(),
            ares_channel: ares_channel,
            quit: false,
        }
    }

    // Run the event loop.
    pub fn run(self) -> thread::JoinHandle<()> {
        thread::spawn(|| self.event_loop_thread())
    }

    // Event loop thread - waits for events, and handles them.
    fn event_loop_thread(mut self) {
        let mut events = mio::Events::with_capacity(16);
        loop {
            // Wait for something to happen.
            let timeout = Duration::from_millis(500);
            let results = self.poll
                .poll(&mut events, Some(timeout))
                .expect("poll failed");

            // Process whatever happened.
            match results {
                0 => {
                    // No events - must be a timeout.  Tell c-ares about it.
                    self.ares_channel.lock().unwrap().process_fd(
                        c_ares::SOCKET_BAD,
                        c_ares::SOCKET_BAD);
                },
                _ => {
                    // Process events.  One of them might have asked us to quit.
                    for event in &events {
                        self.handle_event(&event);
                        if self.quit { return }
                    }
                }
            }
        }
    }

    // Handle a single event.
    fn handle_event(&mut self, event: &mio::Event) {
        match event.token() {
            CHANNEL => {
                // The channel is readable.
                self.handle_messages()
            },

            mio::Token(fd) => {
                // Sockets became readable or writable - tell c-ares.
                let rfd = if event.kind().is_readable() {
                    fd as c_ares::Socket
                } else {
                    c_ares::SOCKET_BAD
                };
                let wfd = if event.kind().is_writable() {
                    fd as c_ares::Socket
                } else {
                    c_ares::SOCKET_BAD
                };
                self.ares_channel.lock().unwrap().process_fd(rfd, wfd);
            }
        }
    }

    // Process messages incoming on the channel.
    fn handle_messages(&mut self) {
        loop {
            match self.msg_channel.try_recv() {
                Ok(Message::RegisterInterest(fd, readable, writable)) => {
                    // Instruction to do something with a file descriptor.
                    let efd = mio::unix::EventedFd(&fd);
                    if !readable && !writable {
                        self.tracked_fds.remove(&fd);
                        self.poll
                            .deregister(&efd)
                            .expect("failed to deregister interest");
                    } else {
                        let token = mio::Token(fd as usize);
                        let mut interest = mio::Ready::none();
                        if readable { interest.insert(mio::Ready::readable()) }
                        if writable { interest.insert(mio::Ready::writable()) }
                        let register_result = if !self.tracked_fds.insert(fd) {
                            self.poll
                                .reregister(&efd, token, interest, mio::PollOpt::edge())
                        } else {
                            self.poll
                                .register(&efd, token, interest, mio::PollOpt::edge())
                        };
                        register_result.expect("failed to register interest");
                    }
                },

                Ok(Message::ShutDown) => {
                    // Instruction to shut down.
                    self.quit = true;
                    break
                },

                // No more instructions.
                Err(_) => break,
            }
        }
    }
}

// The Resolver is the interface by which users make DNS queries.
struct Resolver {
    ares_channel: Arc<Mutex<c_ares::Channel>>,
    event_loop_channel: mio::channel::Sender<Message>,
    event_loop_handle: Option<thread::JoinHandle<()>>,
}

impl Resolver {
    // Create a new Resolver.
    pub fn new() -> Resolver {
        // Whenever c-ares tells us what to do with a file descriptor, we'll
        // send that request along, in a message to the event loop thread.
        let (tx, rx) = mio::channel::channel();
        let tx_clone = tx.clone();
        let sock_callback =
            move |fd: c_ares::Socket, readable: bool, writable: bool| {
                let _ = tx_clone.send(
                    Message::RegisterInterest(fd, readable, writable));
            };

        // Create a c_ares::Channel.
        let mut options = c_ares::Options::new();
        options
            .set_socket_state_callback(sock_callback)
            .set_flags(c_ares::flags::STAYOPEN | c_ares::flags::EDNS)
            .set_timeout(500)
            .set_tries(3);
        let mut ares_channel = c_ares::Channel::new(options)
            .expect("Failed to create channel");
        ares_channel.set_servers(&["8.8.8.8"]).expect("Failed to set servers");
        let locked_channel = Arc::new(Mutex::new(ares_channel));

        // Create and run the event loop.
        let channel_clone = locked_channel.clone();
        let event_loop = EventLoop::new(channel_clone, rx);
        let handle = event_loop.run();

        // Return the Resolver.
        Resolver {
            ares_channel: locked_channel,
            event_loop_channel: tx,
            event_loop_handle: Some(handle),
        }
    }

    // A CNAME query.  Returns a future that will resolve to hold the result.
    pub fn query_cname(&self, name: &str)
        -> futures::BoxFuture<c_ares::CNameResults, c_ares::AresError> {
        let (c, p) = futures::oneshot();
        self.ares_channel.lock().unwrap().query_cname(name, move |result| {
            c.complete(result);
        });
        p.map_err(|_| c_ares::AresError::ECANCELLED)
            .and_then(futures::done)
            .boxed()
    }

    // An MX query.  Returns a future that will resolve to hold the result.
    pub fn query_mx(&self, name: &str)
        -> futures::BoxFuture<c_ares::MXResults, c_ares::AresError> {
        let (c, p) = futures::oneshot();
        self.ares_channel.lock().unwrap().query_mx(name, move |result| {
            c.complete(result);
        });
        p.map_err(|_| c_ares::AresError::ECANCELLED)
            .and_then(futures::done)
            .boxed()
    }

    // A NAPTR query.  Returns a future that will resolve to hold the result.
    pub fn query_naptr(&self, name: &str)
        -> futures::BoxFuture<c_ares::NAPTRResults, c_ares::AresError> {
        let (c, p) = futures::oneshot();
        self.ares_channel.lock().unwrap().query_naptr(name, move |result| {
            c.complete(result);
        });
        p.map_err(|_| c_ares::AresError::ECANCELLED)
            .and_then(futures::done)
            .boxed()
    }
}

impl Drop for Resolver {
    fn drop(&mut self) {
        // Shut down the event loop and wait for it to finish.
        self.event_loop_channel
            .send(Message::ShutDown)
            .expect("failed to request event loop to shut down");
        if let Some(handle) = self.event_loop_handle.take() {
           handle.join().expect("failed to shut down event loop");
        }
    }
}

fn print_cname_result(
    result: &Result<c_ares::CNameResults, c_ares::AresError>) {
    match *result {
        Err(ref e) => {
            println!("CNAME lookup failed with error '{}'", e.description());
        }
        Ok(ref cname_results) => {
            println!("Successful CNAME lookup...");
            println!("Hostname: {}", cname_results.hostname());
            for alias in cname_results.aliases() {
                println!("Alias: {}", alias);
            }
        }
    }
}

fn print_mx_results(result: &Result<c_ares::MXResults, c_ares::AresError>) {
    match *result {
        Err(ref e) => {
            println!("MX lookup failed with error '{}'", e.description());
        }
        Ok(ref mx_results) => {
            println!("Successful MX lookup...");
            for mx_result in mx_results {
                println!(
                    "host {}, priority {}",
                    mx_result.host(),
                    mx_result.priority());
            }
        }
    }
}

fn print_naptr_results(
    result: &Result<c_ares::NAPTRResults, c_ares::AresError>) {
    match *result {
        Err(ref e) => {
            println!("NAPTR lookup failed with error '{}'", e.description());
        }
        Ok(ref naptr_results) => {
            println!("Successful NAPTR lookup...");
            for naptr_result in naptr_results {
                println!("flags: {}", naptr_result.flags());
                println!("service name: {}", naptr_result.service_name());
                println!("regular expression: {}", naptr_result.reg_exp());
                println!(
                    "replacement pattern: {}",
                    naptr_result.replacement_pattern());
                println!("order: {}", naptr_result.order());
                println!("preference: {}", naptr_result.preference());
            }
        }
    }
}

pub fn main() {
    // Create a tokio event loop, and a Resolver.  Then make some requests.
    let mut event_loop = tokio_core::reactor::Core::new().unwrap();
    let resolver = Resolver::new();
    let query = resolver.query_cname("dimbleby.github.io");
    let result = event_loop.run(query);
    println!("");
    print_cname_result(&result);

    let query = resolver.query_mx("gmail.com");
    let result = event_loop.run(query);
    println!("");
    print_mx_results(&result);

    let query = resolver.query_naptr("apple.com");
    let result = event_loop.run(query);
    println!("");
    print_naptr_results(&result);
}
<|endoftext|>