<commit_before>#![warn(bad_style)]
#![warn(missing_copy_implementations)]
#![warn(missing_debug_implementations)]
// #![warn(missing_docs)]
#![warn(trivial_casts)]
#![warn(trivial_numeric_casts)]
#![warn(unused)]
#![warn(unused_extern_crates)]
#![warn(unused_import_braces)]
#![warn(unused_qualifications)]
#![warn(unused_results)]

extern crate ansi_term;
extern crate argparse;
extern crate rustc_test;
extern crate slsr_core;
extern crate slsr_solver;

use std::{io, process};
use std::io::prelude::*;

use error::AppResult;
use parse_arg::Config;

mod error;
mod parse_arg;
mod pprint;

mod solve {
    use std::io;
    use std::fs::File;
    use std::io::prelude::*;

    use slsr_core::puzzle::Puzzle;
    use slsr_solver::{self as solver, Solutions};

    use error::AppResult;
    use parse_arg::{OutputMode, SolveConfig};
    use pprint;

    pub fn run(config: SolveConfig) -> AppResult<()> {
        if config.input_files.is_empty() {
            try!(solve(&config, &mut io::stdin()));
        } else {
            for file in &config.input_files {
                let mut f = try!(File::open(file));
                try!(solve(&config, &mut f));
            }
        }

        Ok(())
    }

    fn solve<T: Read>(config: &SolveConfig, input: &mut T) -> AppResult<()> {
        let mut buf = String::new();
        let _ = try!(input.read_to_string(&mut buf));
        let puzzle = try!(buf.parse::<Puzzle>());

        if config.derive_all {
            for solution in try!(Solutions::new(&puzzle)) {
                try!(output(&config, solution));
            }
        } else {
            let solution = try!(solver::solve(&puzzle));
            try!(output(&config, solution));
        }

        Ok(())
    }

    fn output(config: &SolveConfig, solution: Puzzle) -> io::Result<()> {
        match config.output_mode {
            OutputMode::Pretty(conf) => {
                try!(pprint::print(&conf, &solution));
            }
            OutputMode::Raw => {
                print!("{}", solution.to_string());
            }
            OutputMode::None => {}
        }

        Ok(())
    }
}

mod test {
    use std::fs::File;
    use std::io::prelude::*;
    use rustc_test::{self as test, DynTestFn, DynTestName, ShouldPanic, TestDesc, TestDescAndFn};

    use slsr_core::puzzle::Puzzle;
    use slsr_solver::{self as solver, Solutions};

    use error::AppResult;
    use parse_arg::TestConfig;

    pub fn run(config: TestConfig) -> AppResult<()> {
        let derive_all = config.derive_all;
        let tests = config.input_files
                          .into_iter()
                          .map(|input| {
                              TestDescAndFn {
                                  desc: TestDesc {
                                      name: DynTestName(input.clone()),
                                      ignore: false,
                                      should_panic: ShouldPanic::No,
                                  },
                                  testfn: DynTestFn(Box::new(move || {
                                      solve(&input, derive_all).unwrap()
                                  })),
                              }
                          })
                          .collect();

        test::test_main(&["".to_string()], tests);

        Ok(())
    }

    fn solve(file: &str, derive_all: bool) -> AppResult<()> {
        let mut buf = String::new();
        let _ = try!(try!(File::open(file)).read_to_string(&mut buf));
        let puzzle = try!(buf.parse::<Puzzle>());

        if derive_all {
            for solution in try!(Solutions::new(&puzzle)) {
                let _ = test::black_box(solution);
            }
        } else {
            let _ = test::black_box(try!(solver::solve(&puzzle)));
        }

        Ok(())
    }
}

mod bench {
    use std::fs::File;
    use std::io::prelude::*;
    use rustc_test::{self as test, DynBenchFn, DynTestName, ShouldPanic, TestDesc, TestDescAndFn};

    use slsr_core::puzzle::Puzzle;
    use slsr_solver::{self as solver, Solutions};

    use error::AppResult;
    use parse_arg::BenchConfig;

    pub fn run(config: BenchConfig) -> AppResult<()> {
        let derive_all = config.derive_all;
        let tests = config.input_files
                          .into_iter()
                          .map(|input| {
                              TestDescAndFn {
                                  desc: TestDesc {
                                      name: DynTestName(input.clone()),
                                      ignore: false,
                                      should_panic: ShouldPanic::No,
                                  },
                                  testfn: DynBenchFn(Box::new(move |bencher| {
                                      bencher.iter(|| {
                                          solve(&input, derive_all)
                                      })
                                  })),
                              }
                          })
                          .collect();

        test::test_main(&["".to_string(), "--bench".to_string()], tests);

        Ok(())
    }

    fn solve(file: &str, derive_all: bool) -> AppResult<()> {
        let mut buf = String::new();
        let _ = try!(try!(File::open(file)).read_to_string(&mut buf));
        let puzzle = try!(buf.parse::<Puzzle>());

        if derive_all {
            for solution in try!(Solutions::new(&puzzle)) {
                let _ = test::black_box(solution);
            }
        } else {
            let _ = test::black_box(try!(solver::solve(&puzzle)));
        }

        Ok(())
    }
}

fn run() -> AppResult<()> {
    match Config::parse() {
        Config::Solve(config) => solve::run(config),
        Config::Test(config) => test::run(config),
        Config::Bench(config) => bench::run(config),
    }
}

fn main() {
    if let Err(e) = run() {
        let _ = writeln!(&mut io::stderr(), "{}", e);
        process::exit(255);
    }
}
<commit_msg>cli: run rustfmt<commit_after>#![warn(bad_style)]
#![warn(missing_copy_implementations)]
#![warn(missing_debug_implementations)]
// #![warn(missing_docs)]
#![warn(trivial_casts)]
#![warn(trivial_numeric_casts)]
#![warn(unused)]
#![warn(unused_extern_crates)]
#![warn(unused_import_braces)]
#![warn(unused_qualifications)]
#![warn(unused_results)]

extern crate ansi_term;
extern crate argparse;
extern crate rustc_test;
extern crate slsr_core;
extern crate slsr_solver;

use std::{io, process};
use std::io::prelude::*;

use error::AppResult;
use parse_arg::Config;

mod error;
mod parse_arg;
mod pprint;

mod solve {
    use std::io;
    use std::fs::File;
    use std::io::prelude::*;

    use slsr_core::puzzle::Puzzle;
    use slsr_solver::{self as solver, Solutions};

    use error::AppResult;
    use parse_arg::{OutputMode, SolveConfig};
    use pprint;

    pub fn run(config: SolveConfig) -> AppResult<()> {
        if config.input_files.is_empty() {
            try!(solve(&config, &mut io::stdin()));
        } else {
            for file in &config.input_files {
                let mut f = try!(File::open(file));
                try!(solve(&config, &mut f));
            }
        }

        Ok(())
    }

    fn solve<T: Read>(config: &SolveConfig, input: &mut T) -> AppResult<()> {
        let mut buf = String::new();
        let _ = try!(input.read_to_string(&mut buf));
        let puzzle = try!(buf.parse::<Puzzle>());

        if config.derive_all {
            for solution in try!(Solutions::new(&puzzle)) {
                try!(output(&config, solution));
            }
        } else {
            let solution = try!(solver::solve(&puzzle));
            try!(output(&config, solution));
        }

        Ok(())
    }

    fn output(config: &SolveConfig, solution: Puzzle) -> io::Result<()> {
        match config.output_mode {
            OutputMode::Pretty(conf) => {
                try!(pprint::print(&conf, &solution));
            }
            OutputMode::Raw => {
                print!("{}", solution.to_string());
            }
            OutputMode::None => {}
        }

        Ok(())
    }
}

mod test {
    use std::fs::File;
    use std::io::prelude::*;
    use rustc_test::{self as test, DynTestFn, DynTestName, ShouldPanic, TestDesc, TestDescAndFn};

    use slsr_core::puzzle::Puzzle;
    use slsr_solver::{self as solver, Solutions};

    use error::AppResult;
    use parse_arg::TestConfig;

    pub fn run(config: TestConfig) -> AppResult<()> {
        let derive_all = config.derive_all;
        let tests = config.input_files
                          .into_iter()
                          .map(|input| {
                              TestDescAndFn {
                                  desc: TestDesc {
                                      name: DynTestName(input.clone()),
                                      ignore: false,
                                      should_panic: ShouldPanic::No,
                                  },
                                  testfn: DynTestFn(Box::new(move || {
                                      solve(&input, derive_all).unwrap()
                                  })),
                              }
                          })
                          .collect();

        test::test_main(&["".to_string()], tests);

        Ok(())
    }

    fn solve(file: &str, derive_all: bool) -> AppResult<()> {
        let mut buf = String::new();
        let _ = try!(try!(File::open(file)).read_to_string(&mut buf));
        let puzzle = try!(buf.parse::<Puzzle>());

        if derive_all {
            for solution in try!(Solutions::new(&puzzle)) {
                let _ = test::black_box(solution);
            }
        } else {
            let _ = test::black_box(try!(solver::solve(&puzzle)));
        }

        Ok(())
    }
}

mod bench {
    use std::fs::File;
    use std::io::prelude::*;
    use rustc_test::{self as test, DynBenchFn, DynTestName, ShouldPanic, TestDesc, TestDescAndFn};

    use slsr_core::puzzle::Puzzle;
    use slsr_solver::{self as solver, Solutions};

    use error::AppResult;
    use parse_arg::BenchConfig;

    pub fn run(config: BenchConfig) -> AppResult<()> {
        let derive_all = config.derive_all;
        let tests = config.input_files
                          .into_iter()
                          .map(|input| {
                              TestDescAndFn {
                                  desc: TestDesc {
                                      name: DynTestName(input.clone()),
                                      ignore: false,
                                      should_panic: ShouldPanic::No,
                                  },
                                  testfn: DynBenchFn(Box::new(move |bencher| {
                                      bencher.iter(|| solve(&input, derive_all))
                                  })),
                              }
                          })
                          .collect();

        test::test_main(&["".to_string(), "--bench".to_string()], tests);

        Ok(())
    }

    fn solve(file: &str, derive_all: bool) -> AppResult<()> {
        let mut buf = String::new();
        let _ = try!(try!(File::open(file)).read_to_string(&mut buf));
        let puzzle = try!(buf.parse::<Puzzle>());

        if derive_all {
            for solution in try!(Solutions::new(&puzzle)) {
                let _ = test::black_box(solution);
            }
        } else {
            let _ = test::black_box(try!(solver::solve(&puzzle)));
        }

        Ok(())
    }
}

fn run() -> AppResult<()> {
    match Config::parse() {
        Config::Solve(config) => solve::run(config),
        Config::Test(config) => test::run(config),
        Config::Bench(config) => bench::run(config),
    }
}

