<commit_before>// Copyright 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.

/*!

typeck.rs, an introduction

The type checker is responsible for:

1. Determining the type of each expression
2. Resolving methods and traits
3. Guaranteeing that most type rules are met ("most?", you say, "why most?"
   Well, dear reader, read on)

The main entry point is `check_crate()`.  Type checking operates in
several major phases:

1. The collect phase first passes over all items and determines their
   type, without examining their "innards".

2. Variance inference then runs to compute the variance of each parameter

3. Coherence checks for overlapping or orphaned impls

4. Finally, the check phase then checks function bodies and so forth.
   Within the check phase, we check each function body one at a time
   (bodies of function expressions are checked as part of the
   containing function).  Inference is used to supply types wherever
   they are unknown. The actual checking of a function itself has
   several phases (check, regionck, writeback), as discussed in the
   documentation for the `check` module.

The type checker is defined into various submodules which are documented
independently:

- astconv: converts the AST representation of types
  into the `ty` representation

- collect: computes the types of each top-level item and enters them into
  the `cx.tcache` table for later use

- coherence: enforces coherence rules, builds some tables

- variance: variance inference

- check: walks over function bodies and type checks them, inferring types for
  local variables, type parameters, etc as necessary.

- infer: finds the types to use for each type variable such that
  all subtyping and assignment constraints are met.  In essence, the check
  module specifies the constraints, and the infer module solves them.

# Note

This API is completely unstable and subject to change.

*/

#![crate_name = "rustc_typeck"]
#![unstable(feature = "rustc_private", issue = "27812")]
#![crate_type = "dylib"]
#![crate_type = "rlib"]
#![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
      html_favicon_url = "https://doc.rust-lang.org/favicon.ico",
      html_root_url = "https://doc.rust-lang.org/nightly/")]
#![cfg_attr(not(stage0), deny(warnings))]

#![allow(non_camel_case_types)]

#![feature(box_patterns)]
#![feature(box_syntax)]
#![feature(conservative_impl_trait)]
#![feature(dotdot_in_tuple_patterns)]
#![feature(quote)]
#![feature(rustc_diagnostic_macros)]
#![feature(rustc_private)]
#![feature(staged_api)]
#![cfg_attr(stage0, feature(question_mark))]

#[macro_use] extern crate log;
#[macro_use] extern crate syntax;
extern crate syntax_pos;

extern crate arena;
extern crate fmt_macros;
#[macro_use] extern crate rustc;
extern crate rustc_platform_intrinsics as intrinsics;
extern crate rustc_back;
extern crate rustc_const_math;
extern crate rustc_const_eval;
extern crate rustc_errors as errors;

pub use rustc::dep_graph;
pub use rustc::hir;
pub use rustc::lint;
pub use rustc::middle;
pub use rustc::session;
pub use rustc::util;

use dep_graph::DepNode;
use hir::map as hir_map;
use rustc::infer::TypeOrigin;
use rustc::ty::subst::Substs;
use rustc::ty::{self, Ty, TyCtxt, TypeFoldable};
use rustc::traits::{self, Reveal};
use session::{config, CompileResult};
use util::common::time;

use syntax::ast;
use syntax::abi::Abi;
use syntax_pos::Span;

use std::cell::RefCell;
use util::nodemap::NodeMap;

// NB: This module needs to be declared first so diagnostics are
// registered before they are used.
pub mod diagnostics;

pub mod check;
pub mod check_unused;
mod rscope;
mod astconv;
pub mod collect;
mod constrained_type_params;
pub mod coherence;
pub mod variance;

pub struct TypeAndSubsts<'tcx> {
    pub substs: &'tcx Substs<'tcx>,
    pub ty: Ty<'tcx>,
}

pub struct CrateCtxt<'a, 'tcx: 'a> {
    ast_ty_to_ty_cache: RefCell<NodeMap<Ty<'tcx>>>,

    /// A vector of every trait accessible in the whole crate
    /// (i.e. including those from subcrates). This is used only for
    /// error reporting, and so is lazily initialised and generally
    /// shouldn't taint the common path (hence the RefCell).
    pub all_traits: RefCell<Option<check::method::AllTraitsVec>>,

    /// This stack is used to identify cycles in the user's source.
    /// Note that these cycles can cross multiple items.
    pub stack: RefCell<Vec<collect::AstConvRequest>>,

    pub tcx: TyCtxt<'a, 'tcx, 'tcx>,

    /// Obligations which will have to be checked at the end of
    /// type-checking, after all functions have been inferred.
    /// The key is the NodeId of the item the obligations were from.
    pub deferred_obligations: RefCell<NodeMap<Vec<traits::DeferredObligation<'tcx>>>>,
}

// Functions that write types into the node type table
fn write_ty_to_tcx<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, node_id: ast::NodeId, ty: Ty<'tcx>) {
    debug!("write_ty_to_tcx({}, {:?})", node_id,  ty);
    assert!(!ty.needs_infer());
    ccx.tcx.node_type_insert(node_id, ty);
}

fn write_substs_to_tcx<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
                                 node_id: ast::NodeId,
                                 item_substs: ty::ItemSubsts<'tcx>) {
    if !item_substs.is_noop() {
        debug!("write_substs_to_tcx({}, {:?})",
               node_id,
               item_substs);

        assert!(!item_substs.substs.needs_infer());

        ccx.tcx.tables.borrow_mut().item_substs.insert(node_id, item_substs);
    }
}

fn require_c_abi_if_variadic(tcx: TyCtxt,
                             decl: &hir::FnDecl,
                             abi: Abi,
                             span: Span) {
    if decl.variadic && abi != Abi::C {
        let mut err = struct_span_err!(tcx.sess, span, E0045,
                  "variadic function must have C calling convention");
        err.span_label(span, &("variadics require C calling conventions").to_string())
            .emit();
    }
}

fn require_same_types<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
                                origin: TypeOrigin,
                                t1: Ty<'tcx>,
                                t2: Ty<'tcx>)
                                -> bool {
    ccx.tcx.infer_ctxt(None, None, Reveal::NotSpecializable).enter(|infcx| {
        if let Err(err) = infcx.eq_types(false, origin.clone(), t1, t2) {
            infcx.report_mismatched_types(origin, t1, t2, err);
            false
        } else {
            true
        }
    })
}

fn check_main_fn_ty(ccx: &CrateCtxt,
                    main_id: ast::NodeId,
                    main_span: Span) {
    let tcx = ccx.tcx;
    let main_t = tcx.node_id_to_type(main_id);
    match main_t.sty {
        ty::TyFnDef(..) => {
            match tcx.map.find(main_id) {
                Some(hir_map::NodeItem(it)) => {
                    match it.node {
                        hir::ItemFn(.., ref generics, _) => {
                            if generics.is_parameterized() {
                                struct_span_err!(ccx.tcx.sess, generics.span, E0131,
                                         "main function is not allowed to have type parameters")
                                    .span_label(generics.span,
                                                &format!("main cannot have type parameters"))
                                    .emit();
                                return;
                            }
                        }
                        _ => ()
                    }
                }
                _ => ()
            }
            let main_def_id = tcx.map.local_def_id(main_id);
            let substs = tcx.intern_substs(&[]);
            let se_ty = tcx.mk_fn_def(main_def_id, substs,
                                      tcx.mk_bare_fn(ty::BareFnTy {
                unsafety: hir::Unsafety::Normal,
                abi: Abi::Rust,
                sig: ty::Binder(ty::FnSig {
                    inputs: Vec::new(),
                    output: tcx.mk_nil(),
                    variadic: false
                })
            }));

            require_same_types(
                ccx,
                TypeOrigin::MainFunctionType(main_span),
                main_t,
                se_ty);
        }
        _ => {
            span_bug!(main_span,
                      "main has a non-function type: found `{}`",
                      main_t);
        }
    }
}

fn check_start_fn_ty(ccx: &CrateCtxt,
                     start_id: ast::NodeId,
                     start_span: Span) {
    let tcx = ccx.tcx;
    let start_t = tcx.node_id_to_type(start_id);
    match start_t.sty {
        ty::TyFnDef(..) => {
            match tcx.map.find(start_id) {
                Some(hir_map::NodeItem(it)) => {
                    match it.node {
                        hir::ItemFn(..,ref ps,_)
                        if ps.is_parameterized() => {
                            struct_span_err!(tcx.sess, ps.span, E0132,
                                "start function is not allowed to have type parameters")
                                .span_label(ps.span,
                                            &format!("start function cannot have type parameters"))
                                .emit();
                            return;
                        }
                        _ => ()
                    }
                }
                _ => ()
            }

            let start_def_id = ccx.tcx.map.local_def_id(start_id);
            let substs = tcx.intern_substs(&[]);
            let se_ty = tcx.mk_fn_def(start_def_id, substs,
                                      tcx.mk_bare_fn(ty::BareFnTy {
                unsafety: hir::Unsafety::Normal,
                abi: Abi::Rust,
                sig: ty::Binder(ty::FnSig {
                    inputs: vec![
                        tcx.types.isize,
                        tcx.mk_imm_ptr(tcx.mk_imm_ptr(tcx.types.u8))
                    ],
                    output: tcx.types.isize,
                    variadic: false,
                }),
            }));

            require_same_types(
                ccx,
                TypeOrigin::StartFunctionType(start_span),
                start_t,
                se_ty);
        }
        _ => {
            span_bug!(start_span,
                      "start has a non-function type: found `{}`",
                      start_t);
        }
    }
}

fn check_for_entry_fn(ccx: &CrateCtxt) {
    let tcx = ccx.tcx;
    let _task = tcx.dep_graph.in_task(DepNode::CheckEntryFn);
    if let Some((id, sp)) = *tcx.sess.entry_fn.borrow() {
        match tcx.sess.entry_type.get() {
            Some(config::EntryMain) => check_main_fn_ty(ccx, id, sp),
            Some(config::EntryStart) => check_start_fn_ty(ccx, id, sp),
            Some(config::EntryNone) => {}
            None => bug!("entry function without a type")
        }
    }
}

pub fn check_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>)
                             -> CompileResult {
    let time_passes = tcx.sess.time_passes();
    let ccx = CrateCtxt {
        ast_ty_to_ty_cache: RefCell::new(NodeMap()),
        all_traits: RefCell::new(None),
        stack: RefCell::new(Vec::new()),
        tcx: tcx,
        deferred_obligations: RefCell::new(NodeMap()),
    };

    // this ensures that later parts of type checking can assume that items
    // have valid types and not error
    tcx.sess.track_errors(|| {
        time(time_passes, "type collecting", ||
             collect::collect_item_types(&ccx));

    })?;

    time(time_passes, "variance inference", ||
         variance::infer_variance(tcx));

    tcx.sess.track_errors(|| {
      time(time_passes, "coherence checking", ||
          coherence::check_coherence(&ccx));
    })?;

    time(time_passes, "wf checking", || check::check_wf_new(&ccx))?;

    time(time_passes, "item-types checking", || check::check_item_types(&ccx))?;

    time(time_passes, "item-bodies checking", || check::check_item_bodies(&ccx))?;

    time(time_passes, "drop-impl checking", || check::check_drop_impls(&ccx))?;

    check_unused::check_crate(tcx);
    check_for_entry_fn(&ccx);

    let err_count = tcx.sess.err_count();
    if err_count == 0 {
        Ok(())
    } else {
        Err(err_count)
    }
}