fn main() {
    if let Err(e) = run() {
        let _ = writeln!(&mut io::stderr(), "{}", e);
        process::exit(255);
    }
}
<|endoftext|>


<commit_before>#![crate_type="rlib"]

pub static C: u32 = 0-1;
<commit_msg>Remove treat-err-as-bug err test from run-make-fulldeps<commit_after><|endoftext|>


<commit_before>#![crate_name = "docopt_macros"]
#![crate_type = "dylib"]

#![feature(collections, core, plugin_registrar, quote, rustc_private)]

//! This crate defines the `docopt!` macro. It is documented in the
//! documentation of the `docopt` crate.

extern crate syntax;
extern crate rustc;
extern crate docopt;

use std::collections::HashMap;

use rustc::plugin::Registry;
use syntax::ast;
use syntax::codemap;
use syntax::ext::base::{ExtCtxt, MacResult, MacItems, DummyResult};
use syntax::ext::build::AstBuilder;
use syntax::fold::Folder;
use syntax::owned_slice::OwnedSlice;
use syntax::parse::common::SeqSep;
use syntax::parse::parser::Parser;
use syntax::parse::token;
use syntax::print::pprust;
use syntax::ptr::P;

use docopt::{Docopt, ArgvMap};
use docopt::parse::{Options, Atom, Positional, Zero, One};

#[plugin_registrar]
pub fn plugin_registrar(reg: &mut Registry) {
    reg.register_macro("docopt", expand);
}

fn expand(cx: &mut ExtCtxt, span: codemap::Span, tts: &[ast::TokenTree])
         -> Box<MacResult+'static> {
    let parsed = match MacParser::new(cx, tts).parse() {
        Ok(parsed) => parsed,
        Err(_) => return DummyResult::any(span),
    };
    parsed.items(cx)
}

/// Parsed corresponds to the result of parsing a `docopt` macro call.
/// It can be used to write a corresponding struct.
struct Parsed {
    struct_info: StructInfo,
    doc: Docopt,
    /// Overrided type annotations for struct members. May be empty.
    /// When a type annotation for an atom doesn't exist, then one is
    /// inferred automatically. It is one of: `bool`, `uint`, `String` or
    /// `Vec<String>`.
    types: HashMap<Atom, P<ast::Ty>>,
}

impl Parsed {
    /// Returns a macro result suitable for expansion.
    /// Contains two items: one for the struct and one for the struct impls.
    fn items(&self, cx: &ExtCtxt) -> Box<MacResult+'static> {
        let mut its = vec!();
        its.push(self.struct_decl(cx));

        let struct_name = self.struct_info.name;
        let full_doc = &*self.doc.parser().full_doc;
        its.push(quote_item!(cx,
            impl $struct_name {
                #[allow(dead_code)]
                fn docopt() -> docopt::Docopt {
                    // The unwrap is justified here because this code
                    // gen only happens if the Docopt usage string is valid.
                    docopt::Docopt::new($full_doc).unwrap()
                }
            }
        ).unwrap());
        MacItems::new(its.into_iter())
    }

    /// Returns an item for the struct definition.
    fn struct_decl(&self, cx: &ExtCtxt) -> P<ast::Item> {
        let name = self.struct_info.name.clone();
        let vis = if self.struct_info.public { ast::Public }
                  else { ast::Inherited };
        let def = ast::StructDef {
            fields: self.struct_fields(cx),
            ctor_id: None
        };

        let mut traits = vec!["RustcDecodable".to_string()];
        traits.push_all(&*self.struct_info.deriving);
        let attrs = vec![attribute(cx, "allow", vec!["non_snake_case"]),
                         attribute(cx, "derive", traits)];

        let st = cx.item_struct(codemap::DUMMY_SP, name.clone(), def);
        cx.item(codemap::DUMMY_SP, name, attrs, st.node.clone()).map(|mut it| {
            it.vis = vis;
            it
        })
    }

    /// Returns a list of fields for the struct definition.
    /// Handles type annotations.
    fn struct_fields(&self, cx: &ExtCtxt) -> Vec<ast::StructField> {
        let mut fields: Vec<ast::StructField> = vec!();
        for (atom, opts) in self.doc.parser().descs.iter() {
            let name = ArgvMap::key_to_struct_field(&*atom.to_string());
            let ty = match self.types.get(atom) {
                None => self.pat_type(cx, atom, opts),
                Some(ty) => ty.clone(),
            };
            fields.push(self.mk_struct_field(&*name, ty));
        }
        fields
    }

    /// Returns an inferred type for a usage pattern.
    /// This is only invoked when a type annotation is not present.
    fn pat_type(&self, cx: &ExtCtxt, atom: &Atom, opts: &Options) -> P<ast::Ty> {
        let sp = codemap::DUMMY_SP;
        match (opts.repeats, &opts.arg) {
            (false, &Zero) => {
                match atom {
                    &Positional(_) => cx.ty_ident(sp, ident("String")),
                    _ => cx.ty_ident(sp, ident("bool")),
                }
            }
            (true, &Zero) => {
                match atom {
                    &Positional(_) => ty_vec_string(cx),
                    _ => cx.ty_ident(sp, ident("uint")),
                }
            }
            (false, &One(_)) => cx.ty_ident(sp, ident("String")),
            (true, &One(_)) => ty_vec_string(cx),
        }
    }

    /// Creates a struct field from a member name and type.
    fn mk_struct_field(&self, name: &str, ty: P<ast::Ty>) -> ast::StructField {
        codemap::dummy_spanned(ast::StructField_ {
            kind: ast::NamedField(ident(name), ast::Public),
            id: ast::DUMMY_NODE_ID,
            ty: ty,
            attrs: vec!(),
        })
    }
}

/// State for parsing a `docopt` macro invocation.
struct MacParser<'a, 'b:'a> {
    cx: &'a mut ExtCtxt<'b>,
    p: Parser<'b>,
}

impl<'a, 'b> MacParser<'a, 'b> {
    fn new(cx: &'a mut ExtCtxt<'b>, tts: &[ast::TokenTree]) -> MacParser<'a, 'b> {
        let p = cx.new_parser_from_tts(tts);
        MacParser { cx: cx, p: p }
    }

    /// Main entry point for parsing arguments to `docopt` macro.
    /// First looks for an identifier for the struct name.
    /// Second, a string containing the docopt usage patterns.
    /// Third, an optional list of type annotations.
    fn parse(&mut self) -> Result<Parsed, ()> {
        if self.p.token == token::Eof {
            self.cx.span_err(self.cx.call_site(), "macro expects arguments");
            return Err(());
        }
        let struct_info = try!(self.parse_struct_info());
        let docstr = try!(self.parse_str());

        let sep = SeqSep {
            sep: Some(token::Comma),
            trailing_sep_allowed: true,
        };
        let types = self.p.parse_seq_to_end(
            &token::Eof, sep, |p| MacParser::parse_type_annotation(p)
        ).into_iter()
         .map(|(ident, ty)| {
             let field_name = token::get_ident(ident).to_string();
             let key = ArgvMap::struct_field_to_key(&*field_name);
             (Atom::new(&*key), ty)
          })
         .collect::<HashMap<Atom, P<ast::Ty>>>();
        self.p.expect(&token::Eof);

        // This config does not matter because we're only asking for the
        // usage patterns in the Docopt string. The configuration does not
        // affect the retrieval of usage patterns.
        let doc = match Docopt::new(docstr) {
            Ok(doc) => doc,
            Err(err) => {
                self.cx.span_err(self.cx.call_site(),
                                 &*format!("Invalid Docopt usage: {}", err));
                return Err(());
            }
        };
        Ok(Parsed {
            struct_info: struct_info,
            doc: doc,
            types: types,
        })
    }

    /// Parses a single string literal. On failure, an error is logged and
    /// unit is returned.
    fn parse_str(&mut self) -> Result<String, ()> {
        fn lit_is_str(lit: &ast::Lit) -> bool {
            match lit.node {
                ast::LitStr(_, _) => true,
                _ => false,
            }
        }
        fn lit_to_string(lit: &ast::Lit) -> String {
            match lit.node {
                ast::LitStr(ref s, _) => s.to_string(),
                _ => panic!("BUG: expected string literal"),
            }
        }
        let exp = self.cx.expander().fold_expr(self.p.parse_expr());
        let s = match exp.node {
            ast::ExprLit(ref lit) if lit_is_str(&**lit) => {
                lit_to_string(&**lit)
            }
            _ => {
                let err = format!("Expected string literal but got {}",
                                  pprust::expr_to_string(&*exp));
                self.cx.span_err(exp.span, &*err);
                return Err(());
            }
        };
        self.p.bump();
        Ok(s)
    }

    /// Parses a type annotation in a `docopt` invocation of the form
    /// `ident: Ty`.
    /// Note that this is a static method as it is used as a HOF.
    fn parse_type_annotation(p: &mut Parser) -> (ast::Ident, P<ast::Ty>) {
        let ident = p.parse_ident();
        p.expect(&token::Colon);
        let ty = p.parse_ty();
        (ident, ty)
    }

    /// Parses struct information, like visibility, name and deriving.
    fn parse_struct_info(&mut self) -> Result<StructInfo, ()> {
        let public = self.p.eat_keyword(token::keywords::Pub);
        let mut info = StructInfo {
            name: self.p.parse_ident(),
            public: public,
            deriving: vec![],
        };
        if self.p.eat(&token::Comma) { return Ok(info); }
        let deriving = self.p.parse_ident();
        if deriving.as_str() != "derive" {
            let err = format!("Expected 'derive' keyword but got '{}'",
                              deriving);
            self.cx.span_err(self.cx.call_site(), &*err);
            return Err(());
        }
        while !self.p.eat(&token::Comma) {
            info.deriving.push(self.p.parse_ident().as_str().to_string());
        }
        Ok(info)
    }
}

struct StructInfo {
    name: ast::Ident,
    public: bool,
    deriving: Vec<String>,
}

// Convenience functions for building intermediate values.

fn ident(s: &str) -> ast::Ident {
    ast::Ident::new(token::intern(s))
}

fn attribute<S, T>(cx: &ExtCtxt, name: S, items: Vec<T>) -> ast::Attribute
            where S: Str, T: Str {
    let sp = codemap::DUMMY_SP;
    let its = items.into_iter().map(|s| meta_item(cx, s.as_slice())).collect();
    let mi = cx.meta_list(sp, intern(name.as_slice()), its);
    cx.attribute(sp, mi)
}

fn meta_item(cx: &ExtCtxt, s: &str) -> P<ast::MetaItem> {
    cx.meta_word(codemap::DUMMY_SP, intern(s))
}

fn intern(s: &str) -> token::InternedString {
    token::intern_and_get_ident(s)
}