__build_diagnostic_array! { librustc_typeck, DIAGNOSTICS }
<commit_msg>Auto merge of #36131 - Florob:entry_typeck, r=eddyb<commit_after>// Copyright 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.

/*!

typeck.rs, an introduction

The type checker is responsible for:

1. Determining the type of each expression
2. Resolving methods and traits
3. Guaranteeing that most type rules are met ("most?", you say, "why most?"
   Well, dear reader, read on)

The main entry point is `check_crate()`.  Type checking operates in
several major phases:

1. The collect phase first passes over all items and determines their
   type, without examining their "innards".

2. Variance inference then runs to compute the variance of each parameter

3. Coherence checks for overlapping or orphaned impls

4. Finally, the check phase then checks function bodies and so forth.
   Within the check phase, we check each function body one at a time
   (bodies of function expressions are checked as part of the
   containing function).  Inference is used to supply types wherever
   they are unknown. The actual checking of a function itself has
   several phases (check, regionck, writeback), as discussed in the
   documentation for the `check` module.

The type checker is defined into various submodules which are documented
independently:

- astconv: converts the AST representation of types
  into the `ty` representation

- collect: computes the types of each top-level item and enters them into
  the `cx.tcache` table for later use

- coherence: enforces coherence rules, builds some tables

- variance: variance inference

- check: walks over function bodies and type checks them, inferring types for
  local variables, type parameters, etc as necessary.

- infer: finds the types to use for each type variable such that
  all subtyping and assignment constraints are met.  In essence, the check
  module specifies the constraints, and the infer module solves them.

# Note

This API is completely unstable and subject to change.

*/

#![crate_name = "rustc_typeck"]
#![unstable(feature = "rustc_private", issue = "27812")]
#![crate_type = "dylib"]
#![crate_type = "rlib"]
#![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
      html_favicon_url = "https://doc.rust-lang.org/favicon.ico",
      html_root_url = "https://doc.rust-lang.org/nightly/")]
#![cfg_attr(not(stage0), deny(warnings))]

#![allow(non_camel_case_types)]

#![feature(box_patterns)]
#![feature(box_syntax)]
#![feature(conservative_impl_trait)]
#![feature(dotdot_in_tuple_patterns)]
#![feature(quote)]
#![feature(rustc_diagnostic_macros)]
#![feature(rustc_private)]
#![feature(staged_api)]
#![cfg_attr(stage0, feature(question_mark))]

#[macro_use] extern crate log;
#[macro_use] extern crate syntax;
extern crate syntax_pos;

extern crate arena;
extern crate fmt_macros;
#[macro_use] extern crate rustc;
extern crate rustc_platform_intrinsics as intrinsics;
extern crate rustc_back;
extern crate rustc_const_math;
extern crate rustc_const_eval;
extern crate rustc_errors as errors;

pub use rustc::dep_graph;
pub use rustc::hir;
pub use rustc::lint;
pub use rustc::middle;
pub use rustc::session;
pub use rustc::util;

use dep_graph::DepNode;
use hir::map as hir_map;
use rustc::infer::TypeOrigin;
use rustc::ty::subst::Substs;
use rustc::ty::{self, Ty, TyCtxt, TypeFoldable};
use rustc::traits::{self, Reveal};
use session::{config, CompileResult};
use util::common::time;

use syntax::ast;
use syntax::abi::Abi;
use syntax_pos::Span;

use std::cell::RefCell;
use util::nodemap::NodeMap;

// NB: This module needs to be declared first so diagnostics are
// registered before they are used.
pub mod diagnostics;

pub mod check;
pub mod check_unused;
mod rscope;
mod astconv;
pub mod collect;
mod constrained_type_params;
pub mod coherence;
pub mod variance;

pub struct TypeAndSubsts<'tcx> {
    pub substs: &'tcx Substs<'tcx>,
    pub ty: Ty<'tcx>,
}

pub struct CrateCtxt<'a, 'tcx: 'a> {
    ast_ty_to_ty_cache: RefCell<NodeMap<Ty<'tcx>>>,

    /// A vector of every trait accessible in the whole crate
    /// (i.e. including those from subcrates). This is used only for
    /// error reporting, and so is lazily initialised and generally
    /// shouldn't taint the common path (hence the RefCell).
    pub all_traits: RefCell<Option<check::method::AllTraitsVec>>,

    /// This stack is used to identify cycles in the user's source.
    /// Note that these cycles can cross multiple items.
    pub stack: RefCell<Vec<collect::AstConvRequest>>,

    pub tcx: TyCtxt<'a, 'tcx, 'tcx>,

    /// Obligations which will have to be checked at the end of
    /// type-checking, after all functions have been inferred.
    /// The key is the NodeId of the item the obligations were from.
    pub deferred_obligations: RefCell<NodeMap<Vec<traits::DeferredObligation<'tcx>>>>,
}

// Functions that write types into the node type table
fn write_ty_to_tcx<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, node_id: ast::NodeId, ty: Ty<'tcx>) {
    debug!("write_ty_to_tcx({}, {:?})", node_id,  ty);
    assert!(!ty.needs_infer());
    ccx.tcx.node_type_insert(node_id, ty);
}

fn write_substs_to_tcx<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
                                 node_id: ast::NodeId,
                                 item_substs: ty::ItemSubsts<'tcx>) {
    if !item_substs.is_noop() {
        debug!("write_substs_to_tcx({}, {:?})",
               node_id,
               item_substs);

        assert!(!item_substs.substs.needs_infer());

        ccx.tcx.tables.borrow_mut().item_substs.insert(node_id, item_substs);
    }
}

fn require_c_abi_if_variadic(tcx: TyCtxt,
                             decl: &hir::FnDecl,
                             abi: Abi,
                             span: Span) {
    if decl.variadic && abi != Abi::C {
        let mut err = struct_span_err!(tcx.sess, span, E0045,
                  "variadic function must have C calling convention");
        err.span_label(span, &("variadics require C calling conventions").to_string())
            .emit();
    }
}

fn require_same_types<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
                                origin: TypeOrigin,
                                expected: Ty<'tcx>,
                                actual: Ty<'tcx>)
                                -> bool {
    ccx.tcx.infer_ctxt(None, None, Reveal::NotSpecializable).enter(|infcx| {
        if let Err(err) = infcx.eq_types(false, origin.clone(), expected, actual) {
            infcx.report_mismatched_types(origin, expected, actual, err);
            false
        } else {
            true
        }
    })
}

fn check_main_fn_ty(ccx: &CrateCtxt,
                    main_id: ast::NodeId,
                    main_span: Span) {
    let tcx = ccx.tcx;
    let main_t = tcx.node_id_to_type(main_id);
    match main_t.sty {
        ty::TyFnDef(..) => {
            match tcx.map.find(main_id) {
                Some(hir_map::NodeItem(it)) => {
                    match it.node {
                        hir::ItemFn(.., ref generics, _) => {
                            if generics.is_parameterized() {
                                struct_span_err!(ccx.tcx.sess, generics.span, E0131,
                                         "main function is not allowed to have type parameters")
                                    .span_label(generics.span,
                                                &format!("main cannot have type parameters"))
                                    .emit();
                                return;
                            }
                        }
                        _ => ()
                    }
                }
                _ => ()
            }
            let main_def_id = tcx.map.local_def_id(main_id);
            let substs = tcx.intern_substs(&[]);
            let se_ty = tcx.mk_fn_def(main_def_id, substs,
                                      tcx.mk_bare_fn(ty::BareFnTy {
                unsafety: hir::Unsafety::Normal,
                abi: Abi::Rust,
                sig: ty::Binder(ty::FnSig {
                    inputs: Vec::new(),
                    output: tcx.mk_nil(),
                    variadic: false
                })
            }));

            require_same_types(
                ccx,
                TypeOrigin::MainFunctionType(main_span),
                se_ty,
                main_t);
        }
        _ => {
            span_bug!(main_span,
                      "main has a non-function type: found `{}`",
                      main_t);
        }
    }
}

fn check_start_fn_ty(ccx: &CrateCtxt,
                     start_id: ast::NodeId,
                     start_span: Span) {
    let tcx = ccx.tcx;
    let start_t = tcx.node_id_to_type(start_id);
    match start_t.sty {
        ty::TyFnDef(..) => {
            match tcx.map.find(start_id) {
                Some(hir_map::NodeItem(it)) => {
                    match it.node {
                        hir::ItemFn(..,ref ps,_)
                        if ps.is_parameterized() => {
                            struct_span_err!(tcx.sess, ps.span, E0132,
                                "start function is not allowed to have type parameters")
                                .span_label(ps.span,
                                            &format!("start function cannot have type parameters"))
                                .emit();
                            return;
                        }
                        _ => ()
                    }
                }
                _ => ()
            }

            let start_def_id = ccx.tcx.map.local_def_id(start_id);
            let substs = tcx.intern_substs(&[]);
            let se_ty = tcx.mk_fn_def(start_def_id, substs,
                                      tcx.mk_bare_fn(ty::BareFnTy {
                unsafety: hir::Unsafety::Normal,
                abi: Abi::Rust,
                sig: ty::Binder(ty::FnSig {
                    inputs: vec![
                        tcx.types.isize,
                        tcx.mk_imm_ptr(tcx.mk_imm_ptr(tcx.types.u8))
                    ],
                    output: tcx.types.isize,
                    variadic: false,
                }),
            }));

            require_same_types(
                ccx,
                TypeOrigin::StartFunctionType(start_span),
                se_ty,
                start_t);
        }
        _ => {
            span_bug!(start_span,
                      "start has a non-function type: found `{}`",
                      start_t);
        }
    }
}

fn check_for_entry_fn(ccx: &CrateCtxt) {
    let tcx = ccx.tcx;
    let _task = tcx.dep_graph.in_task(DepNode::CheckEntryFn);
    if let Some((id, sp)) = *tcx.sess.entry_fn.borrow() {
        match tcx.sess.entry_type.get() {
            Some(config::EntryMain) => check_main_fn_ty(ccx, id, sp),
            Some(config::EntryStart) => check_start_fn_ty(ccx, id, sp),
            Some(config::EntryNone) => {}
            None => bug!("entry function without a type")
        }
    }
}

pub fn check_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>)
                             -> CompileResult {
    let time_passes = tcx.sess.time_passes();
    let ccx = CrateCtxt {
        ast_ty_to_ty_cache: RefCell::new(NodeMap()),
        all_traits: RefCell::new(None),
        stack: RefCell::new(Vec::new()),
        tcx: tcx,
        deferred_obligations: RefCell::new(NodeMap()),
    };

    // this ensures that later parts of type checking can assume that items
    // have valid types and not error
    tcx.sess.track_errors(|| {
        time(time_passes, "type collecting", ||
             collect::collect_item_types(&ccx));

    })?;

    time(time_passes, "variance inference", ||
         variance::infer_variance(tcx));

    tcx.sess.track_errors(|| {
      time(time_passes, "coherence checking", ||
          coherence::check_coherence(&ccx));
    })?;

    time(time_passes, "wf checking", || check::check_wf_new(&ccx))?;

    time(time_passes, "item-types checking", || check::check_item_types(&ccx))?;

    time(time_passes, "item-bodies checking", || check::check_item_bodies(&ccx))?;

    time(time_passes, "drop-impl checking", || check::check_drop_impls(&ccx))?;

    check_unused::check_crate(tcx);
    check_for_entry_fn(&ccx);

    let err_count = tcx.sess.err_count();
    if err_count == 0 {
        Ok(())
    } else {
        Err(err_count)
    }
}