fn ty_vec_string(cx: &ExtCtxt) -> P<ast::Ty> {
    let sp = codemap::DUMMY_SP;
    let tystr = ast::AngleBracketedParameterData {
        lifetimes: vec![],
        types: OwnedSlice::from_vec(vec![cx.ty_ident(sp, ident("String"))]),
        bindings: OwnedSlice::empty(),
    };
    cx.ty_path(ast::Path {
        span: sp,
        global: false,
        segments: vec![ast::PathSegment {
            identifier: ident("Vec"),
            parameters: ast::PathParameters::AngleBracketedParameters(tystr),
        }]
    })
}
<commit_msg>rustup for compiler plugin<commit_after>#![crate_name = "docopt_macros"]
#![crate_type = "dylib"]

#![feature(collections, core, plugin_registrar, quote, rustc_private)]

//! This crate defines the `docopt!` macro. It is documented in the
//! documentation of the `docopt` crate.

extern crate syntax;
extern crate rustc;
extern crate docopt;

use std::collections::HashMap;

use rustc::plugin::Registry;
use syntax::{ast, codemap};
use syntax::ext::base::{ExtCtxt, MacResult, MacEager, DummyResult};
use syntax::ext::build::AstBuilder;
use syntax::fold::Folder;
use syntax::owned_slice::OwnedSlice;
use syntax::parse::common::SeqSep;
use syntax::parse::parser::Parser;
use syntax::parse::token;
use syntax::print::pprust;
use syntax::ptr::P;
use syntax::util::small_vector::SmallVector;

use docopt::{Docopt, ArgvMap};
use docopt::parse::{Options, Atom, Positional, Zero, One};

#[plugin_registrar]
pub fn plugin_registrar(reg: &mut Registry) {
    reg.register_macro("docopt", expand);
}

fn expand(cx: &mut ExtCtxt, span: codemap::Span, tts: &[ast::TokenTree])
         -> Box<MacResult+'static> {
    let parsed = match MacParser::new(cx, tts).parse() {
        Ok(parsed) => parsed,
        Err(_) => return DummyResult::any(span),
    };
    parsed.items(cx)
}

/// Parsed corresponds to the result of parsing a `docopt` macro call.
/// It can be used to write a corresponding struct.
struct Parsed {
    struct_info: StructInfo,
    doc: Docopt,
    /// Overrided type annotations for struct members. May be empty.
    /// When a type annotation for an atom doesn't exist, then one is
    /// inferred automatically. It is one of: `bool`, `uint`, `String` or
    /// `Vec<String>`.
    types: HashMap<Atom, P<ast::Ty>>,
}

impl Parsed {
    /// Returns a macro result suitable for expansion.
    /// Contains two items: one for the struct and one for the struct impls.
    fn items(&self, cx: &ExtCtxt) -> Box<MacResult+'static> {
        let mut its = vec!();
        its.push(self.struct_decl(cx));

        let struct_name = self.struct_info.name;
        let full_doc = &*self.doc.parser().full_doc;
        its.push(quote_item!(cx,
            impl $struct_name {
                #[allow(dead_code)]
                fn docopt() -> docopt::Docopt {
                    // The unwrap is justified here because this code
                    // gen only happens if the Docopt usage string is valid.
                    docopt::Docopt::new($full_doc).unwrap()
                }
            }
        ).unwrap());
        MacEager::items(SmallVector::many(its))
    }

    /// Returns an item for the struct definition.
    fn struct_decl(&self, cx: &ExtCtxt) -> P<ast::Item> {
        let name = self.struct_info.name.clone();
        let vis = if self.struct_info.public { ast::Public }
                  else { ast::Inherited };
        let def = ast::StructDef {
            fields: self.struct_fields(cx),
            ctor_id: None
        };

        let mut traits = vec!["RustcDecodable".to_string()];
        traits.push_all(&*self.struct_info.deriving);
        let attrs = vec![attribute(cx, "allow", vec!["non_snake_case"]),
                         attribute(cx, "derive", traits)];

        let st = cx.item_struct(codemap::DUMMY_SP, name.clone(), def);
        cx.item(codemap::DUMMY_SP, name, attrs, st.node.clone()).map(|mut it| {
            it.vis = vis;
            it
        })
    }

    /// Returns a list of fields for the struct definition.
    /// Handles type annotations.
    fn struct_fields(&self, cx: &ExtCtxt) -> Vec<ast::StructField> {
        let mut fields: Vec<ast::StructField> = vec!();
        for (atom, opts) in self.doc.parser().descs.iter() {
            let name = ArgvMap::key_to_struct_field(&*atom.to_string());
            let ty = match self.types.get(atom) {
                None => self.pat_type(cx, atom, opts),
                Some(ty) => ty.clone(),
            };
            fields.push(self.mk_struct_field(&*name, ty));
        }
        fields
    }

    /// Returns an inferred type for a usage pattern.
    /// This is only invoked when a type annotation is not present.
    fn pat_type(&self, cx: &ExtCtxt, atom: &Atom, opts: &Options) -> P<ast::Ty> {
        let sp = codemap::DUMMY_SP;
        match (opts.repeats, &opts.arg) {
            (false, &Zero) => {
                match atom {
                    &Positional(_) => cx.ty_ident(sp, ident("String")),
                    _ => cx.ty_ident(sp, ident("bool")),
                }
            }
            (true, &Zero) => {
                match atom {
                    &Positional(_) => ty_vec_string(cx),
                    _ => cx.ty_ident(sp, ident("uint")),
                }
            }
            (false, &One(_)) => cx.ty_ident(sp, ident("String")),
            (true, &One(_)) => ty_vec_string(cx),
        }
    }

    /// Creates a struct field from a member name and type.
    fn mk_struct_field(&self, name: &str, ty: P<ast::Ty>) -> ast::StructField {
        codemap::dummy_spanned(ast::StructField_ {
            kind: ast::NamedField(ident(name), ast::Public),
            id: ast::DUMMY_NODE_ID,
            ty: ty,
            attrs: vec!(),
        })
    }
}

/// State for parsing a `docopt` macro invocation.
struct MacParser<'a, 'b:'a> {
    cx: &'a mut ExtCtxt<'b>,
    p: Parser<'b>,
}

impl<'a, 'b> MacParser<'a, 'b> {
    fn new(cx: &'a mut ExtCtxt<'b>, tts: &[ast::TokenTree]) -> MacParser<'a, 'b> {
        let p = cx.new_parser_from_tts(tts);
        MacParser { cx: cx, p: p }
    }

    /// Main entry point for parsing arguments to `docopt` macro.
    /// First looks for an identifier for the struct name.
    /// Second, a string containing the docopt usage patterns.
    /// Third, an optional list of type annotations.
    fn parse(&mut self) -> Result<Parsed, ()> {
        if self.p.token == token::Eof {
            self.cx.span_err(self.cx.call_site(), "macro expects arguments");
            return Err(());
        }
        let struct_info = try!(self.parse_struct_info());
        let docstr = try!(self.parse_str());

        let sep = SeqSep {
            sep: Some(token::Comma),
            trailing_sep_allowed: true,
        };
        let types = self.p.parse_seq_to_end(
            &token::Eof, sep, |p| MacParser::parse_type_annotation(p)
        ).into_iter()
         .map(|(ident, ty)| {
             let field_name = token::get_ident(ident).to_string();
             let key = ArgvMap::struct_field_to_key(&*field_name);
             (Atom::new(&*key), ty)
          })
         .collect::<HashMap<Atom, P<ast::Ty>>>();
        self.p.expect(&token::Eof);

        // This config does not matter because we're only asking for the
        // usage patterns in the Docopt string. The configuration does not
        // affect the retrieval of usage patterns.
        let doc = match Docopt::new(docstr) {
            Ok(doc) => doc,
            Err(err) => {
                self.cx.span_err(self.cx.call_site(),
                                 &*format!("Invalid Docopt usage: {}", err));
                return Err(());
            }
        };
        Ok(Parsed {
            struct_info: struct_info,
            doc: doc,
            types: types,
        })
    }

    /// Parses a single string literal. On failure, an error is logged and
    /// unit is returned.
    fn parse_str(&mut self) -> Result<String, ()> {
        fn lit_is_str(lit: &ast::Lit) -> bool {
            match lit.node {
                ast::LitStr(_, _) => true,
                _ => false,
            }
        }
        fn lit_to_string(lit: &ast::Lit) -> String {
            match lit.node {
                ast::LitStr(ref s, _) => s.to_string(),
                _ => panic!("BUG: expected string literal"),
            }
        }
        let exp = self.cx.expander().fold_expr(self.p.parse_expr());
        let s = match exp.node {
            ast::ExprLit(ref lit) if lit_is_str(&**lit) => {
                lit_to_string(&**lit)
            }
            _ => {
                let err = format!("Expected string literal but got {}",
                                  pprust::expr_to_string(&*exp));
                self.cx.span_err(exp.span, &*err);
                return Err(());
            }
        };
        self.p.bump();
        Ok(s)
    }

    /// Parses a type annotation in a `docopt` invocation of the form
    /// `ident: Ty`.
    /// Note that this is a static method as it is used as a HOF.
    fn parse_type_annotation(p: &mut Parser) -> (ast::Ident, P<ast::Ty>) {
        let ident = p.parse_ident();
        p.expect(&token::Colon);
        let ty = p.parse_ty();
        (ident, ty)
    }

    /// Parses struct information, like visibility, name and deriving.
    fn parse_struct_info(&mut self) -> Result<StructInfo, ()> {
        let public = self.p.eat_keyword(token::keywords::Pub);
        let mut info = StructInfo {
            name: self.p.parse_ident(),
            public: public,
            deriving: vec![],
        };
        if self.p.eat(&token::Comma) { return Ok(info); }
        let deriving = self.p.parse_ident();
        if deriving.as_str() != "derive" {
            let err = format!("Expected 'derive' keyword but got '{}'",
                              deriving);
            self.cx.span_err(self.cx.call_site(), &*err);
            return Err(());
        }
        while !self.p.eat(&token::Comma) {
            info.deriving.push(self.p.parse_ident().as_str().to_string());
        }
        Ok(info)
    }
}

struct StructInfo {
    name: ast::Ident,
    public: bool,
    deriving: Vec<String>,
}

// Convenience functions for building intermediate values.

fn ident(s: &str) -> ast::Ident {
    ast::Ident::new(token::intern(s))
}

fn attribute<S, T>(cx: &ExtCtxt, name: S, items: Vec<T>) -> ast::Attribute
            where S: Str, T: Str {
    let sp = codemap::DUMMY_SP;
    let its = items.into_iter().map(|s| meta_item(cx, s.as_slice())).collect();
    let mi = cx.meta_list(sp, intern(name.as_slice()), its);
    cx.attribute(sp, mi)
}

fn meta_item(cx: &ExtCtxt, s: &str) -> P<ast::MetaItem> {
    cx.meta_word(codemap::DUMMY_SP, intern(s))
}

fn intern(s: &str) -> token::InternedString {
    token::intern_and_get_ident(s)
}

fn ty_vec_string(cx: &ExtCtxt) -> P<ast::Ty> {
    let sp = codemap::DUMMY_SP;
    let tystr = ast::AngleBracketedParameterData {
        lifetimes: vec![],
        types: OwnedSlice::from_vec(vec![cx.ty_ident(sp, ident("String"))]),
        bindings: OwnedSlice::empty(),
    };
    cx.ty_path(ast::Path {
        span: sp,
        global: false,
        segments: vec![ast::PathSegment {
            identifier: ident("Vec"),
            parameters: ast::PathParameters::AngleBracketedParameters(tystr),
        }]
    })
}
<|endoftext|>


<commit_before>#[legacy_exports];
export FreeTypeNativeFont, with_test_native_font, create;

use font::{FontMetrics, FractionalPixel};

use util::*;
use vec_as_buf = vec::as_imm_buf;
use ptr::{addr_of, null};
use cast::reinterpret_cast;
use glyph::GlyphIndex;
use font::FontMetrics;
use azure::freetype;
use freetype::{ FT_Error, FT_Library, FT_Face, FT_Long, FT_ULong, FT_UInt, FT_GlyphSlot };
use freetype::bindgen::{
    FT_Init_FreeType,
    FT_Done_FreeType,
    FT_New_Memory_Face,
    FT_Done_Face,
    FT_Get_Char_Index,
    FT_Load_Glyph,
    FT_Set_Char_Size
};

fn float_to_fixed_ft(f: float) -> i32 {
    float_to_fixed(6, f)
}

fn fixed_to_float_ft(f: i32) -> float {
    fixed_to_float(6, f)
}

struct FreeTypeNativeFont {
    /// The font binary. This must stay valid for the lifetime of the font
    buf: @~[u8],
    face: FT_Face,

    drop {
        assert self.face.is_not_null();
        if !FT_Done_Face(self.face).succeeded() {
            fail ~"FT_Done_Face failed";
        }
    }
}

fn FreeTypeNativeFont(face: FT_Face, buf: @~[u8]) -> FreeTypeNativeFont {
    assert face.is_not_null();
    FreeTypeNativeFont { buf: buf, face: face }
}

impl FreeTypeNativeFont {

    fn glyph_index(codepoint: char) -> Option<GlyphIndex> {
        assert self.face.is_not_null();
        let idx = FT_Get_Char_Index(self.face, codepoint as FT_ULong);
        return if idx != 0 as FT_UInt {
            Some(idx as GlyphIndex)
        } else {
            debug!("Invalid codepoint: %?", codepoint);
            None
        };
    }

    // FIXME: What unit is this returning? Let's have a custom type
    fn glyph_h_advance(glyph: GlyphIndex) -> Option<FractionalPixel> {
        assert self.face.is_not_null();
        let res =  FT_Load_Glyph(self.face, glyph as FT_UInt, 0);
        if res.succeeded() {
            unsafe {
                let void_glyph = (*self.face).glyph;
                let slot: FT_GlyphSlot = reinterpret_cast(&void_glyph);
                assert slot.is_not_null();
                debug!("metrics: %?", (*slot).metrics);
                let advance = (*slot).metrics.horiAdvance;
                debug!("h_advance for %? is %?", glyph, advance);
                let advance = advance as i32;
                return Some(fixed_to_float_ft(advance) as FractionalPixel);
            }
        } else {
            debug!("Unable to load glyph %?. reason: %?", glyph, res);
            return None;
        }
    }

    fn get_metrics() -> FontMetrics {
        /* TODO: complete me (Issue #76) */
        return FontMetrics {
            underline_size:   0.0,
            underline_offset: 0.0,
            leading:          0.0,
            x_height:         0.0,
            em_size:          gfx::geometry::au(0),
            em_height:        0.0,
            em_ascent:        0.0,
            em_descent:       0.0,
            max_advance:      0.0
        }
    }
}

pub fn create(lib: &FT_Library, buf: @~[u8]) -> Result<FreeTypeNativeFont, ()> {
    assert lib.is_not_null();
    let face: FT_Face = null();
    return vec_as_buf(*buf, |cbuf, _len| {
           if FT_New_Memory_Face(*lib, cbuf, (*buf).len() as FT_Long,
                                 0 as FT_Long, addr_of(&face)).succeeded() {
               // FIXME: These values are placeholders
               let res = FT_Set_Char_Size(face, 0, 20*64, 0, 72);
               if !res.succeeded() { fail ~"unable to set font char size" }
               Ok(FreeTypeNativeFont(face, buf))
           } else {
               Err(())
           }
    })
}

trait FTErrorMethods {
    fn succeeded() -> bool;
}

impl FT_Error : FTErrorMethods {
    fn succeeded() -> bool { self == 0 as FT_Error }
}

fn with_test_native_font(f: fn@(nf: &NativeFont)) {
    use font::test_font_bin;
    use unwrap_result = result::unwrap;

    with_lib(|lib| {
        let buf = @test_font_bin();
        let font = unwrap_result(create(lib, move buf));
        f(&font);
    })
}

fn with_lib(f: fn@((&FT_Library))) {
    let lib: FT_Library = null();
    assert FT_Init_FreeType(addr_of(&lib)).succeeded();
    f(&lib);
    FT_Done_FreeType(lib);
}

#[test]
fn create_should_return_err_if_buf_is_bogus() {
    with_lib(|lib| {
        let buf = @~[];
        assert create(lib, buf).is_err();
    })
}
<commit_msg>Fix linux breakage<commit_after>#[legacy_exports];
export FreeTypeNativeFont, with_test_native_font, create;

use font::{FontMetrics, FractionalPixel};

use au = gfx::geometry;
use util::*;
use vec_as_buf = vec::as_imm_buf;
use ptr::{addr_of, null};
use cast::reinterpret_cast;
use glyph::GlyphIndex;
use font::FontMetrics;
use azure::freetype;
use freetype::{ FT_Error, FT_Library, FT_Face, FT_Long, FT_ULong, FT_UInt, FT_GlyphSlot };
use freetype::bindgen::{
    FT_Init_FreeType,
    FT_Done_FreeType,
    FT_New_Memory_Face,
    FT_Done_Face,
    FT_Get_Char_Index,
    FT_Load_Glyph,
    FT_Set_Char_Size
};

fn float_to_fixed_ft(f: float) -> i32 {
    float_to_fixed(6, f)
}

fn fixed_to_float_ft(f: i32) -> float {
    fixed_to_float(6, f)
}

struct FreeTypeNativeFont {
    /// The font binary. This must stay valid for the lifetime of the font
    buf: @~[u8],
    face: FT_Face,

    drop {
        assert self.face.is_not_null();
        if !FT_Done_Face(self.face).succeeded() {
            fail ~"FT_Done_Face failed";
        }
    }
}

fn FreeTypeNativeFont(face: FT_Face, buf: @~[u8]) -> FreeTypeNativeFont {
    assert face.is_not_null();
    FreeTypeNativeFont { buf: buf, face: face }
}

impl FreeTypeNativeFont {

    fn glyph_index(codepoint: char) -> Option<GlyphIndex> {
        assert self.face.is_not_null();
        let idx = FT_Get_Char_Index(self.face, codepoint as FT_ULong);
        return if idx != 0 as FT_UInt {
            Some(idx as GlyphIndex)
        } else {
            debug!("Invalid codepoint: %?", codepoint);
            None
        };
    }

    // FIXME: What unit is this returning? Let's have a custom type
    fn glyph_h_advance(glyph: GlyphIndex) -> Option<FractionalPixel> {
        assert self.face.is_not_null();
        let res =  FT_Load_Glyph(self.face, glyph as FT_UInt, 0);
        if res.succeeded() {
            unsafe {
                let void_glyph = (*self.face).glyph;
                let slot: FT_GlyphSlot = reinterpret_cast(&void_glyph);
                assert slot.is_not_null();
                debug!("metrics: %?", (*slot).metrics);
                let advance = (*slot).metrics.horiAdvance;
                debug!("h_advance for %? is %?", glyph, advance);
                let advance = advance as i32;
                return Some(fixed_to_float_ft(advance) as FractionalPixel);
            }
        } else {
            debug!("Unable to load glyph %?. reason: %?", glyph, res);
            return None;
        }
    }

    fn get_metrics() -> FontMetrics {
        /* TODO: complete me (Issue #76) */
        return FontMetrics {
            underline_size:   au::from_pt(0.0),
            underline_offset: au::from_pt(0.0),
            leading:          au::from_pt(0.0),
            x_height:         au::from_pt(0.0),
            em_size:          au::from_pt(0.0),
            ascent:           au::from_pt(0.0),
            descent:          au::from_pt(0.0),
            max_advance:      au::from_pt(0.0)
        }
    }
}

pub fn create(lib: &FT_Library, buf: @~[u8]) -> Result<FreeTypeNativeFont, ()> {
    assert lib.is_not_null();
    let face: FT_Face = null();
    return vec_as_buf(*buf, |cbuf, _len| {
           if FT_New_Memory_Face(*lib, cbuf, (*buf).len() as FT_Long,
                                 0 as FT_Long, addr_of(&face)).succeeded() {
               // FIXME: These values are placeholders
               let res = FT_Set_Char_Size(face, 0, 20*64, 0, 72);
               if !res.succeeded() { fail ~"unable to set font char size" }
               Ok(FreeTypeNativeFont(face, buf))
           } else {
               Err(())
           }
    })
}

trait FTErrorMethods {
    fn succeeded() -> bool;
}

impl FT_Error : FTErrorMethods {
    fn succeeded() -> bool { self == 0 as FT_Error }
}

fn with_test_native_font(f: fn@(nf: &NativeFont)) {
    use font::test_font_bin;
    use unwrap_result = result::unwrap;

    with_lib(|lib| {
        let buf = @test_font_bin();
        let font = unwrap_result(create(lib, move buf));
        f(&font);
    })
}

fn with_lib(f: fn@((&FT_Library))) {
    let lib: FT_Library = null();
    assert FT_Init_FreeType(addr_of(&lib)).succeeded();
    f(&lib);
    FT_Done_FreeType(lib);
}

#[test]
fn create_should_return_err_if_buf_is_bogus() {
    with_lib(|lib| {
        let buf = @~[];
        assert create(lib, buf).is_err();
    })
}
<|endoftext|>


<commit_before>use std::rc::Rc;