__build_diagnostic_array! { librustc_typeck, DIAGNOSTICS }
<|endoftext|>


<commit_before>use nom::multispace;
use nom::{IResult, Err, ErrorKind, Needed};
use std::str;

use common::{field_list, statement_terminator, table_reference, value_list, Literal};
use column::Column;
use table::Table;

#[derive(Clone, Debug, Default, Hash, PartialEq, Serialize, Deserialize)]
pub struct InsertStatement {
    pub table: Table,
    pub fields: Vec<(Column, Literal)>,
}

/// Parse rule for a SQL insert query.
/// TODO(malte): support REPLACE, multiple parens expr, nested selection, DEFAULT VALUES
named!(pub insertion<&[u8], InsertStatement>,
    complete!(chain!(
        caseless_tag!("insert") ~
        multispace ~
        caseless_tag!("into") ~
        multispace ~
        table: table_reference ~
        multispace ~
        fields: opt!(chain!(
                tag!("(") ~
                multispace? ~
                fields: field_list ~
                multispace? ~
                tag!(")") ~
                multispace,
                || { fields }
                )
            ) ~
        caseless_tag!("values") ~
        multispace ~
        tag!("(") ~
        values: value_list ~
        tag!(")") ~
        statement_terminator,
        || {
            // "table AS alias" isn't legal in INSERT statements
            assert!(table.alias.is_none());
            InsertStatement {
                table: table,
                fields: match fields {
                    Some(ref f) =>
                        f.iter()
                         .cloned()
                         .zip(values.into_iter())
                         .collect(),
                    None =>
                        values.into_iter()
                              .enumerate()
                              .map(|(i, v)| {
                                  (Column::from(format!("{}", i).as_str()), v)
                              })
                              .collect(),
                },
            }
        }
    ))
);

#[cfg(test)]
mod tests {
    use super::*;
    use column::Column;
    use table::Table;

    #[test]
    fn simple_insert() {
        let qstring = "INSERT INTO users VALUES (42, \"test\");";

        let res = insertion(qstring.as_bytes());
        assert_eq!(
            res.unwrap().1,
            InsertStatement {
                table: Table::from("users"),
                fields: vec![
                    (Column::from("0"), 42.into()),
                    (Column::from("1"), "test".into()),
                ],
                ..Default::default()
            }
        );
    }

    #[test]
    fn complex_insert() {
        let qstring = "INSERT INTO users VALUES (42, 'test', \"test\", CURRENT_TIMESTAMP);";

        let res = insertion(qstring.as_bytes());
        assert_eq!(
            res.unwrap().1,
            InsertStatement {
                table: Table::from("users"),
                fields: vec![
                    (Column::from("0"), 42.into()),
                    (Column::from("1"), "test".into()),
                    (Column::from("2"), "test".into()),
                    (Column::from("3"), Literal::CurrentTimestamp),
                ],
                ..Default::default()
            }
        );
    }

    #[test]
    fn insert_with_field_names() {
        let qstring = "INSERT INTO users (id, name) VALUES (42, \"test\");";

        let res = insertion(qstring.as_bytes());
        assert_eq!(
            res.unwrap().1,
            InsertStatement {
                table: Table::from("users"),
                fields: vec![
                    (Column::from("id"), 42.into()),
                    (Column::from("name"), "test".into()),
                ],
                ..Default::default()
            }
        );
    }
}
<commit_msg>Spaces after table name and VALUES are optional<commit_after>use nom::multispace;
use nom::{IResult, Err, ErrorKind, Needed};
use std::str;

use common::{field_list, statement_terminator, table_reference, value_list, Literal};
use column::Column;
use table::Table;

#[derive(Clone, Debug, Default, Hash, PartialEq, Serialize, Deserialize)]
pub struct InsertStatement {
    pub table: Table,
    pub fields: Vec<(Column, Literal)>,
}

/// Parse rule for a SQL insert query.
/// TODO(malte): support REPLACE, multiple parens expr, nested selection, DEFAULT VALUES
named!(pub insertion<&[u8], InsertStatement>,
    complete!(chain!(
        caseless_tag!("insert") ~
        multispace ~
        caseless_tag!("into") ~
        multispace ~
        table: table_reference ~
        multispace? ~
        fields: opt!(chain!(
                tag!("(") ~
                multispace? ~
                fields: field_list ~
                multispace? ~
                tag!(")") ~
                multispace,
                || { fields }
                )
            ) ~
        caseless_tag!("values") ~
        multispace? ~
        tag!("(") ~
        values: value_list ~
        tag!(")") ~
        statement_terminator,
        || {
            // "table AS alias" isn't legal in INSERT statements
            assert!(table.alias.is_none());
            InsertStatement {
                table: table,
                fields: match fields {
                    Some(ref f) =>
                        f.iter()
                         .cloned()
                         .zip(values.into_iter())
                         .collect(),
                    None =>
                        values.into_iter()
                              .enumerate()
                              .map(|(i, v)| {
                                  (Column::from(format!("{}", i).as_str()), v)
                              })
                              .collect(),
                },
            }
        }
    ))
);

#[cfg(test)]
mod tests {
    use super::*;
    use column::Column;
    use table::Table;

    #[test]
    fn simple_insert() {
        let qstring = "INSERT INTO users VALUES (42, \"test\");";

        let res = insertion(qstring.as_bytes());
        assert_eq!(
            res.unwrap().1,
            InsertStatement {
                table: Table::from("users"),
                fields: vec![
                    (Column::from("0"), 42.into()),
                    (Column::from("1"), "test".into()),
                ],
                ..Default::default()
            }
        );
    }

    #[test]
    fn complex_insert() {
        let qstring = "INSERT INTO users VALUES (42, 'test', \"test\", CURRENT_TIMESTAMP);";

        let res = insertion(qstring.as_bytes());
        assert_eq!(
            res.unwrap().1,
            InsertStatement {
                table: Table::from("users"),
                fields: vec![
                    (Column::from("0"), 42.into()),
                    (Column::from("1"), "test".into()),
                    (Column::from("2"), "test".into()),
                    (Column::from("3"), Literal::CurrentTimestamp),
                ],
                ..Default::default()
            }
        );
    }

    #[test]
    fn insert_with_field_names() {
        let qstring = "INSERT INTO users (id, name) VALUES (42, \"test\");";

        let res = insertion(qstring.as_bytes());
        assert_eq!(
            res.unwrap().1,
            InsertStatement {
                table: Table::from("users"),
                fields: vec![
                    (Column::from("id"), 42.into()),
                    (Column::from("name"), "test".into()),
                ],
                ..Default::default()
            }
        );
    }

    // Issue #3
    #[test]
    fn insert_without_spaces() {
        let qstring = "INSERT INTO users(id, name) VALUES(42, \"test\");";

        let res = insertion(qstring.as_bytes());
        assert_eq!(
            res.unwrap().1,
            InsertStatement {
                table: Table::from("users"),
                fields: vec![
                    (Column::from("id"), 42.into()),
                    (Column::from("name"), "test".into()),
                ],
                ..Default::default()
            }
        );
    }
}
<|endoftext|>


<commit_before>/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */

use std::collections::HashSet;
use std::sync::Arc;

use common::ArgumentName;
use common::Diagnostic;
use common::DiagnosticsResult;
use common::NamedItem;
use common::WithLocation;
use graphql_ir::reexport::StringKey;
use graphql_ir::LinkedField;
use graphql_ir::OperationDefinition;
use graphql_ir::OperationDefinitionName;
use graphql_ir::Program;
use graphql_ir::ScalarField;
use graphql_ir::Selection;
use graphql_syntax::OperationKind;
use intern::string_key::Intern;
use lazy_static::lazy_static;
use relay_config::SchemaConfig;
use schema::Field;
use schema::FieldID;
use schema::SDLSchema;
use schema::Schema;
use schema::Type;

use crate::get_normalization_operation_name;
use crate::match_::RawResponseGenerationMode;
use crate::relay_resolvers::get_bool_argument_is_true;
use crate::relay_resolvers::RELAY_RESOLVER_DIRECTIVE_NAME;
use crate::SplitOperationMetadata;
use crate::ValidationMessage;

lazy_static! {
    pub static ref HAS_OUTPUT_TYPE_ARGUMENT_NAME: ArgumentName =
        ArgumentName("has_output_type".intern());
}

fn generate_fat_selections_from_type(
    schema: &SDLSchema,
    schema_config: &SchemaConfig,
    type_: Type,
    field_name: WithLocation<StringKey>,
) -> DiagnosticsResult<Vec<Selection>> {
    match type_ {
        Type::Object(object_id) => {
            let object = schema.object(object_id);
            if !object.is_extension {
                return Err(vec![Diagnostic::error(
                    ValidationMessage::RelayResolverServerTypeNotSupported {
                        field_name: field_name.item,
                        type_name: schema.get_type_name(type_),
                    },
                    field_name.location,
                )]);
            }

            let mut parent_types = HashSet::new();
            parent_types.insert(type_);
            generate_selections_from_fields(
                schema,
                schema_config,
                &object.fields,
                &mut parent_types,
            )
        }
        Type::Enum(_) => Err(vec![Diagnostic::error(
            ValidationMessage::RelayResolverOutputTypeUnsupported {
                type_kind: "enum".intern(),
                field_name: field_name.item,
                type_name: schema.get_type_name(type_),
            },
            field_name.location,
        )]),
        Type::Scalar(_) => Err(vec![Diagnostic::error(
            ValidationMessage::RelayResolverOutputTypeUnsupported {
                type_kind: "scalar".intern(),
                field_name: field_name.item,
                type_name: schema.get_type_name(type_),
            },
            field_name.location,
        )]),
        Type::InputObject(_) => Err(vec![Diagnostic::error(
            ValidationMessage::RelayResolverOutputTypeInvalidInputObjectType {
                field_name: field_name.item,
                type_name: schema.get_type_name(type_),
            },
            field_name.location,
        )]),
        Type::Interface(_) => Err(vec![Diagnostic::error(
            ValidationMessage::RelayResolverOutputTypeUnsupported {
                type_kind: "interface".intern(),
                field_name: field_name.item,
                type_name: schema.get_type_name(type_),
            },
            field_name.location,
        )]),
        Type::Union(_) => Err(vec![Diagnostic::error(
            ValidationMessage::RelayResolverOutputTypeUnsupported {
                type_kind: "union".intern(),
                field_name: field_name.item,
                type_name: schema.get_type_name(type_),
            },
            field_name.location,
        )]),
    }
}

fn generate_selections_from_fields(
    schema: &SDLSchema,
    schema_config: &SchemaConfig,
    field_ids: &[FieldID],
    parent_types: &mut HashSet<Type>,
) -> DiagnosticsResult<Vec<Selection>> {
    let mut errors = vec![];
    let mut selections = vec![];
    for field_id in field_ids {
        if schema
            .field(*field_id)
            .directives
            .named(*RELAY_RESOLVER_DIRECTIVE_NAME)
            .is_some()
        {
            continue;
        }
        match generate_selection_from_field(schema, schema_config, field_id, parent_types) {
            Ok(selection) => selections.push(selection),
            Err(err) => {
                errors.extend(err);
            }
        }
    }
    if errors.is_empty() {
        Ok(selections)
    } else {
        Err(errors)
    }
}

fn generate_selection_from_field(
    schema: &SDLSchema,
    schema_config: &SchemaConfig,
    field_id: &FieldID,
    parent_types: &mut HashSet<Type>,
) -> DiagnosticsResult<Selection> {
    let field = schema.field(*field_id);
    let type_ = field.type_.inner();
    if field.name.item == schema_config.node_interface_id_field {
        return Err(vec![Diagnostic::error(
            ValidationMessage::RelayResolverIDFieldNotSupported {
                id_name: field.name.item,
            },
            field.name.location,
        )]);
    }

    if !field.arguments.is_empty() {
        return Err(vec![Diagnostic::error(
            ValidationMessage::RelayResolverArgumentsNotSupported,
            field.name.location,
        )]);
    }

    match type_ {
        Type::Enum(_) => Ok(Selection::ScalarField(Arc::new(ScalarField {
            alias: None,
            definition: WithLocation::generated(*field_id),
            arguments: vec![],
            directives: vec![],
        }))),
        Type::Scalar(_) => Ok(Selection::ScalarField(Arc::new(ScalarField {
            alias: None,
            definition: WithLocation::generated(*field_id),
            arguments: vec![],
            directives: vec![],
        }))),
        Type::Object(object_id) => {
            let object = schema.object(object_id);
            if !object.is_extension {
                return Err(vec![Diagnostic::error(
                    ValidationMessage::RelayResolverServerTypeNotSupported {
                        field_name: field.name.item,
                        type_name: schema.get_type_name(type_),
                    },
                    field.name.location,
                )]);
            }

            if parent_types.contains(&type_) {
                return Err(vec![Diagnostic::error(
                    ValidationMessage::RelayResolverTypeRecursionDetected {
                        type_name: schema.get_type_name(type_),
                    },
                    field.name.location,
                )]);
            }

            parent_types.insert(type_);
            let selections = generate_selections_from_fields(
                schema,
                schema_config,
                &object.fields,
                parent_types,
            )?;
            parent_types.remove(&type_);

            Ok(Selection::LinkedField(Arc::new(LinkedField {
                alias: None,
                definition: WithLocation::generated(*field_id),
                arguments: vec![],
                directives: vec![],
                selections,
            })))
        }
        Type::InputObject(_) => Err(vec![Diagnostic::error(
            ValidationMessage::RelayResolverOutputTypeInvalidInputObjectType {
                field_name: field.name.item,
                type_name: schema.get_type_name(type_),
            },
            field.name.location,
        )]),
        Type::Union(_) => Err(vec![Diagnostic::error(
            ValidationMessage::RelayResolverOutputTypeUnsupported {
                type_kind: "union".intern(),
                field_name: field.name.item,
                type_name: schema.get_type_name(type_),
            },
            field.name.location,
        )]),
        Type::Interface(_) => Err(vec![Diagnostic::error(
            ValidationMessage::RelayResolverOutputTypeUnsupported {
                type_kind: "interface".intern(),
                field_name: field.name.item,
                type_name: schema.get_type_name(type_),
            },
            field.name.location,
        )]),
    }
}

pub(crate) fn generate_name_for_nested_object_operation(
    schema: &SDLSchema,
    field: &Field,
) -> WithLocation<OperationDefinitionName> {
    let parent_type = field
        .parent_type
        .unwrap_or_else(|| panic!("Expected parent type for field {:?}.", field));

    let normalization_name = get_normalization_operation_name(
        format!("{}__{}", schema.get_type_name(parent_type), field.name.item).intern(),
    )
    .intern();

    field
        .name
        .map(|_| OperationDefinitionName(normalization_name))
}

pub fn generate_relay_resolvers_operations_for_nested_objects(
    program: &Program,
    schema_config: &SchemaConfig,
) -> DiagnosticsResult<Program> {
    let mut operations = vec![];
    let mut errors = vec![];
    for field in program.schema.get_fields() {
        if !field.is_extension {
            continue;
        }

        if let Some(directive) = field.directives.named(*RELAY_RESOLVER_DIRECTIVE_NAME) {
            let has_output_type =
                get_bool_argument_is_true(&directive.arguments, *HAS_OUTPUT_TYPE_ARGUMENT_NAME);
            if !has_output_type {
                continue;
            }

            // Allow scalar/enums as @outputType
            if field.type_.inner().is_scalar() || field.type_.inner().is_enum() {
                continue;
            }

            let selections = match generate_fat_selections_from_type(
                &program.schema,
                schema_config,
                field.type_.inner(),
                field.name,
            ) {
                Ok(selections) => selections,
                Err(err) => {
                    errors.extend(err);
                    vec![]
                }
            };

            if !errors.is_empty() {
                continue;
            }

            let operation_name = generate_name_for_nested_object_operation(&program.schema, field);
            let directives = vec![
                SplitOperationMetadata {
                    location: field.name.location,
                    parent_documents: Default::default(),
                    derived_from: None,
                    raw_response_type_generation_mode: Some(
                        RawResponseGenerationMode::AllFieldsRequired,
                    ),
                }
                .to_directive(),
            ];

            let operation = OperationDefinition {
                name: operation_name,
                type_: field.type_.inner(),
                variable_definitions: vec![],
                directives,
                selections,
                kind: OperationKind::Query,
            };

            operations.push(Arc::new(operation))
        }
    }

    if errors.is_empty() {
        if operations.is_empty() {
            Ok(program.clone())
        } else {
            let mut next_program = program.clone();

            for operation in operations {
                next_program.insert_operation(operation)
            }

            Ok(next_program)
        }
    } else {
        Err(errors)
    }
}
<commit_msg>Minor cleanup in generate_relay_resolvers_operations_for_nested_objects<commit_after>/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */

use std::collections::HashSet;
use std::sync::Arc;

use common::ArgumentName;
use common::Diagnostic;
use common::DiagnosticsResult;
use common::NamedItem;
use common::WithLocation;
use graphql_ir::reexport::StringKey;
use graphql_ir::LinkedField;
use graphql_ir::OperationDefinition;
use graphql_ir::OperationDefinitionName;
use graphql_ir::Program;
use graphql_ir::ScalarField;
use graphql_ir::Selection;
use graphql_syntax::OperationKind;
use intern::string_key::Intern;
use lazy_static::lazy_static;
use relay_config::SchemaConfig;
use schema::Field;
use schema::FieldID;
use schema::ObjectID;
use schema::SDLSchema;
use schema::Schema;
use schema::Type;

use crate::get_normalization_operation_name;
use crate::match_::RawResponseGenerationMode;
use crate::relay_resolvers::get_bool_argument_is_true;
use crate::relay_resolvers::RELAY_RESOLVER_DIRECTIVE_NAME;
use crate::SplitOperationMetadata;
use crate::ValidationMessage;

lazy_static! {
    pub static ref HAS_OUTPUT_TYPE_ARGUMENT_NAME: ArgumentName =
        ArgumentName("has_output_type".intern());
}

fn generate_fat_selections_from_type(
    schema: &SDLSchema,
    schema_config: &SchemaConfig,
    type_: Type,
    field_name: WithLocation<StringKey>,
) -> DiagnosticsResult<Vec<Selection>> {
    match type_ {
        Type::Object(object_id) => {
            let object = schema.object(object_id);
            if !object.is_extension {
                return Err(vec![Diagnostic::error(
                    ValidationMessage::RelayResolverServerTypeNotSupported {
                        field_name: field_name.item,
                        type_name: schema.get_type_name(type_),
                    },
                    field_name.location,
                )]);
            }

            let mut parent_types = HashSet::new();
            parent_types.insert(type_);
            generate_selections_from_object_fields(
                schema,
                schema_config,
                &object.fields,
                &mut parent_types,
            )
        }
        Type::Enum(_) => Err(vec![Diagnostic::error(
            ValidationMessage::RelayResolverOutputTypeUnsupported {
                type_kind: "enum".intern(),
                field_name: field_name.item,
                type_name: schema.get_type_name(type_),
            },
            field_name.location,
        )]),
        Type::Scalar(_) => Err(vec![Diagnostic::error(
            ValidationMessage::RelayResolverOutputTypeUnsupported {
                type_kind: "scalar".intern(),
                field_name: field_name.item,
                type_name: schema.get_type_name(type_),
            },
            field_name.location,
        )]),
        Type::InputObject(_) => Err(vec![Diagnostic::error(
            ValidationMessage::RelayResolverOutputTypeInvalidInputObjectType {
                field_name: field_name.item,
                type_name: schema.get_type_name(type_),
            },
            field_name.location,
        )]),
        Type::Interface(_) => Err(vec![Diagnostic::error(
            ValidationMessage::RelayResolverOutputTypeUnsupported {
                type_kind: "interface".intern(),
                field_name: field_name.item,
                type_name: schema.get_type_name(type_),
            },
            field_name.location,
        )]),
        Type::Union(_) => Err(vec![Diagnostic::error(
            ValidationMessage::RelayResolverOutputTypeUnsupported {
                type_kind: "union".intern(),
                field_name: field_name.item,
                type_name: schema.get_type_name(type_),
            },
            field_name.location,
        )]),
    }
}

fn generate_selections_from_object_fields(
    schema: &SDLSchema,
    schema_config: &SchemaConfig,
    field_ids: &[FieldID],
    parent_types: &mut HashSet<Type>,
) -> DiagnosticsResult<Vec<Selection>> {
    let mut errors = vec![];
    let mut selections = vec![];
    for field_id in field_ids {
        if schema
            .field(*field_id)
            .directives
            .named(*RELAY_RESOLVER_DIRECTIVE_NAME)
            .is_some()
        {
            continue;
        }
        match generate_selection_from_field(schema, schema_config, field_id, parent_types) {
            Ok(selection) => selections.push(selection),
            Err(err) => {
                errors.extend(err);
            }
        }
    }
    if errors.is_empty() {
        Ok(selections)
    } else {
        Err(errors)
    }
}