/// A SliceParser is a parser that parses some elements out of the beginning of
/// a slice and returns a parsed value along with the rest of the unparsed slice
pub trait SliceParser  {
  type I;
  type O;

  fn parse<'a>(&self, data: &'a[Self::I]) -> ParseResult<&'a [Self::I], Self::O>;
}

/// Combinator methods for slice parsers.  In most cases, these methods copy
/// the caller into a higher-order parser
pub trait ParserCombinator : SliceParser + Clone {

  /// Chain this parser with another parser, creating new parser that returns a
  /// tuple of their results
  fn then<P: SliceParser<I=Self::I>>(&self, p: P) -> ChainedParser<Self,P> {
    ChainedParser{first: self.clone(), second: p}
  }

  /// Chain this parser with another parser, but toss the value from this parser
  fn then_r<P: ParserCombinator<I=Self::I>>(&self, p: P) -> MapParser<ChainedParser<Self, P>, P::O> {
    self.then(p).map(|(_, t)| t)
  }

  /// Chain this parser with another parser, but toss the value from the other parser
  fn then_l<P: ParserCombinator<I=Self::I>>(&self, p: P) -> MapParser<ChainedParser<Self, P>, Self::O> {
    self.then(p).map(|(t, _)| t)
  }

  /// Create a new parser that will repeat this parser until it returns an error
  fn repeat(&self) -> RepeatParser<Self> {
    RepeatParser{parser: self.clone()}
  }

  /// Map the value of this parser
  fn map<T, F: 'static + Fn(Self::O) -> T>(&self, f: F) -> MapParser<Self, T> {
    MapParser{parser: self.clone(), mapper: Rc::new(Box::new(f))}
  }

  /// Create a disjunction with another parser.  If this parser produces an error, the other parser will be used
  fn or<P: SliceParser<I=Self::I, O=Self::O>>(&self, p: P) -> OrParser<Self::I, Self::O, Self,P> {
    OrParser{first: self.clone(), second: p}
  }

}

pub type ParseResult<I,O> = Result<(O, I), String>;

/// Create a parser that only recognizes the given literal value
pub fn lit<T: Eq + Clone>(l: T) -> LiteralParser<T> {
  LiteralParser{literal: l}
}

/// Create a parser that will return Some if the given parser is successful, None otherwise
pub fn opt<T: SliceParser>(t: T) -> OptionParser<T> {
  OptionParser{parser: t}
}

/// Create a lazily evaluated parser from a function.  This can be used to generate recursive parsers
pub fn recursive<I,O, F:  Fn() -> Box<SliceParser<I=I,O=O>>>(f: F) -> RecursiveParser<I,O,F> {
  RecursiveParser{parser: Rc::new(f)}
}

pub fn matcher<T: Clone, U, F: 'static + Fn(T) -> Option<U>>(f: F) -> MatchParser<T, U> {
  MatchParser{matcher: Rc::new(Box::new(f))}
}

//////////////////////// STRUCTS /////////////////////////////////////////////

/// A Chained parser contains two parsers that will be used in sequence to
/// create a tuple of parsed values
pub struct ChainedParser<A,B> {
  first: A,
  second: B,
}
impl<C, A: SliceParser<I=C>, B: SliceParser<I=C>> SliceParser for ChainedParser<A, B> {
  type I = C;
  type O = (A::O,B::O);

  fn parse<'a>(&self, data: &'a[Self::I]) -> ParseResult<&'a [Self::I], Self::O>{
    match self.first.parse(data) {
      Ok((a, d2)) => match self.second.parse(d2) {
        Ok((b, remain)) => Ok(((a, b), remain)),
        Err(err) => Err(err)
      },
      Err(err) => Err(err)
    }
  }
}

impl<C, A: ParserCombinator<I=C>, B: ParserCombinator<I=C>>  Clone for ChainedParser<A, B> {

  fn clone(&self) -> Self {
    ChainedParser{first: self.first.clone(), second: self.second.clone()}
  }
}

impl<C, A: ParserCombinator<I=C>, B: ParserCombinator<I=C>>  ParserCombinator for ChainedParser<A, B> {}

/// A LiteralParser looks for an exact match of the given item at the beginning
// of the slice
#[derive(Clone)]
pub struct LiteralParser< T: Eq + Clone> {
  pub literal: T,
}

impl<T: Eq + Clone> SliceParser for LiteralParser< T> {
  type I = T;
  type O = T;

  fn parse<'a>(&self, data: &'a [T]) -> ParseResult<&'a [T], T> {
    if data.len() < 1 {
      return Err(format!("ran out of data"))
    }
    if data[0] == self.literal {
      Ok((data[0].clone(), &data[1..]))
    } else {
      Err(format!("Literal mismatch"))
    }
  }
}

impl<T: Eq + Clone> ParserCombinator for LiteralParser<T>{}

/// A Parser that repeats the given parser until it encounters an error.  A
/// vector of the accumulated parsed values is returned
pub struct RepeatParser<P: SliceParser> {
  parser: P
}
impl<T: SliceParser> SliceParser for RepeatParser<T> {
  type I = T::I;
  type O = Vec<T::O>;

  fn parse<'a>(&self, data: &'a [Self::I]) -> ParseResult<&'a [Self::I], Self::O> {
    let mut remain = data;
    let mut v: Vec<T::O> = Vec::new();
    loop {
      match self.parser.parse(remain.clone()) {
        Ok((result, rest)) => {
          v.push(result);
          remain = rest;
        }
        Err(_) => {
          return Ok((v, remain));
        }
      }
    }
  }
}

impl<T: ParserCombinator> ParserCombinator for RepeatParser<T> {}

impl<T: ParserCombinator> Clone for RepeatParser<T> {
  fn clone(&self) -> Self {
    RepeatParser{parser: self.parser.clone()}
  }
}

/// A Parser that uses a closure to map the result of another parser
pub struct MapParser<P: SliceParser, T> {
  parser: P,
  mapper: Rc<Box<Fn(P::O) -> T>>,
}

impl<P: SliceParser, T> SliceParser for MapParser<P,T> {
  type I = P::I;
  type O = T;

  fn parse<'a>(&self, data: &'a [Self::I]) -> ParseResult<&'a [Self::I], Self::O> {
    self.parser.parse(data).map(|(output, input)| ((self.mapper)(output), input))
  }

}

impl<P: ParserCombinator, T> Clone for MapParser<P,T> {

  fn clone(&self) -> Self {
    MapParser{parser: self.parser.clone(), mapper: self.mapper.clone()}
  }
}

impl<P: ParserCombinator, T> ParserCombinator for MapParser<P,T> {}

pub struct OrParser<I,O, S: SliceParser<I=I,O=O>, T: SliceParser<I=I,O=O>> {
  first: S,
  second: T,
}

impl<I,O, S: SliceParser<I=I,O=O>, T: SliceParser<I=I,O=O>> SliceParser for OrParser<I,O,S,T> {
  type I = I;
  type O = O;

  fn parse<'a>(&self, data: &'a [Self::I]) -> ParseResult<&'a [Self::I], Self::O> {
    match self.first.parse(data.clone()) {
      Ok((a, d2)) => Ok((a, d2)),
      Err(_) => match self.second.parse(data.clone()) {
        Ok((b, remain)) => Ok((b, remain)),
        Err(err) => Err(err)
      }
    }
  }
}

impl<I,O, S: ParserCombinator<I=I,O=O>, T: ParserCombinator<I=I,O=O>> Clone for OrParser<I,O,S,T> {

  fn clone(&self) -> Self {
    OrParser{first: self.first.clone(), second: self.second.clone()}
  }
}

impl<I,O, S: ParserCombinator<I=I,O=O>, T: ParserCombinator<I=I,O=O>> ParserCombinator for OrParser<I,O,S,T> {}

#[derive(Clone)]
pub struct OptionParser<P: SliceParser> {
  parser: P
}
impl<P: SliceParser> SliceParser for OptionParser<P> {
  type I = P::I;
  type O = Option<P::O>;

  fn parse<'a>(&self, data: &'a [Self::I]) -> ParseResult<&'a [Self::I], Self::O> {
    match self.parser.parse(data.clone()) {
      Ok((result, rest))  => Ok((Some(result), rest)),
      Err(_)              => Ok((None, data)),
    }
  }
}

pub struct RecursiveParser<I, O, F> where F: Fn() -> Box<SliceParser<I=I,O=O>>{
  parser: Rc<F>
}

impl<I, O, F> SliceParser for RecursiveParser<I, O, F> where F: Fn() -> Box<SliceParser<I=I,O=O>> {

  type I = I;
  type O = O;

  fn parse<'a>(&self, data: &'a [Self::I]) -> ParseResult<&'a [Self::I], Self::O> {
    (self.parser)().parse(data)
  }

}

impl<I, O, F> ParserCombinator for RecursiveParser<I, O, F> where F: Fn() -> Box<SliceParser<I=I,O=O>> {}

impl<I, O, F> Clone for RecursiveParser<I, O, F> where F: Fn() -> Box<SliceParser<I=I,O=O>> {
  fn clone(&self) -> Self {
    RecursiveParser{parser: self.parser.clone()}
  }
}

pub struct MatchParser<T: Clone, U> {
  matcher: Rc<Box<Fn(T) -> Option<U>>>
}

impl<T: Clone, U> SliceParser for MatchParser<T,U> {
  type I = T;
  type O = U;

  fn parse<'a>(&self, data: &'a [Self::I]) -> ParseResult<&'a [Self::I], Self::O> {
    if data.len() < 1 {
      return Err(format!("ran out of data"))
    }
    match (self.matcher)(data[0].clone()) {
      Some(u) => Ok((u, &data[1..])),
      None    => Err(format!("Match failed"))
    }
  }
}

impl<T: Clone, U> ParserCombinator for MatchParser<T,U> {}

impl<T: Clone, U> Clone for MatchParser<T,U> {

  fn clone(&self) -> Self {
    MatchParser{matcher: self.matcher.clone()}
  }

}

<commit_msg>another dead end<commit_after>use std::rc::Rc;

/// A SliceParser is a parser that parses some elements out of the beginning of
/// a slice and returns a parsed value along with the rest of the unparsed slice
pub trait SliceParser  {
  type I: ?Sized;
  type O;

  fn parse<'a>(&self, data: &'a Self::I) -> ParseResult<&'a Self::I, Self::O>;
}

/// Combinator methods for slice parsers.  In most cases, these methods copy
/// the caller into a higher-order parser
pub trait ParserCombinator : SliceParser + Clone {

  /// Chain this parser with another parser, creating new parser that returns a
  /// tuple of their results
  fn then<P: SliceParser<I=Self::I>>(&self, p: P) -> ChainedParser<Self,P> {
    ChainedParser{first: self.clone(), second: p}
  }

  /// Chain this parser with another parser, but toss the value from this parser
  fn then_r<P: ParserCombinator<I=Self::I>>(&self, p: P) -> MapParser<ChainedParser<Self, P>, P::O> {
    self.then(p).map(|(_, t)| t)
  }

  /// Chain this parser with another parser, but toss the value from the other parser
  fn then_l<P: ParserCombinator<I=Self::I>>(&self, p: P) -> MapParser<ChainedParser<Self, P>, Self::O> {
    self.then(p).map(|(t, _)| t)
  }

  /// Create a new parser that will repeat this parser until it returns an error
  fn repeat(&self) -> RepeatParser<Self> {
    RepeatParser{parser: self.clone()}
  }

  /// Map the value of this parser
  fn map<T, F: 'static + Fn(Self::O) -> T>(&self, f: F) -> MapParser<Self, T> {
    MapParser{parser: self.clone(), mapper: Rc::new(Box::new(f))}
  }

  /// Create a disjunction with another parser.  If this parser produces an error, the other parser will be used
  fn or<P: SliceParser<I=Self::I, O=Self::O>>(&self, p: P) -> OrParser<Self::I, Self::O, Self,P> {
    OrParser{first: self.clone(), second: p}
  }

}

pub type ParseResult<I,O> = Result<(O, I), String>;

/// Create a parser that only recognizes the given literal value
pub fn lit<T: Eq + Clone>(l: T) -> LiteralParser<T> {
  LiteralParser{literal: l}
}

/// Create a parser that will return Some if the given parser is successful, None otherwise
pub fn opt<T: SliceParser>(t: T) -> OptionParser<T> {
  OptionParser{parser: t}
}

/// Create a lazily evaluated parser from a function.  This can be used to generate recursive parsers
pub fn recursive<I,O, F:  Fn() -> Box<SliceParser<I=I,O=O>>>(f: F) -> RecursiveParser<I,O,F> {
  RecursiveParser{parser: Rc::new(f)}
}

pub fn matcher<T: Clone, U, F: 'static + Fn(T) -> Option<U>>(f: F) -> MatchParser<T, U> {
  MatchParser{matcher: Rc::new(Box::new(f))}
}

//////////////////////// STRUCTS /////////////////////////////////////////////

/// A Chained parser contains two parsers that will be used in sequence to
/// create a tuple of parsed values
pub struct ChainedParser<A,B> {
  first: A,
  second: B,
}
impl<C, A: SliceParser<I=C>, B: SliceParser<I=C>> SliceParser for ChainedParser<A, B> {
  type I = C;
  type O = (A::O,B::O);

  fn parse<'a>(&self, data: &'a Self::I) -> ParseResult<&'a Self::I, Self::O>{
    match self.first.parse(data) {
      Ok((a, d2)) => match self.second.parse(d2) {
        Ok((b, remain)) => Ok(((a, b), remain)),
        Err(err) => Err(err)
      },
      Err(err) => Err(err)
    }
  }
}

impl<C, A: ParserCombinator<I=C>, B: ParserCombinator<I=C>>  Clone for ChainedParser<A, B> {

  fn clone(&self) -> Self {
    ChainedParser{first: self.first.clone(), second: self.second.clone()}
  }
}

impl<C, A: ParserCombinator<I=C>, B: ParserCombinator<I=C>>  ParserCombinator for ChainedParser<A, B> {}

/// A LiteralParser looks for an exact match of the given item at the beginning
// of the slice
#[derive(Clone)]
pub struct LiteralParser< T: Eq + Clone> {
  pub literal: T,
}

impl<T: Eq + Clone> SliceParser for LiteralParser< T> {
  type I = [T];
  type O = T;

  fn parse<'a>(&self, data: &'a [T]) -> ParseResult<&'a [T], T> {
    if data.len() < 1 {
      return Err(format!("ran out of data"))
    }
    if data[0] == self.literal {
      Ok((data[0].clone(), &data[1..]))
    } else {
      Err(format!("Literal mismatch"))
    }
  }
}

impl<T: Eq + Clone> ParserCombinator for LiteralParser<T>{}

/// A Parser that repeats the given parser until it encounters an error.  A
/// vector of the accumulated parsed values is returned
pub struct RepeatParser<P: SliceParser> {
  parser: P
}
impl<T: SliceParser> SliceParser for RepeatParser<T> {
  type I = T::I;
  type O = Vec<T::O>;

  fn parse<'a>(&self, data: &'a Self::I) -> ParseResult<&'a Self::I, Self::O> {
    let mut remain = data;
    let mut v: Vec<T::O> = Vec::new();
    loop {
      match self.parser.parse(remain.clone()) {
        Ok((result, rest)) => {
          v.push(result);
          remain = rest;
        }
        Err(_) => {
          return Ok((v, remain));
        }
      }
    }
  }
}

impl<T: ParserCombinator> ParserCombinator for RepeatParser<T> {}

impl<T: ParserCombinator> Clone for RepeatParser<T> {
  fn clone(&self) -> Self {
    RepeatParser{parser: self.parser.clone()}
  }
}

/// A Parser that uses a closure to map the result of another parser
pub struct MapParser<P: SliceParser, T> {
  parser: P,
  mapper: Rc<Box<Fn(P::O) -> T>>,
}

impl<P: SliceParser, T> SliceParser for MapParser<P,T> {
  type I = P::I;
  type O = T;

  fn parse<'a>(&self, data: &'a Self::I) -> ParseResult<&'a Self::I, Self::O> {
    self.parser.parse(data).map(|(output, input)| ((self.mapper)(output), input))
  }

}

impl<P: ParserCombinator, T> Clone for MapParser<P,T> {

  fn clone(&self) -> Self {
    MapParser{parser: self.parser.clone(), mapper: self.mapper.clone()}
  }
}

impl<P: ParserCombinator, T> ParserCombinator for MapParser<P,T> {}

pub struct OrParser<I,O, S: SliceParser<I=I,O=O>, T: SliceParser<I=I,O=O>> {
  first: S,
  second: T,
}

impl<I,O, S: SliceParser<I=I,O=O>, T: SliceParser<I=I,O=O>> SliceParser for OrParser<I,O,S,T> {
  type I = I;
  type O = O;

  fn parse<'a>(&self, data: &'a Self::I) -> ParseResult<&'a Self::I, Self::O> {
    match self.first.parse(data.clone()) {
      Ok((a, d2)) => Ok((a, d2)),
      Err(_) => match self.second.parse(data.clone()) {
        Ok((b, remain)) => Ok((b, remain)),
        Err(err) => Err(err)
      }
    }
  }
}

impl<I,O, S: ParserCombinator<I=I,O=O>, T: ParserCombinator<I=I,O=O>> Clone for OrParser<I,O,S,T> {

  fn clone(&self) -> Self {
    OrParser{first: self.first.clone(), second: self.second.clone()}
  }
}

impl<I,O, S: ParserCombinator<I=I,O=O>, T: ParserCombinator<I=I,O=O>> ParserCombinator for OrParser<I,O,S,T> {}

#[derive(Clone)]
pub struct OptionParser<P: SliceParser> {
  parser: P
}
impl<P: SliceParser> SliceParser for OptionParser<P> {
  type I = P::I;
  type O = Option<P::O>;

  fn parse<'a>(&self, data: &'a Self::I) -> ParseResult<&'a Self::I, Self::O> {
    match self.parser.parse(data.clone()) {
      Ok((result, rest))  => Ok((Some(result), rest)),
      Err(_)              => Ok((None, data)),
    }
  }
}

pub struct RecursiveParser<I, O, F> where F: Fn() -> Box<SliceParser<I=I,O=O>>{
  parser: Rc<F>
}

impl<I, O, F> SliceParser for RecursiveParser<I, O, F> where F: Fn() -> Box<SliceParser<I=I,O=O>> {

  type I = I;
  type O = O;

  fn parse<'a>(&self, data: &'a Self::I) -> ParseResult<&'a Self::I, Self::O> {
    (self.parser)().parse(data)
  }

}

impl<I, O, F> ParserCombinator for RecursiveParser<I, O, F> where F: Fn() -> Box<SliceParser<I=I,O=O>> {}

impl<I, O, F> Clone for RecursiveParser<I, O, F> where F: Fn() -> Box<SliceParser<I=I,O=O>> {
  fn clone(&self) -> Self {
    RecursiveParser{parser: self.parser.clone()}
  }
}

pub struct MatchParser<T: Clone, U> {
  matcher: Rc<Box<Fn(T) -> Option<U>>>
}

impl<T: Clone, U> SliceParser for MatchParser<T,U> {
  type I = T;
  type O = U;

  fn parse<'a>(&self, data: &'a Self::I) -> ParseResult<&'a Self::I, Self::O> {
    if data.len() < 1 {
      return Err(format!("ran out of data"))
    }
    match (self.matcher)(data[0].clone()) {
      Some(u) => Ok((u, &data[1..])),
      None    => Err(format!("Match failed"))
    }
  }
}

impl<T: Clone, U> ParserCombinator for MatchParser<T,U> {}

impl<T: Clone, U> Clone for MatchParser<T,U> {

  fn clone(&self) -> Self {
    MatchParser{matcher: self.matcher.clone()}
  }

}

<|endoftext|>


<commit_before>pub(crate) mod http_request_to_grpc_frames_typed;
pub(crate) mod http_response_to_grpc_frames;
pub(crate) mod http_response_to_grpc_frames_typed;
pub(crate) mod req_sink;
pub(crate) mod types;

use std::net::SocketAddr;

use bytes::Bytes;

use httpbis;
use httpbis::Header;
use httpbis::Headers;
use httpbis::HttpScheme;

use tls_api;

use method::MethodDescriptor;

use error::*;
use result;

use client::http_request_to_grpc_frames_typed::http_req_to_grpc_frames_typed;
use client::http_response_to_grpc_frames_typed::http_response_to_grpc_frames_typed;
use client::req_sink::ClientRequestSink;
use error;
use futures::future;
use futures::Future;
use proto::grpc_frame::write_grpc_frame_to_vec;
use req::*;
use resp::*;
use or_static::arc::ArcOrStatic;

#[derive(Default, Debug, Clone)]
pub struct ClientConf {
    pub http: httpbis::ClientConf,
}

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

/// gRPC client implementation.
/// Used by generated code.
#[derive(Debug)]
pub struct Client {
    client: ::std::sync::Arc<httpbis::Client>,
    host: String,
    http_scheme: HttpScheme,
    port: Option<u16>,
}

impl Client {
    /// Create a client connected to specified host and port.
    pub fn new_plain(host: &str, port: u16, conf: ClientConf) -> result::Result<Client> {
        let mut conf = conf;
        conf.http.thread_name = Some(
            conf.http
                .thread_name
                .unwrap_or_else(|| "grpc-client-loop".to_owned()),
        );

        httpbis::Client::new_plain(host, port, conf.http)
            .map(|client| Client {
                client: ::std::sync::Arc::new(client),
                host: host.to_owned(),
                http_scheme: HttpScheme::Http,
                port: Some(port.to_owned()),
            }).map_err(Error::from)
    }