fn generate_selection_from_field(
    schema: &SDLSchema,
    schema_config: &SchemaConfig,
    field_id: &FieldID,
    parent_types: &mut HashSet<Type>,
) -> DiagnosticsResult<Selection> {
    let field = schema.field(*field_id);
    let type_ = field.type_.inner();
    if field.name.item == schema_config.node_interface_id_field {
        return Err(vec![Diagnostic::error(
            ValidationMessage::RelayResolverIDFieldNotSupported {
                id_name: field.name.item,
            },
            field.name.location,
        )]);
    }

    if !field.arguments.is_empty() {
        return Err(vec![Diagnostic::error(
            ValidationMessage::RelayResolverArgumentsNotSupported,
            field.name.location,
        )]);
    }

    match type_ {
        Type::Enum(_) => Ok(Selection::ScalarField(Arc::new(ScalarField {
            alias: None,
            definition: WithLocation::generated(*field_id),
            arguments: vec![],
            directives: vec![],
        }))),
        Type::Scalar(_) => Ok(Selection::ScalarField(Arc::new(ScalarField {
            alias: None,
            definition: WithLocation::generated(*field_id),
            arguments: vec![],
            directives: vec![],
        }))),
        Type::Object(object_id) => {
            let selections = generate_selections_from_object(
                object_id,
                parent_types,
                schema,
                schema_config,
                field,
            )?;
            Ok(Selection::LinkedField(Arc::new(LinkedField {
                alias: None,
                definition: WithLocation::generated(*field_id),
                arguments: vec![],
                directives: vec![],
                selections,
            })))
        }
        Type::InputObject(_) => Err(vec![Diagnostic::error(
            ValidationMessage::RelayResolverOutputTypeInvalidInputObjectType {
                field_name: field.name.item,
                type_name: schema.get_type_name(type_),
            },
            field.name.location,
        )]),
        Type::Union(_) => Err(vec![Diagnostic::error(
            ValidationMessage::RelayResolverOutputTypeUnsupported {
                type_kind: "union".intern(),
                field_name: field.name.item,
                type_name: schema.get_type_name(type_),
            },
            field.name.location,
        )]),
        Type::Interface(_) => Err(vec![Diagnostic::error(
            ValidationMessage::RelayResolverOutputTypeUnsupported {
                type_kind: "interface".intern(),
                field_name: field.name.item,
                type_name: schema.get_type_name(type_),
            },
            field.name.location,
        )]),
    }
}

fn generate_selections_from_object(
    object_id: ObjectID,
    parent_types: &mut HashSet<Type>,
    schema: &SDLSchema,
    schema_config: &SchemaConfig,
    field: &Field,
) -> Result<Vec<Selection>, Vec<Diagnostic>> {
    let object = schema.object(object_id);
    let type_ = Type::Object(object_id);

    if !object.is_extension {
        return Err(vec![Diagnostic::error(
            ValidationMessage::RelayResolverServerTypeNotSupported {
                field_name: field.name.item,
                type_name: object.name.item.0,
            },
            field.name.location,
        )]);
    }

    if parent_types.contains(&type_) {
        return Err(vec![Diagnostic::error(
            ValidationMessage::RelayResolverTypeRecursionDetected {
                type_name: object.name.item.0,
            },
            field.name.location,
        )]);
    }
    parent_types.insert(type_);
    let selections = generate_selections_from_object_fields(
        schema,
        schema_config,
        &object.fields,
        parent_types,
    )?;
    parent_types.remove(&type_);

    Ok(selections)
}

pub(crate) fn generate_name_for_nested_object_operation(
    schema: &SDLSchema,
    field: &Field,
) -> WithLocation<OperationDefinitionName> {
    let parent_type = field
        .parent_type
        .unwrap_or_else(|| panic!("Expected parent type for field {:?}.", field));

    let normalization_name = get_normalization_operation_name(
        format!("{}__{}", schema.get_type_name(parent_type), field.name.item).intern(),
    )
    .intern();

    field
        .name
        .map(|_| OperationDefinitionName(normalization_name))
}

pub fn generate_relay_resolvers_operations_for_nested_objects(
    program: &Program,
    schema_config: &SchemaConfig,
) -> DiagnosticsResult<Program> {
    let mut operations = vec![];
    let mut errors = vec![];
    for field in program.schema.get_fields() {
        if !field.is_extension {
            continue;
        }

        if let Some(directive) = field.directives.named(*RELAY_RESOLVER_DIRECTIVE_NAME) {
            let has_output_type =
                get_bool_argument_is_true(&directive.arguments, *HAS_OUTPUT_TYPE_ARGUMENT_NAME);
            if !has_output_type {
                continue;
            }

            // Allow scalar/enums as @outputType
            if field.type_.inner().is_scalar() || field.type_.inner().is_enum() {
                continue;
            }

            let selections = match generate_fat_selections_from_type(
                &program.schema,
                schema_config,
                field.type_.inner(),
                field.name,
            ) {
                Ok(selections) => selections,
                Err(err) => {
                    errors.extend(err);
                    vec![]
                }
            };

            if !errors.is_empty() {
                continue;
            }

            let operation_name = generate_name_for_nested_object_operation(&program.schema, field);
            let directives = vec![
                SplitOperationMetadata {
                    location: field.name.location,
                    parent_documents: Default::default(),
                    derived_from: None,
                    raw_response_type_generation_mode: Some(
                        RawResponseGenerationMode::AllFieldsRequired,
                    ),
                }
                .to_directive(),
            ];

            let operation = OperationDefinition {
                name: operation_name,
                type_: field.type_.inner(),
                variable_definitions: vec![],
                directives,
                selections,
                kind: OperationKind::Query,
            };

            operations.push(Arc::new(operation))
        }
    }

    if errors.is_empty() {
        if operations.is_empty() {
            Ok(program.clone())
        } else {
            let mut next_program = program.clone();

            for operation in operations {
                next_program.insert_operation(operation)
            }

            Ok(next_program)
        }
    } else {
        Err(errors)
    }
}
<|endoftext|>


<commit_before>use crate::acpi::hpet::Hpet;

static LEG_RT_CNF: u64 = 2;
static ENABLE_CNF: u64 = 1;

static TN_VAL_SET_CNF: u64 = 0x40;
static TN_TYPE_CNF: u64 = 0x08;
static TN_INT_ENB_CNF: u64 = 0x04;

static CAPABILITY_OFFSET: usize = 0x00;
static GENERAL_CONFIG_OFFSET: usize = 0x10;
// static GENERAL_INTERRUPT_OFFSET: usize = 0x20;
// static MAIN_COUNTER_OFFSET: usize = 0xF0;
// static NUM_TIMER_CAP_MASK: u64 = 0x0f00;
static LEG_RT_CAP: u64 = 0x8000;
static T0_CONFIG_CAPABILITY_OFFSET: usize = 0x100;
static T0_COMPARATOR_OFFSET: usize = 0x108;

static PER_INT_CAP: u64 = 0x10;

pub unsafe fn init(hpet: &mut Hpet) -> bool {
    let capability = hpet.base_address.read_u64(CAPABILITY_OFFSET);
    if capability & LEG_RT_CAP == 0 {
        return false;
    }

    let counter_clk_period_fs = capability >> 32;
    let desired_fs_period: u64 = 2_250_286 * 1_000_000;

    let clk_periods_per_kernel_tick: u64 = desired_fs_period / counter_clk_period_fs;

    let t0_capabilities = hpet.base_address.read_u64(T0_CONFIG_CAPABILITY_OFFSET);
    if t0_capabilities & PER_INT_CAP == 0 {
        return false;
    }

    let t0_config_word: u64 = TN_VAL_SET_CNF | TN_TYPE_CNF | TN_INT_ENB_CNF;
    hpet.base_address.write_u64(T0_CONFIG_CAPABILITY_OFFSET, t0_config_word);
    hpet.base_address.write_u64(T0_COMPARATOR_OFFSET, clk_periods_per_kernel_tick);
    // set accumulator value
    hpet.base_address.write_u64(T0_COMPARATOR_OFFSET, clk_periods_per_kernel_tick);
    // set interval

    let enable_word: u64 = hpet.base_address.read_u64(GENERAL_CONFIG_OFFSET) | LEG_RT_CNF | ENABLE_CNF;
    hpet.base_address.write_u64(GENERAL_CONFIG_OFFSET, enable_word);
    // Enable interrupts from the HPET

    true
}
<commit_msg>Log reasons why HPET not used<commit_after>use crate::acpi::hpet::Hpet;

static LEG_RT_CNF: u64 = 2;
static ENABLE_CNF: u64 = 1;

static TN_VAL_SET_CNF: u64 = 0x40;
static TN_TYPE_CNF: u64 = 0x08;
static TN_INT_ENB_CNF: u64 = 0x04;

static CAPABILITY_OFFSET: usize = 0x00;
static GENERAL_CONFIG_OFFSET: usize = 0x10;
// static GENERAL_INTERRUPT_OFFSET: usize = 0x20;
// static MAIN_COUNTER_OFFSET: usize = 0xF0;
// static NUM_TIMER_CAP_MASK: u64 = 0x0f00;
static LEG_RT_CAP: u64 = 0x8000;
static T0_CONFIG_CAPABILITY_OFFSET: usize = 0x100;
static T0_COMPARATOR_OFFSET: usize = 0x108;

static PER_INT_CAP: u64 = 0x10;

pub unsafe fn init(hpet: &mut Hpet) -> bool {
    let capability = hpet.base_address.read_u64(CAPABILITY_OFFSET);
    if capability & LEG_RT_CAP == 0 {
        log::warn!("HPET missing capability LEG_RT_CAP");
        return false;
    }

    let counter_clk_period_fs = capability >> 32;
    let desired_fs_period: u64 = 2_250_286 * 1_000_000;

    let clk_periods_per_kernel_tick: u64 = desired_fs_period / counter_clk_period_fs;

    let t0_capabilities = hpet.base_address.read_u64(T0_CONFIG_CAPABILITY_OFFSET);
    if t0_capabilities & PER_INT_CAP == 0 {
        log::warn!("HPET T0 missing capability PER_INT_CAP");
        return false;
    }

    let t0_config_word: u64 = TN_VAL_SET_CNF | TN_TYPE_CNF | TN_INT_ENB_CNF;
    hpet.base_address.write_u64(T0_CONFIG_CAPABILITY_OFFSET, t0_config_word);
    hpet.base_address.write_u64(T0_COMPARATOR_OFFSET, clk_periods_per_kernel_tick);
    // set accumulator value
    hpet.base_address.write_u64(T0_COMPARATOR_OFFSET, clk_periods_per_kernel_tick);
    // set interval

    let enable_word: u64 = hpet.base_address.read_u64(GENERAL_CONFIG_OFFSET) | LEG_RT_CNF | ENABLE_CNF;
    hpet.base_address.write_u64(GENERAL_CONFIG_OFFSET, enable_word);
    // Enable interrupts from the HPET

    true
}
<|endoftext|>


<commit_before>use std::time::Duration;

#[derive(Default, Clone)]
struct FrameInfo {
    frame: u32,
    elapsed: Duration,
}

impl FrameInfo {
    fn new(frame: u32, elapsed: Duration) -> Self {
        FrameInfo {
            frame: frame,
            elapsed: elapsed,
        }
    }

    fn elapse(&self, elapsed: Duration) -> Self {
        FrameInfo::new(self.frame, elapsed)
    }
}

#[derive(Clone)]
pub struct FrameAnimator {
    max: u32,
    duration: Duration,
    repeat: bool,
    current: Option<FrameInfo>,
}

impl FrameAnimator {
    pub fn new(max: u32, duration: Duration, repeat: bool) -> FrameAnimator {
        FrameAnimator {
            max: max,
            duration: duration,
            repeat: repeat,
            current: None,
        }
    }

    pub fn frame(&self) -> Option<u32> {
        self.current.as_ref().map(|c| c.frame)
    }

    pub fn animate(&mut self, delta: Duration) {
        self.current =
            self.current.as_ref().map_or(Some(FrameInfo::default()), |i| self.advance(i, delta));
    }

    pub fn num_frames(&self) -> u32 {
        self.max
    }