    /// Create a client connected to specified Unix domain socket.
    #[cfg(unix)]
    pub fn new_plain_unix(addr: &str, conf: ClientConf) -> result::Result<Client> {
        let mut conf = conf;
        conf.http.thread_name = Some(
            conf.http
                .thread_name
                .unwrap_or_else(|| "grpc-client-loop".to_owned()),
        );

        httpbis::Client::new_plain_unix(addr, conf.http)
            .map(|client| Client {
                client: ::std::sync::Arc::new(client),
                host: addr.to_owned(),
                http_scheme: HttpScheme::Http,
                port: None,
            }).map_err(Error::from)
    }

    /// Create a client connected to specified host and port.
    pub fn new_tls<C: tls_api::TlsConnector>(
        host: &str,
        port: u16,
        conf: ClientConf,
    ) -> result::Result<Client> {
        let mut conf = conf;
        conf.http.thread_name = Some(
            conf.http
                .thread_name
                .unwrap_or_else(|| "grpc-client-loop".to_owned()),
        );

        httpbis::Client::new_tls::<C>(host, port, conf.http)
            .map(|client| Client {
                client: ::std::sync::Arc::new(client),
                host: host.to_owned(),
                http_scheme: HttpScheme::Https,
                port: Some(port.to_owned()),
            }).map_err(Error::from)
    }

    pub fn new_expl<C: tls_api::TlsConnector>(
        addr: &SocketAddr,
        host: &str,
        tls: httpbis::ClientTlsOption<C>,
        conf: ClientConf,
    ) -> result::Result<Client> {
        let mut conf = conf;
        conf.http.thread_name = Some(
            conf.http
                .thread_name
                .unwrap_or_else(|| "grpc-client-loop".to_owned()),
        );

        let http_scheme = tls.http_scheme();

        httpbis::Client::new_expl(addr, tls, conf.http)
            .map(|client| Client {
                client: ::std::sync::Arc::new(client),
                host: host.to_owned(),
                http_scheme: http_scheme,
                port: Some(addr.port()),
            }).map_err(Error::from)
    }

    fn call_impl<Req, Resp>(
        &self,
        options: RequestOptions,
        req: Option<Req>,
        method: ArcOrStatic<MethodDescriptor<Req, Resp>>,
    ) -> Box<
        Future<Item = (ClientRequestSink<Req>, StreamingResponse<Resp>), Error = error::Error>
            + Send,
    >
    where
        Req: Send + 'static,
        Resp: Send + 'static,
    {
        let mut authority = self.host.clone();
        if let Some(port_value) = self.port {
            authority = format!("{}:{}", authority, port_value);
        }

        debug!("start call {}/{}", authority, method.name);

        if options.cachable {
            // TODO: GET
            // https://github.com/grpc/grpc/issues/18230
        }

        let mut headers = Headers::from_vec(vec![
            Header::new(Bytes::from_static(b":method"), Bytes::from_static(b"POST")),
            // TODO: do not allocate static
            Header::new(Bytes::from_static(b":path"), method.name.to_string()),
            Header::new(Bytes::from_static(b":authority"), authority),
            Header::new(
                Bytes::from_static(b":scheme"),
                Bytes::from_static(self.http_scheme.as_bytes()),
            ),
            Header::new(
                Bytes::from_static(b"content-type"),
                Bytes::from_static(b"application/grpc"),
            ),
            Header::new(Bytes::from_static(b"te"), Bytes::from_static(b"trailers")),
        ]);

        headers.extend(options.metadata.into_headers());

        let req_bytes = match req {
            Some(req) => match method.req_marshaller.write(&req) {
                Ok(bytes) => {
                    // TODO: extra allocation
                    Some(Bytes::from(write_grpc_frame_to_vec(&bytes)))
                }
                Err(e) => return Box::new(future::err(e)),
            },
            None => None,
        };

        let end_stream = req_bytes.is_some();

        //        let request_frames = {
        //            let method = method.clone();
        //            req.0
        //                .and_then(move |req| {
        //                    let grpc_frame = method.req_marshaller.write(&req)?;
        //                    Ok(Bytes::from(write_grpc_frame_to_vec(&grpc_frame)))
        //                }).map_err(|_e| httpbis::Error::Other("grpc error")) // TODO: preserve error
        //        };

        let http_future = self
            .client
            .start_request(headers, req_bytes, None, end_stream);

        let http_future = http_future.map_err(error::Error::from);

        let req_marshaller = method.req_marshaller.clone();
        let resp_marshaller = method.resp_marshaller.clone();

        Box::new(http_future.map(move |(req, resp)| {
            let grpc_req = http_req_to_grpc_frames_typed(req, req_marshaller);
            let grpc_resp = http_response_to_grpc_frames_typed(resp, resp_marshaller);
            (grpc_req, grpc_resp)
        }))

        //        Box::new(http_future
        //            .map(|(req, resp)| {
        //                let grpc_req = ClientRequestSink {
        //                    common: SinkCommon {
        //                        marshaller: method.req_marshaller,
        //                        sink: req,
        //                    }
    }

    pub fn call_unary<Req, Resp>(
        &self,
        o: RequestOptions,
        req: Req,
        method: ArcOrStatic<MethodDescriptor<Req, Resp>>,
    ) -> SingleResponse<Resp>
    where
        Req: Send + 'static,
        Resp: Send + 'static,
    {
        SingleResponse::new(
            self.call_impl(o, Some(req), method)
                .and_then(|(_req, resp)| resp.single()),
        )
    }

    pub fn call_server_streaming<Req, Resp>(
        &self,
        o: RequestOptions,
        req: Req,
        method: ArcOrStatic<MethodDescriptor<Req, Resp>>,
    ) -> StreamingResponse<Resp>
    where
        Req: Send + 'static,
        Resp: Send + 'static,
    {
        StreamingResponse::new(
            self.call_impl(o, Some(req), method)
                .map(|(_req, resp)| resp.0)
                .flatten(),
        )
    }

    pub fn call_client_streaming<Req, Resp>(
        &self,
        o: RequestOptions,
        method: ArcOrStatic<MethodDescriptor<Req, Resp>>,
    ) -> impl Future<Item = (ClientRequestSink<Req>, SingleResponse<Resp>), Error = error::Error>
    where
        Req: Send + 'static,
        Resp: Send + 'static,
    {
        self.call_impl(o, None, method)
            .map(|(req, resp)| (req, resp.single()))
    }

    pub fn call_bidi<Req, Resp>(
        &self,
        o: RequestOptions,
        method: ArcOrStatic<MethodDescriptor<Req, Resp>>,
    ) -> impl Future<Item = (ClientRequestSink<Req>, StreamingResponse<Resp>), Error = error::Error>
    where
        Req: Send + 'static,
        Resp: Send + 'static,
    {
        self.call_impl(o, None, method)
    }
}

fn _assert_types() {
    ::assert_types::assert_send::<Client>();
    ::assert_types::assert_sync::<Client>();
}
<commit_msg>Add a way to bring your own tokio event loop<commit_after>pub(crate) mod http_request_to_grpc_frames_typed;
pub(crate) mod http_response_to_grpc_frames;
pub(crate) mod http_response_to_grpc_frames_typed;
pub(crate) mod req_sink;
pub(crate) mod types;

use std::net::SocketAddr;

use bytes::Bytes;
use tokio_core::reactor::Remote;

use httpbis;
use httpbis::Header;
use httpbis::Headers;
use httpbis::HttpScheme;

use tls_api;

use method::MethodDescriptor;

use error::*;
use result;

use client::http_request_to_grpc_frames_typed::http_req_to_grpc_frames_typed;
use client::http_response_to_grpc_frames_typed::http_response_to_grpc_frames_typed;
use client::req_sink::ClientRequestSink;
use error;
use futures::future;
use futures::Future;
use proto::grpc_frame::write_grpc_frame_to_vec;
use req::*;
use resp::*;
use or_static::arc::ArcOrStatic;

#[derive(Default, Debug, Clone)]
pub struct ClientConf {
    pub http: httpbis::ClientConf,
}

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

/// gRPC client implementation.
/// Used by generated code.
#[derive(Debug)]
pub struct Client {
    client: ::std::sync::Arc<httpbis::Client>,
    host: String,
    http_scheme: HttpScheme,
    port: Option<u16>,
}

impl Client {
    pub fn new_explicit_plain(
        host: &str,
        port: u16,
        conf: ClientConf,
        event_loop: Option<Remote>,
    ) -> result::Result<Client> {
        let mut conf = conf;
        conf.http.thread_name = Some(
            conf.http
                .thread_name
                .unwrap_or_else(|| "grpc-client-loop".to_owned()),
        );

        let mut builder = httpbis::ClientBuilder::new_plain();
        builder.set_addr((host, port))?;
        builder.event_loop = event_loop;
        builder.conf = conf.http;

        Ok(Client {
            client: ::std::sync::Arc::new(builder.build()?),
            host: host.to_owned(),
            http_scheme: HttpScheme::Http,
            port: Some(port),
        })
    }

    /// Create a client connected to specified host and port.
    pub fn new_plain(host: &str, port: u16, conf: ClientConf) -> result::Result<Client> {
        let mut conf = conf;
        conf.http.thread_name = Some(
            conf.http
                .thread_name
                .unwrap_or_else(|| "grpc-client-loop".to_owned()),
        );

        httpbis::Client::new_plain(host, port, conf.http)
            .map(|client| Client {
                client: ::std::sync::Arc::new(client),
                host: host.to_owned(),
                http_scheme: HttpScheme::Http,
                port: Some(port.to_owned()),
            }).map_err(Error::from)
    }

    /// Create a client connected to specified Unix domain socket.
    #[cfg(unix)]
    pub fn new_plain_unix(addr: &str, conf: ClientConf) -> result::Result<Client> {
        let mut conf = conf;
        conf.http.thread_name = Some(
            conf.http
                .thread_name
                .unwrap_or_else(|| "grpc-client-loop".to_owned()),
        );

        httpbis::Client::new_plain_unix(addr, conf.http)
            .map(|client| Client {
                client: ::std::sync::Arc::new(client),
                host: addr.to_owned(),
                http_scheme: HttpScheme::Http,
                port: None,
            }).map_err(Error::from)
    }

    /// Create a client connected to specified host and port.
    pub fn new_tls<C: tls_api::TlsConnector>(
        host: &str,
        port: u16,
        conf: ClientConf,
    ) -> result::Result<Client> {
        let mut conf = conf;
        conf.http.thread_name = Some(
            conf.http
                .thread_name
                .unwrap_or_else(|| "grpc-client-loop".to_owned()),
        );

        httpbis::Client::new_tls::<C>(host, port, conf.http)
            .map(|client| Client {
                client: ::std::sync::Arc::new(client),
                host: host.to_owned(),
                http_scheme: HttpScheme::Https,
                port: Some(port.to_owned()),
            }).map_err(Error::from)
    }

    pub fn new_expl<C: tls_api::TlsConnector>(
        addr: &SocketAddr,
        host: &str,
        tls: httpbis::ClientTlsOption<C>,
        conf: ClientConf,
        event_loop: Option<Remote>,
    ) -> result::Result<Client> {
        let mut conf = conf;
        conf.http.thread_name = Some(
            conf.http
                .thread_name
                .unwrap_or_else(|| "grpc-client-loop".to_owned()),
        );

        let http_scheme = tls.http_scheme();
        let mut builder = httpbis::ClientBuilder::<C>::new();
        builder.set_addr(addr)?;
        if let httpbis::ClientTlsOption::Tls(ref host, _) = tls {
            builder.set_tls(host)?;
        }
        builder.event_loop = event_loop;
        builder.conf = conf.http;

        Ok(Client {
            client: ::std::sync::Arc::new(builder.build()?),
            host: host.to_owned(),
            http_scheme,
            port: Some(addr.port())
        })
    }

    fn call_impl<Req, Resp>(
        &self,
        options: RequestOptions,
        req: Option<Req>,
        method: ArcOrStatic<MethodDescriptor<Req, Resp>>,
    ) -> Box<
        Future<Item = (ClientRequestSink<Req>, StreamingResponse<Resp>), Error = error::Error>
            + Send,
    >
    where
        Req: Send + 'static,
        Resp: Send + 'static,
    {
        let mut authority = self.host.clone();
        if let Some(port_value) = self.port {
            authority = format!("{}:{}", authority, port_value);
        }

        debug!("start call {}/{}", authority, method.name);

        if options.cachable {
            // TODO: GET
            // https://github.com/grpc/grpc/issues/18230
        }

        let mut headers = Headers::from_vec(vec![
            Header::new(Bytes::from_static(b":method"), Bytes::from_static(b"POST")),
            // TODO: do not allocate static
            Header::new(Bytes::from_static(b":path"), method.name.to_string()),
            Header::new(Bytes::from_static(b":authority"), authority),
            Header::new(
                Bytes::from_static(b":scheme"),
                Bytes::from_static(self.http_scheme.as_bytes()),
            ),
            Header::new(
                Bytes::from_static(b"content-type"),
                Bytes::from_static(b"application/grpc"),
            ),
            Header::new(Bytes::from_static(b"te"), Bytes::from_static(b"trailers")),
        ]);

        headers.extend(options.metadata.into_headers());

        let req_bytes = match req {
            Some(req) => match method.req_marshaller.write(&req) {
                Ok(bytes) => {
                    // TODO: extra allocation
                    Some(Bytes::from(write_grpc_frame_to_vec(&bytes)))
                }
                Err(e) => return Box::new(future::err(e)),
            },
            None => None,
        };

        let end_stream = req_bytes.is_some();

        //        let request_frames = {
        //            let method = method.clone();
        //            req.0
        //                .and_then(move |req| {
        //                    let grpc_frame = method.req_marshaller.write(&req)?;
        //                    Ok(Bytes::from(write_grpc_frame_to_vec(&grpc_frame)))
        //                }).map_err(|_e| httpbis::Error::Other("grpc error")) // TODO: preserve error
        //        };

        let http_future = self
            .client
            .start_request(headers, req_bytes, None, end_stream);

        let http_future = http_future.map_err(error::Error::from);

        let req_marshaller = method.req_marshaller.clone();
        let resp_marshaller = method.resp_marshaller.clone();

        Box::new(http_future.map(move |(req, resp)| {
            let grpc_req = http_req_to_grpc_frames_typed(req, req_marshaller);
            let grpc_resp = http_response_to_grpc_frames_typed(resp, resp_marshaller);
            (grpc_req, grpc_resp)
        }))

        //        Box::new(http_future
        //            .map(|(req, resp)| {
        //                let grpc_req = ClientRequestSink {
        //                    common: SinkCommon {
        //                        marshaller: method.req_marshaller,
        //                        sink: req,
        //                    }
    }

    pub fn call_unary<Req, Resp>(
        &self,
        o: RequestOptions,
        req: Req,
        method: ArcOrStatic<MethodDescriptor<Req, Resp>>,
    ) -> SingleResponse<Resp>
    where
        Req: Send + 'static,
        Resp: Send + 'static,
    {
        SingleResponse::new(
            self.call_impl(o, Some(req), method)
                .and_then(|(_req, resp)| resp.single()),
        )
    }

    pub fn call_server_streaming<Req, Resp>(
        &self,
        o: RequestOptions,
        req: Req,
        method: ArcOrStatic<MethodDescriptor<Req, Resp>>,
    ) -> StreamingResponse<Resp>
    where
        Req: Send + 'static,
        Resp: Send + 'static,
    {
        StreamingResponse::new(
            self.call_impl(o, Some(req), method)
                .map(|(_req, resp)| resp.0)
                .flatten(),
        )
    }

    pub fn call_client_streaming<Req, Resp>(
        &self,
        o: RequestOptions,
        method: ArcOrStatic<MethodDescriptor<Req, Resp>>,
    ) -> impl Future<Item = (ClientRequestSink<Req>, SingleResponse<Resp>), Error = error::Error>
    where
        Req: Send + 'static,
        Resp: Send + 'static,
    {
        self.call_impl(o, None, method)
            .map(|(req, resp)| (req, resp.single()))
    }

    pub fn call_bidi<Req, Resp>(
        &self,
        o: RequestOptions,
        method: ArcOrStatic<MethodDescriptor<Req, Resp>>,
    ) -> impl Future<Item = (ClientRequestSink<Req>, StreamingResponse<Resp>), Error = error::Error>
    where
        Req: Send + 'static,
        Resp: Send + 'static,
    {
        self.call_impl(o, None, method)
    }
}

fn _assert_types() {
    ::assert_types::assert_send::<Client>();
    ::assert_types::assert_sync::<Client>();
}
<|endoftext|>


<commit_before>// compile-flags: -C no-prepopulate-passes
// ignore-tidy-linelength

#![crate_type = "lib"]

// Below, these constants are defined as enum variants that by itself would
// have a lower alignment than the enum type. Ensure that we mark them
// correctly with the higher alignment of the enum.

// CHECK: @STATIC = {{.*}}, align 4

// This checks the constants from inline_enum_const
// CHECK: @alloc8 = {{.*}}, align 2

// This checks the constants from {low,high}_align_const, they share the same
// constant, but the alignment differs, so the higher one should be used
// CHECK: [[LOW_HIGH:@[0-9]+]] = {{.*}} getelementptr inbounds (<{ [8 x i8] }>, <{ [8 x i8] }>* @alloc20, i32 0, i32 0, i32 0), {{.*}}

#[derive(Copy, Clone)]
// repr(i16) is required for the {low,high}_align_const test
#[repr(i16)]
pub enum E<A, B> {
    A(A),
    B(B),
}

#[no_mangle]
pub static STATIC: E<i16, i32> = E::A(0);

// CHECK-LABEL: @static_enum_const
#[no_mangle]
pub fn static_enum_const() -> E<i16, i32> {
    STATIC
}

// CHECK-LABEL: @inline_enum_const
#[no_mangle]
pub fn inline_enum_const() -> E<i8, i16> {
    *&E::A(0)
}

// CHECK-LABEL: @low_align_const
#[no_mangle]
pub fn low_align_const() -> E<i16, [i16; 3]> {
    // Check that low_align_const and high_align_const use the same constant
    // CHECK: load %"E<i16, [i16; 3]>"*, %"E<i16, [i16; 3]>"** bitcast (<{ i8*, [0 x i8] }>* [[LOW_HIGH]] to %"E<i16, [i16; 3]>"**),
    *&E::A(0)
}

// CHECK-LABEL: @high_align_const
#[no_mangle]
pub fn high_align_const() -> E<i16, i32> {
    // Check that low_align_const and high_align_const use the same constant
    // CHECK: load %"E<i16, i32>"*, %"E<i16, i32>"** bitcast (<{ i8*, [0 x i8] }>* [[LOW_HIGH]] to %"E<i16, i32>"**),
    *&E::A(0)
}
<commit_msg>Update codegen tests<commit_after>// compile-flags: -C no-prepopulate-passes
// ignore-tidy-linelength

#![crate_type = "lib"]

// Below, these constants are defined as enum variants that by itself would
// have a lower alignment than the enum type. Ensure that we mark them
// correctly with the higher alignment of the enum.

// CHECK: @STATIC = {{.*}}, align 4

// This checks the constants from inline_enum_const
// CHECK: @alloc8 = {{.*}}, align 2

// This checks the constants from {low,high}_align_const, they share the same
// constant, but the alignment differs, so the higher one should be used
// CHECK: [[LOW_HIGH:@alloc[0-9]+]] = {{.*}}, align 4

#[derive(Copy, Clone)]
// repr(i16) is required for the {low,high}_align_const test
#[repr(i16)]
pub enum E<A, B> {
    A(A),
    B(B),
}

#[no_mangle]
pub static STATIC: E<i16, i32> = E::A(0);

// CHECK-LABEL: @static_enum_const
#[no_mangle]
pub fn static_enum_const() -> E<i16, i32> {
    STATIC
}

// CHECK-LABEL: @inline_enum_const
#[no_mangle]
pub fn inline_enum_const() -> E<i8, i16> {
    *&E::A(0)
}

// CHECK-LABEL: @low_align_const
#[no_mangle]
pub fn low_align_const() -> E<i16, [i16; 3]> {
    // Check that low_align_const and high_align_const use the same constant
    // CHECK: memcpy.p0i8.p0i8.i64(i8* align 2 %1, i8* align 2 getelementptr inbounds (<{ [8 x i8] }>, <{ [8 x i8] }>* [[LOW_HIGH]], i32 0, i32 0, i32 0), i64 8, i1 false)
    *&E::A(0)
}

// CHECK-LABEL: @high_align_const
#[no_mangle]
pub fn high_align_const() -> E<i16, i32> {
    // Check that low_align_const and high_align_const use the same constant
    // CHECK: memcpy.p0i8.p0i8.i64(i8* align 4 %1, i8* align 4 getelementptr inbounds (<{ [8 x i8] }>, <{ [8 x i8] }>* [[LOW_HIGH]], i32 0, i32 0, i32 0), i64 8, i1 false)
    *&E::A(0)
}
<|endoftext|>