    fn advance(&self, current: &FrameInfo, delta: Duration) -> Option<FrameInfo> {
        let elapsed = current.elapsed + delta;
        elapsed.checked_sub(self.duration)
            .map_or(Some(current.elapse(elapsed)), |r| self.next(current, r))
    }

    fn next(&self, current: &FrameInfo, remaining: Duration) -> Option<FrameInfo> {
        let frame = (current.frame + 1) % self.max;
        if frame > 0 || self.repeat {
            Some(FrameInfo::new(frame, remaining))
        } else {
            None
        }
    }
}
<commit_msg>refactor frame_animator<commit_after>use std::time::Duration;

#[derive(Default, Clone)]
struct FrameInfo {
    frame: u32,
    elapsed: Duration,
}

impl FrameInfo {
    fn new(frame: u32, elapsed: Duration) -> Self {
        FrameInfo {
            frame: frame,
            elapsed: elapsed,
        }
    }

    fn elapse(&self, elapsed: Duration) -> Self {
        FrameInfo::new(self.frame, elapsed)
    }
}

#[derive(Clone)]
pub struct FrameAnimator {
    max: u32,
    duration: Duration,
    repeat: bool,
    current: Option<FrameInfo>,
}

impl FrameAnimator {
    pub fn new(max: u32, duration: Duration, repeat: bool) -> FrameAnimator {
        FrameAnimator {
            max: max,
            duration: duration,
            repeat: repeat,
            current: None,
        }
    }

    pub fn frame(&self) -> Option<u32> {
        self.current.as_ref().map(|c| c.frame)
    }

    pub fn num_frames(&self) -> u32 {
        self.max
    }

    pub fn animate(&mut self, delta: Duration) {
        self.current = self.current.as_ref().map_or(Some(Default::default()), |frame| {
            let elapsed = frame.elapsed + delta;
            elapsed.checked_sub(self.duration)
                .map_or(Some(frame.elapse(elapsed)), |r| self.next(frame, r))
        });
    }

    fn next(&self, current: &FrameInfo, remaining: Duration) -> Option<FrameInfo> {
        let frame = (current.frame + 1) % self.max;
        if frame > 0 || self.repeat {
            Some(FrameInfo::new(frame, remaining))
        } else {
            None
        }
    }
}
<|endoftext|>


<commit_before>
use crate::utils::is_stop_char;
use crate::Lang;
use super::Outcome;

const BUL: &'static str = "АаБбВвГгДдЕеЖжЗзИиЙйКкЛлМмНнОоПпРрСсТтУуФфХхЦцЧчШшЩщЪъЬьЮюЯя";
const RUS: &'static str = "АаБбВвГгДдЕеЁёЖжЗзИиЙйКкЛлМмНнОоПпРрСсТтУуФфХхЦцЧчШшЩщЪъЫыЬьЭэЮюЯя";
const UKR: &'static str = "АаБбВвГгҐґДдЕеЄєЖжЗзИиІіЇїЙйКкЛлМмНнОоПпРрСсТтУуФфХхЦцЧчШшЩщЬьЮюЯя";
const BEL: &'static str = "АаБбВвГгДдЕеЁёЖжЗзІіЙйКкЛлМмНнОоПпРрСсТтУуЎўФфХхЦцЧчШшЫыЬьЭэЮюЯя";
const SRP: &'static str = "АаБбВвГгДдЂђЕеЖжЗзИиЈјКкЛлЉљМмНнЊњОоПпРрСсТтЋћУуФфХхЦцЧчЏџШш";
const MKD: &'static str = "АаБбВвГгДдЃѓЕеЖжЗзЅѕИиЈјКкЛлЉљМмНнЊњОоПпРрСсТтЌќУуФфХхЦцЧчЏџШш";

fn get_lang_chars(lang: Lang) -> Vec<char> {
    let alphabet = match lang {
        Lang::Rus => RUS,
        Lang::Ukr => UKR,
        Lang::Bul => BUL,
        Lang::Bel => BEL,
        Lang::Srp => SRP,
        Lang::Mkd => MKD,
        _ => panic!(format!("No alphabet for {}", lang)),
    };
    alphabet.chars().collect()
}

pub fn alphabet_calculate_scores(text: &str) -> Outcome {
    let mut raw_scores = vec![
        (Lang::Rus, 0),
        (Lang::Ukr, 0),
        (Lang::Bul, 0),
        (Lang::Bel, 0),
        (Lang::Mkd, 0),
        (Lang::Srp, 0),
    ];

    let max_raw_score = text.chars().filter(|&ch| !is_stop_char(ch)).count();

    for (lang, score) in &mut raw_scores {
        let alphabet = get_lang_chars(*lang);

        for ch in text.chars() {
            if is_stop_char(ch) {
                continue;
            };
            if alphabet.contains(&ch) {
                *score += 1;
            } else {
                *score -= 1;
            }
        }
    }

    raw_scores.sort_by(|a, b| b.1.cmp(&a.1));

    let mut normalized_scores = vec![];

    for (index, &(lang, raw_score)) in raw_scores.iter().enumerate() {
        let normalized_score = raw_score as f64 / max_raw_score as f64;
        normalized_scores[index] = (lang, normalized_score);
    }

    Outcome {
        max_raw_score,
        raw_scores,
        normalized_scores,
    }
}
<commit_msg>Fix some bugs<commit_after>
use crate::utils::is_stop_char;
use crate::Lang;
use super::Outcome;

const BUL: &'static str = "АаБбВвГгДдЕеЖжЗзИиЙйКкЛлМмНнОоПпРрСсТтУуФфХхЦцЧчШшЩщЪъЬьЮюЯя";
const RUS: &'static str = "АаБбВвГгДдЕеЁёЖжЗзИиЙйКкЛлМмНнОоПпРрСсТтУуФфХхЦцЧчШшЩщЪъЫыЬьЭэЮюЯя";
const UKR: &'static str = "АаБбВвГгҐґДдЕеЄєЖжЗзИиІіЇїЙйКкЛлМмНнОоПпРрСсТтУуФфХхЦцЧчШшЩщЬьЮюЯя";
const BEL: &'static str = "АаБбВвГгДдЕеЁёЖжЗзІіЙйКкЛлМмНнОоПпРрСсТтУуЎўФфХхЦцЧчШшЫыЬьЭэЮюЯя";
const SRP: &'static str = "АаБбВвГгДдЂђЕеЖжЗзИиЈјКкЛлЉљМмНнЊњОоПпРрСсТтЋћУуФфХхЦцЧчЏџШш";
const MKD: &'static str = "АаБбВвГгДдЃѓЕеЖжЗзЅѕИиЈјКкЛлЉљМмНнЊњОоПпРрСсТтЌќУуФфХхЦцЧчЏџШш";

fn get_lang_chars(lang: Lang) -> Vec<char> {
    let alphabet = match lang {
        Lang::Rus => RUS,
        Lang::Ukr => UKR,
        Lang::Bul => BUL,
        Lang::Bel => BEL,
        Lang::Srp => SRP,
        Lang::Mkd => MKD,
        _ => panic!(format!("No alphabet for {}", lang)),
    };
    alphabet.chars().collect()
}

pub fn alphabet_calculate_scores(text: &str) -> Outcome {
    let mut raw_scores = vec![
        (Lang::Rus, 0i32),
        (Lang::Ukr, 0i32),
        (Lang::Bul, 0i32),
        (Lang::Bel, 0i32),
        (Lang::Mkd, 0i32),
        (Lang::Srp, 0i32),
    ];

    let max_raw_score = text.chars().filter(|&ch| !is_stop_char(ch)).count();

    for (lang, score) in &mut raw_scores {
        let alphabet = get_lang_chars(*lang);

        for ch in text.chars() {
            if is_stop_char(ch) {
                continue;
            };
            if alphabet.contains(&ch) {
                *score += 1;
            } else {
                *score -= 1;
            }
        }
    }

    raw_scores.sort_by(|a, b| b.1.cmp(&a.1));

    let raw_scores: Vec<(Lang, usize)> = raw_scores
        .into_iter()
        .map(|(l, s)| {
            let score = if s < 0 { 0usize } else { s as usize };
            (l, score)
        })
        .collect();

    let mut normalized_scores = vec![];

    for &(lang, raw_score) in &raw_scores {
        let normalized_score = raw_score as f64 / max_raw_score as f64;
        normalized_scores.push((lang, normalized_score));
    }

    Outcome {
        max_raw_score,
        raw_scores,
        normalized_scores,
    }
}
<|endoftext|>


<commit_before>use crate::compiler::expression_parsers::expression;
use crate::compiler::operand_parsers::*;
use crate::compiler::tokens::Token;

use nom::types::CompleteStr;
use nom::*;

named!(pub factor<CompleteStr, Token>,
    ws!(
        do_parse!(
            f: alt!(
                real |
                ws!(delimited!(tag!("("), expression, tag!(")"))) |
                ident
            ) >>
            (
                {
                    Token::Factor{value: Box::new(f)}
                }
            )
        )
    )
);

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

    #[test]
    fn test_factor() {
        // TODO: fill these test cases out.
        let result = factor(CompleteStr("(1+2)"));
        assert!(result.is_ok());
        let (_, tree) = result.unwrap();
        println!("{:?}", tree);

        let result = factor(CompleteStr("3.0 + foo"));
        assert!(result.is_ok());
        let (_, tree) = result.unwrap();
        println!("{:?}", tree);
    }
}
<commit_msg>fill out factor test cases<commit_after>use crate::compiler::expression_parsers::expression;
use crate::compiler::operand_parsers::*;
use crate::compiler::tokens::Token;

use nom::types::CompleteStr;
use nom::*;

named!(pub factor<CompleteStr, Token>,
    ws!(
        do_parse!(
            f: alt!(
                real |
                ws!(delimited!(tag!("("), expression, tag!(")"))) |
                ident
            ) >>
            (
                {
                    Token::Factor{value: Box::new(f)}
                }
            )
        )
    )
);

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

    #[test]
    fn test_factor() {
        let result = factor(CompleteStr("(1+2)"));
        assert!(result.is_ok());
        let (_, tree) = result.unwrap();
        assert_eq!(
            tree,
            Token::Factor {
                value: Box::new(Token::Expression {
                    left: Box::new(Token::Term {
                        left: Box::new(Token::Factor {
                            value: Box::new(Token::Real { value: 1.0 })
                        }),
                        right: vec![]
                    }),
                    right: vec![(
                        Token::AdditionOp,
                        Token::Term {
                            left: Box::new(Token::Factor {
                                value: Box::new(Token::Real { value: 2.0 })
                            }),
                            right: vec![]
                        }
                    )]
                })
            }
        );

        let result = factor(CompleteStr("3.0 + foo"));
        assert!(result.is_ok());
        let (_, tree) = result.unwrap();
        assert_eq!(
            tree,
            Token::Factor {
                value: Box::new(Token::Real { value: 3.0 })
            }
        );
    }
}
<|endoftext|>


<commit_before>#![feature(nll)]
#![feature(proc_macro_hygiene, decl_macro)]

extern crate getopts;

#[macro_use] extern crate rocket;
#[macro_use] extern crate rocket_contrib;

#[macro_use] extern crate serde_derive;

extern crate pombase;

use std::sync::Mutex;
use std::process;
use std::env;
use std::path::{Path, PathBuf};

use getopts::Options;
use rocket_contrib::json::{Json, JsonValue};
use rocket::response::NamedFile;

use pombase::api::query::Query as PomBaseQuery;
use pombase::api::result::QueryAPIResult;
use pombase::api::search::Search;
use pombase::api::query_exec::QueryExec;
use pombase::api::server_data::ServerData;
use pombase::web::data::{SolrTermSummary, SolrReferenceSummary, GeneDetails, GenotypeDetails,
                         TermDetails, ReferenceDetails};
use pombase::web::config::Config;

const PKG_NAME: &str = env!("CARGO_PKG_NAME");
const VERSION: &str = env!("CARGO_PKG_VERSION");

struct StaticFileState {
    web_root_dir: String,
}

// If the path is a directory, return path+"/index.html".  Otherwise
// try the path, then try path + ".json", then default to loading the
// Angular app from /index.html
#[get("/<path..>", rank=3)]
fn get_misc(path: PathBuf, state: rocket::State<Mutex<StaticFileState>>) -> Option<NamedFile> {
    let web_root_dir = &state.lock().expect("failed to lock").web_root_dir;
    let root_dir_path = Path::new("/").join(web_root_dir);
    let full_path = root_dir_path.join(path);

    if full_path.is_dir() {
        let index_path = full_path.join("index.html");
        return NamedFile::open(index_path).ok();
    }

    if full_path.exists() {
        return NamedFile::open(full_path).ok();
    }

    let mut json_path_str = full_path.to_str().unwrap().to_owned();
    json_path_str += ".json";
    let json_path: PathBuf = json_path_str.into();

    if json_path.exists() {
        return NamedFile::open(json_path).ok();
    }

    NamedFile::open(root_dir_path.join("index.html")).ok()
}

#[get("/api/v1/dataset/latest/data/gene/<id>", rank=2)]
fn get_gene(id: String, state: rocket::State<Mutex<QueryExec>>) -> Option<Json<GeneDetails>> {
    let query_exec = state.lock().expect("failed to lock");
    if let Some(gene) = query_exec.get_server_data().get_full_gene_details(&id) {
        Some(Json(gene))
    } else {
        None
    }
}

#[get("/api/v1/dataset/latest/data/genotype/<id>", rank=2)]
fn get_genotype(id: String, state: rocket::State<Mutex<QueryExec>>) -> Option<Json<GenotypeDetails>> {
    let query_exec = state.lock().expect("failed to lock");
    if let Some(genotype) = query_exec.get_server_data().get_genotype_details(&id) {
        Some(Json(genotype))
    } else {
        None
    }
}

#[get("/api/v1/dataset/latest/data/term/<id>", rank=2)]
fn get_term(id: String, state: rocket::State<Mutex<QueryExec>>) -> Option<Json<TermDetails>> {
    let query_exec = state.lock().expect("failed to lock");
    if let Some(term) = query_exec.get_server_data().get_term_details(&id) {
        Some(Json(term))
    } else {
        None
    }
}

#[get("/api/v1/dataset/latest/data/reference/<id>", rank=2)]
fn get_reference(id: String, state: rocket::State<Mutex<QueryExec>>) -> Option<Json<ReferenceDetails>> {
    let query_exec = state.lock().expect("failed to lock");
    if let Some(reference) = query_exec.get_server_data().get_reference_details(&id) {
        Some(Json(reference))
    } else {
        None
    }
}

#[get("/", rank=1)]
fn get_index(state: rocket::State<Mutex<StaticFileState>>) -> Option<NamedFile> {
    let web_root_dir = &state.lock().expect("failed to lock").web_root_dir;
    let root_dir_path = Path::new("/").join(web_root_dir);
    NamedFile::open(root_dir_path.join("index.html")).ok()
}

#[post("/api/v1/dataset/latest/query", rank=1, data="<q>", format = "application/json")]
fn query_post(q: Json<PomBaseQuery>, state: rocket::State<Mutex<QueryExec>>)
              -> Option<Json<QueryAPIResult>>
{
    let query_exec = state.lock().expect("failed to lock");
    Some(Json(query_exec.exec(&q.into_inner())))
}

#[get ("/reload")]
fn reload(state: rocket::State<Mutex<QueryExec>>) {
    let mut query_exec = state.lock().expect("failed to lock");
    print!("reloading ...\n");
    query_exec.reload();
    print!("... done\n");
}

#[derive(Serialize, Debug)]
struct TermCompletionResponse {
    status: String,
    matches: Vec<SolrTermSummary>,
}

#[derive(Serialize, Debug)]
struct RefCompletionResponse {
    status: String,
    matches: Vec<SolrReferenceSummary>,
}

#[get ("/api/v1/dataset/latest/complete/term/<cv_name>/<q>", rank=1)]
fn term_complete(cv_name: String, q: String, state: rocket::State<Mutex<Search>>)
              -> Option<Json<TermCompletionResponse>>
{
    let search = state.lock().expect("failed to lock");
    let res = search.term_complete(&cv_name, &q);

    let completion_response =
        match res {
            Ok(matches) => {
                TermCompletionResponse {
                    status: "Ok".to_owned(),
                    matches: matches,
                }
            },
            Err(err) => {
                println!("{:?}", err);
                TermCompletionResponse {
                    status: "Error".to_owned(),
                    matches: vec![],
                }
            },
        };

    Some(Json(completion_response))
}

#[get ("/api/v1/dataset/latest/complete/ref/<q>", rank=1)]
fn ref_complete(q: String, state: rocket::State<Mutex<Search>>)
                -> Option<Json<RefCompletionResponse>>
{
    let search = state.lock().expect("failed to lock");
    let res = search.ref_complete(&q);

    let completion_response =
        match res {
            Ok(matches) => {
                RefCompletionResponse {
                    status: "Ok".to_owned(),
                    matches: matches,
                }
            },
            Err(err) => {
                println!("{:?}", err);
                RefCompletionResponse {
                    status: "Error".to_owned(),
                    matches: vec![],
                }
            },
        };

    Some(Json(completion_response))
}

#[get ("/api/v1/dataset/latest/motif_search/<scope>/<q>", rank=1)]
fn motif_search(scope: String, q: String, state: rocket::State<Mutex<Search>>)
                -> Option<String>
{
    let search = state.lock().expect("failed to lock");
    let res = search.motif_search(&scope, &q);

    match res {
        Ok(search_result) => {
            Some(search_result)
        },
        Err(err) => {
            println!("Motif search error: {:?}", err);
            None
        },
    }
}

#[get ("/ping", rank=1)]
fn ping() -> Option<String> {
    Some(String::from("OK") + " " + PKG_NAME + " " + VERSION)
}

#[catch(404)]
fn not_found() -> JsonValue {
    json!({
        "status": "error",
        "reason": "Resource was not found."
    })
}

fn print_usage(program: &str, opts: Options) {
    let brief = format!("Usage: {} [options]", program);
    print!("{}", opts.usage(&brief));
}

fn main() {
    print!("{} v{}\n", PKG_NAME, VERSION);

    let args: Vec<String> = env::args().collect();
    let mut opts = Options::new();

    opts.optflag("h", "help", "print this help message");
    opts.optopt("c", "config-file", "Configuration file name", "CONFIG");
    opts.optopt("m", "search-maps", "Search data", "MAPS_JSON_FILE");
    opts.optopt("w", "web-root-dir", "Root web data directory", "WEB_ROOT_DIR");

    let matches = match opts.parse(&args[1..]) {
        Ok(m) => m,
        Err(f) => panic!("Invalid options\n{}", f)
    };

    let program = args[0].clone();

    if matches.opt_present("help") {
        print_usage(&program, opts);
        process::exit(0);
    }

    if !matches.opt_present("config-file") {
        print!("no -c|--config-file option\n");
        print_usage(&program, opts);
        process::exit(1);
    }
    if !matches.opt_present("search-maps") {
        print!("no --search-maps|-m option\n");
        print_usage(&program, opts);
        process::exit(1);
    }
    if !matches.opt_present("web-root-dir") {
        print!("no --web-root-dir|-w option\n");
        print_usage(&program, opts);
        process::exit(1);
    }

    let search_maps_filename = matches.opt_str("m").unwrap();
    println!("Reading data files ...");

    let config_file_name = matches.opt_str("c").unwrap();
    let server_data = ServerData::new(&config_file_name, &search_maps_filename);
    let query_exec = QueryExec::new(server_data);
    let config = Config::read(&config_file_name);
    let searcher = Search::new(&config);

    let web_root_dir = matches.opt_str("w").unwrap();
    let static_file_state = StaticFileState {
        web_root_dir: web_root_dir,
    };

    println!("Starting server ...");
    rocket::ignite()
        .mount("/", routes![get_index, get_misc, query_post,
                            get_gene, get_genotype, get_term, get_reference,
                            reload, term_complete, ref_complete,
                            motif_search, ping])
        .register(catchers![not_found])
        .manage(Mutex::new(query_exec))
        .manage(Mutex::new(searcher))
        .manage(Mutex::new(static_file_state))
        .launch();
}
<commit_msg>Add code for debugging paths<commit_after>#![feature(nll)]
#![feature(proc_macro_hygiene, decl_macro)]

extern crate getopts;

#[macro_use] extern crate rocket;
#[macro_use] extern crate rocket_contrib;

#[macro_use] extern crate serde_derive;

extern crate pombase;

use std::sync::Mutex;
use std::process;
use std::env;
use std::path::{Path, PathBuf};

use getopts::Options;
use rocket_contrib::json::{Json, JsonValue};
use rocket::response::NamedFile;

use pombase::api::query::Query as PomBaseQuery;
use pombase::api::result::QueryAPIResult;
use pombase::api::search::Search;
use pombase::api::query_exec::QueryExec;
use pombase::api::server_data::ServerData;
use pombase::web::data::{SolrTermSummary, SolrReferenceSummary, GeneDetails, GenotypeDetails,
                         TermDetails, ReferenceDetails};
use pombase::web::config::Config;

const PKG_NAME: &str = env!("CARGO_PKG_NAME");
const VERSION: &str = env!("CARGO_PKG_VERSION");

struct StaticFileState {
    web_root_dir: String,
}

// If the path is a directory, return path+"/index.html".  Otherwise
// try the path, then try path + ".json", then default to loading the
// Angular app from /index.html
#[get("/<path..>", rank=3)]
fn get_misc(path: PathBuf, state: rocket::State<Mutex<StaticFileState>>) -> Option<NamedFile> {
    let web_root_dir = &state.lock().expect("failed to lock").web_root_dir;
    let root_dir_path = Path::new("/").join(web_root_dir);
    let full_path = root_dir_path.join(path);

    print!("attempting to serve this path: {}\n", full_path.display());

    if full_path.is_dir() {
        let index_path = full_path.join("index.html");
        print!("found directory for {}, returning index.html\n", full_path.display());
        return NamedFile::open(index_path).ok();
    }

    if full_path.exists() {
        print!("found file for {}, returning index.html\n", full_path.display());
        return NamedFile::open(full_path).ok();
    }

    let mut json_path_str = full_path.to_str().unwrap().to_owned();
    json_path_str += ".json";
    let json_path: PathBuf = json_path_str.into();

    if json_path.exists() {
        print!("found JSON file for {}, returning index.html\n", full_path.display());
        return NamedFile::open(json_path).ok();
    }

    print!("for {}, /index.html\n", full_path.display());

    NamedFile::open(root_dir_path.join("index.html")).ok()
}

#[get("/api/v1/dataset/latest/data/gene/<id>", rank=2)]
fn get_gene(id: String, state: rocket::State<Mutex<QueryExec>>) -> Option<Json<GeneDetails>> {
    let query_exec = state.lock().expect("failed to lock");
    if let Some(gene) = query_exec.get_server_data().get_full_gene_details(&id) {
        Some(Json(gene))
    } else {
        None
    }
}

#[get("/api/v1/dataset/latest/data/genotype/<id>", rank=2)]
fn get_genotype(id: String, state: rocket::State<Mutex<QueryExec>>) -> Option<Json<GenotypeDetails>> {
    let query_exec = state.lock().expect("failed to lock");
    if let Some(genotype) = query_exec.get_server_data().get_genotype_details(&id) {
        Some(Json(genotype))
    } else {
        None
    }
}

#[get("/api/v1/dataset/latest/data/term/<id>", rank=2)]
fn get_term(id: String, state: rocket::State<Mutex<QueryExec>>) -> Option<Json<TermDetails>> {
    let query_exec = state.lock().expect("failed to lock");
    if let Some(term) = query_exec.get_server_data().get_term_details(&id) {
        Some(Json(term))
    } else {
        None
    }
}

#[get("/api/v1/dataset/latest/data/reference/<id>", rank=2)]
fn get_reference(id: String, state: rocket::State<Mutex<QueryExec>>) -> Option<Json<ReferenceDetails>> {
    let query_exec = state.lock().expect("failed to lock");
    if let Some(reference) = query_exec.get_server_data().get_reference_details(&id) {
        Some(Json(reference))
    } else {
        None
    }
}

#[get("/", rank=1)]
fn get_index(state: rocket::State<Mutex<StaticFileState>>) -> Option<NamedFile> {
    let web_root_dir = &state.lock().expect("failed to lock").web_root_dir;
    let root_dir_path = Path::new("/").join(web_root_dir);
    NamedFile::open(root_dir_path.join("index.html")).ok()
}

#[post("/api/v1/dataset/latest/query", rank=1, data="<q>", format = "application/json")]
fn query_post(q: Json<PomBaseQuery>, state: rocket::State<Mutex<QueryExec>>)
              -> Option<Json<QueryAPIResult>>
{
    let query_exec = state.lock().expect("failed to lock");
    Some(Json(query_exec.exec(&q.into_inner())))
}

#[get ("/reload")]
fn reload(state: rocket::State<Mutex<QueryExec>>) {
    let mut query_exec = state.lock().expect("failed to lock");
    print!("reloading ...\n");
    query_exec.reload();
    print!("... done\n");
}

#[derive(Serialize, Debug)]
struct TermCompletionResponse {
    status: String,
    matches: Vec<SolrTermSummary>,
}

#[derive(Serialize, Debug)]
struct RefCompletionResponse {
    status: String,
    matches: Vec<SolrReferenceSummary>,
}

#[get ("/api/v1/dataset/latest/complete/term/<cv_name>/<q>", rank=1)]
fn term_complete(cv_name: String, q: String, state: rocket::State<Mutex<Search>>)
              -> Option<Json<TermCompletionResponse>>
{
    let search = state.lock().expect("failed to lock");
    let res = search.term_complete(&cv_name, &q);

    let completion_response =
        match res {
            Ok(matches) => {
                TermCompletionResponse {
                    status: "Ok".to_owned(),
                    matches: matches,
                }
            },
            Err(err) => {
                println!("{:?}", err);
                TermCompletionResponse {
                    status: "Error".to_owned(),
                    matches: vec![],
                }
            },
        };

    Some(Json(completion_response))
}

#[get ("/api/v1/dataset/latest/complete/ref/<q>", rank=1)]
fn ref_complete(q: String, state: rocket::State<Mutex<Search>>)
                -> Option<Json<RefCompletionResponse>>
{
    let search = state.lock().expect("failed to lock");
    let res = search.ref_complete(&q);

    let completion_response =
        match res {
            Ok(matches) => {
                RefCompletionResponse {
                    status: "Ok".to_owned(),
                    matches: matches,
                }
            },
            Err(err) => {
                println!("{:?}", err);
                RefCompletionResponse {
                    status: "Error".to_owned(),
                    matches: vec![],
                }
            },
        };

    Some(Json(completion_response))
}

#[get ("/api/v1/dataset/latest/motif_search/<scope>/<q>", rank=1)]
fn motif_search(scope: String, q: String, state: rocket::State<Mutex<Search>>)
                -> Option<String>
{
    let search = state.lock().expect("failed to lock");
    let res = search.motif_search(&scope, &q);

    match res {
        Ok(search_result) => {
            Some(search_result)
        },
        Err(err) => {
            println!("Motif search error: {:?}", err);
            None
        },
    }
}

#[get ("/ping", rank=1)]
fn ping() -> Option<String> {
    Some(String::from("OK") + " " + PKG_NAME + " " + VERSION)
}

#[catch(404)]
fn not_found() -> JsonValue {
    json!({
        "status": "error",
        "reason": "Resource was not found."
    })
}

fn print_usage(program: &str, opts: Options) {
    let brief = format!("Usage: {} [options]", program);
    print!("{}", opts.usage(&brief));
}

fn main() {
    print!("{} v{}\n", PKG_NAME, VERSION);

    let args: Vec<String> = env::args().collect();
    let mut opts = Options::new();

    opts.optflag("h", "help", "print this help message");
    opts.optopt("c", "config-file", "Configuration file name", "CONFIG");
    opts.optopt("m", "search-maps", "Search data", "MAPS_JSON_FILE");
    opts.optopt("w", "web-root-dir", "Root web data directory", "WEB_ROOT_DIR");

    let matches = match opts.parse(&args[1..]) {
        Ok(m) => m,
        Err(f) => panic!("Invalid options\n{}", f)
    };

    let program = args[0].clone();

    if matches.opt_present("help") {
        print_usage(&program, opts);
        process::exit(0);
    }

    if !matches.opt_present("config-file") {
        print!("no -c|--config-file option\n");
        print_usage(&program, opts);
        process::exit(1);
    }
    if !matches.opt_present("search-maps") {
        print!("no --search-maps|-m option\n");
        print_usage(&program, opts);
        process::exit(1);
    }
    if !matches.opt_present("web-root-dir") {
        print!("no --web-root-dir|-w option\n");
        print_usage(&program, opts);
        process::exit(1);
    }

    let search_maps_filename = matches.opt_str("m").unwrap();
    println!("Reading data files ...");

    let config_file_name = matches.opt_str("c").unwrap();
    let server_data = ServerData::new(&config_file_name, &search_maps_filename);
    let query_exec = QueryExec::new(server_data);
    let config = Config::read(&config_file_name);
    let searcher = Search::new(&config);

    let web_root_dir = matches.opt_str("w").unwrap();
    let static_file_state = StaticFileState {
        web_root_dir: web_root_dir,
    };

    println!("Starting server ...");
    rocket::ignite()
        .mount("/", routes![get_index, get_misc, query_post,
                            get_gene, get_genotype, get_term, get_reference,
                            reload, term_complete, ref_complete,
                            motif_search, ping])
        .register(catchers![not_found])
        .manage(Mutex::new(query_exec))
        .manage(Mutex::new(searcher))
        .manage(Mutex::new(static_file_state))
        .launch();
}
<|endoftext|>


<commit_before>use std::fmt::Display;
use std::io::{self, Write};

pub fn echo<S: Display>(message: S) {
    print!("{}", message);
    if let Err(why) = io::stdout().flush() {
        panic!("{}", why);
    }
}

pub fn read_line_from_stdin() -> Result<String, io::Error>  {
    let mut input = String::new();
    io::stdin().read_line(&mut input)
        .map(|_| input.trim().to_string())
}

pub enum Tag {
    Execution,
    Notice,
    Warning,
    Error,
    Okay,
    Caution,
}

pub fn format_with_tag<S: Display>(indent_level: usize, tag: Tag, message: S) -> String {
    let indent = (0 .. indent_level).map(|_| "  ").collect::<String>();

    let tag = match tag {
        Tag::Execution => "EXECUTION",
        Tag::Notice    => "NOTICE",
        Tag::Warning   => "WARNING",
        Tag::Error     => "ERROR",
        Tag::Okay      => "OK",
        Tag::Caution   => "CAUTION",
    };

    format!("{}{}: {}", indent, tag, message)
}

pub fn print_with_tag<S: Display>(indent_level: usize, tag: Tag, message: S) {
    println!("{}", format_with_tag(indent_level, tag, message));
}
<commit_msg>[Refactoring] Just reorder Tag<commit_after>use std::fmt::Display;
use std::io::{self, Write};

pub fn echo<S: Display>(message: S) {
    print!("{}", message);
    if let Err(why) = io::stdout().flush() {
        panic!("{}", why);
    }
}

pub fn read_line_from_stdin() -> Result<String, io::Error>  {
    let mut input = String::new();
    io::stdin().read_line(&mut input)
        .map(|_| input.trim().to_string())
}

pub enum Tag {
    Execution,
    Okay,
    Notice,
    Warning,
    Error,
    Caution,
}

pub fn format_with_tag<S: Display>(indent_level: usize, tag: Tag, message: S) -> String {
    let indent = (0 .. indent_level).map(|_| "  ").collect::<String>();

    let tag = match tag {
        Tag::Execution => "EXECUTION",
        Tag::Okay      => "OK",
        Tag::Notice    => "NOTICE",
        Tag::Warning   => "WARNING",
        Tag::Error     => "ERROR",
        Tag::Caution   => "CAUTION",
    };

    format!("{}{}: {}", indent, tag, message)
}

pub fn print_with_tag<S: Display>(indent_level: usize, tag: Tag, message: S) {
    println!("{}", format_with_tag(indent_level, tag, message));
}
<|endoftext|>


<commit_before>//! MIPS

// Building this module (even if unused) for non-fp64 targets such as the Sony
// PSP fails with an LLVM error. There doesn't seem to be a good way to detect
// fp64 support as it is sometimes implied by the target cpu, so
// `#[cfg(target_feature = "fp64")]` will unfortunately not work. This is a
// fairly conservative workaround that only disables MSA intrinsics for the PSP.
#[cfg(not(target_os = "psp"))]
mod msa;
#[cfg(not(target_os = "psp"))]
pub use self::msa::*;

#[cfg(test)]
use stdarch_test::assert_instr;

/// Generates the trap instruction `BREAK`
#[cfg_attr(test, assert_instr(break))]
#[inline]
pub unsafe fn break_() -> ! {
    crate::intrinsics::abort()
}
<commit_msg>Use fp64 detection instead of OS blacklist<commit_after>//! MIPS

// Building this module (even if unused) for non-fp64 targets fails with an LLVM
// error.
#[cfg(target_feature = "fp64")]
mod msa;
#[cfg(target_feature = "fp64")]
pub use self::msa::*;

#[cfg(test)]
use stdarch_test::assert_instr;

/// Generates the trap instruction `BREAK`
#[cfg_attr(test, assert_instr(break))]
#[inline]
pub unsafe fn break_() -> ! {
    crate::intrinsics::abort()
}
<|endoftext|>