<commit_before>//! A crate for writing odbc clients in safe Rust
//!
//! This crate is only concerned about providing safe bindings to ODBC. It does not try to provide
//! convinience or idiomatic usage on top. This is left to higher level crates.
//!
//! # Desgin decisions:
//! * Constructing a child is not considered to mutate the parent. This is necessare so a parent
//!   handle can be referenced by several child handles.
//! * Any transition in the ODBC State machine is modelled in the type system. This prevents
//!   Function Sequence errors. See [ODBC State Transition Tables][1]
//! [1]: https://docs.microsoft.com/en-us/sql/odbc/reference/appendixes/appendix-b-odbc-state-transition-tables
#![warn(missing_docs, missing_debug_implementations, missing_copy_implementations, trivial_casts,
        trivial_numeric_casts, unused_import_braces, unused_qualifications
)]

extern crate odbc_sys;

pub use return_::{Return, Success, Info, Error};
pub use environment::Environment;
pub use connection::Connection;
pub use version::{NoVersion, Odbc3, Odbc3m8};
pub use sql_str::SqlStr;
pub use diagnostics::{Diagnostics, DiagResult, DiagReturn};
use version::Version;
use handles::{Handle, HEnv, HDbc};

mod version;
mod return_;
mod sql_str;
mod handles;
mod diagnostics;
mod environment;
mod connection;
<commit_msg>shorten link for formatting<commit_after>//! A crate for writing odbc clients in safe Rust
//!
//! This crate is only concerned about providing safe bindings to ODBC. It does not try to provide
//! convinience or idiomatic usage on top. This is left to higher level crates.
//!
//! # Desgin decisions:
//! * Constructing a child is not considered to mutate the parent. This is necessare so a parent
//!   handle can be referenced by several child handles.
//! * Any transition in the ODBC State machine is modelled in the type system. This prevents
//!   Function Sequence errors. See [ODBC State Transition Tables][1]
//! [1]: https://docs.microsoft.com/sql/odbc/reference/appendixes/appendix-b-odbc-state-transition-tables
#![warn(missing_docs, missing_debug_implementations, missing_copy_implementations, trivial_casts,
        trivial_numeric_casts, unused_import_braces, unused_qualifications
)]

extern crate odbc_sys;

pub use return_::{Return, Success, Info, Error};
pub use environment::Environment;
pub use connection::Connection;
pub use version::{NoVersion, Odbc3, Odbc3m8};
pub use sql_str::SqlStr;
pub use diagnostics::{Diagnostics, DiagResult, DiagReturn};
use version::Version;
use handles::{Handle, HEnv, HDbc};

mod version;
mod return_;
mod sql_str;
mod handles;
mod diagnostics;
mod environment;
mod connection;
<|endoftext|>


<commit_before>extern crate rand;

use self::rand::seq::SliceRandom;

/// Convenience function to generate a new petname from default word lists.
pub fn petname(words: u8, separator: &str) -> String {
    Petnames::default().generate(&mut rand::thread_rng(), words, separator)
}

/// Word lists and the logic to combine them into _petnames_.
///
/// A _petname_ with `n` words will contain, in order:
///
///   * 1 adjective when `n >= 2`, otherwise 0 adjectives.
///   * `n - 2` adverbs when `n >= 2`.
///   * 1 name / noun.
///
pub struct Petnames<'a> {
    pub adjectives: Vec<&'a str>,
    pub adverbs: Vec<&'a str>,
    pub names: Vec<&'a str>,
}

impl<'a> Petnames<'a> {
    /// Constructs a new `Petnames` with default word lists.
    pub fn default() -> Petnames<'a> {
        let adjectives = concat!(
            include_str!("../words/large/adjectives.txt"),
            "\n",
            include_str!("../words/medium/adjectives.txt"),
            "\n",
            include_str!("../words/small/adjectives.txt"),
            "\n",
        );
        let adverbs = concat!(
            include_str!("../words/large/adverbs.txt"),
            "\n",
            include_str!("../words/medium/adverbs.txt"),
            "\n",
            include_str!("../words/small/adverbs.txt"),
            "\n",
        );
        let names = concat!(
            include_str!("../words/large/names.txt"),
            "\n",
            include_str!("../words/medium/names.txt"),
            "\n",
            include_str!("../words/small/names.txt"),
            "\n",
        );
        Self {
            adjectives: adjectives.split_whitespace().collect(),
            adverbs: adverbs.split_whitespace().collect(),
            names: names.split_whitespace().collect(),
        }
    }

    /// Generate a new petname.
    ///
    /// # Examples
    ///
    /// ```rust
    /// # extern crate rand;
    /// # extern crate petname;
    /// let mut rng = rand::thread_rng();
    /// petname::Petnames::default().generate(&mut rng, 7, ":");
    /// ```
    pub fn generate<RNG>(&self, rng: &mut RNG, words: u8, separator: &str) -> String
    where
        RNG: rand::Rng,
    {
        // Adverbs all the way, finishing with adjective then name.
        let mut parts = Vec::with_capacity(words as usize);
        for num in (0..words).rev() {
            parts.push(*match num {
                0 => self.names.choose(rng).unwrap(),
                1 => self.adjectives.choose(rng).unwrap(),
                _ => self.adverbs.choose(rng).unwrap(),
            });
        }
        parts.join(separator)
    }
}

#[cfg(test)]
mod tests {

    use super::{petname, rand, Petnames};

    #[test]
    fn default_petnames_has_adjectives() {
        let petnames = Petnames::default();
        assert_ne!(petnames.adjectives.len(), 0);
    }

    #[test]
    fn default_petnames_has_adverbs() {
        let petnames = Petnames::default();
        assert_ne!(petnames.adverbs.len(), 0);
    }

    #[test]
    fn default_petnames_has_names() {
        let petnames = Petnames::default();
        assert_ne!(petnames.names.len(), 0);
    }

    #[test]
    fn generate_uses_adverb_adjective_name() {
        let petnames = Petnames {
            adjectives: vec!["adjective"],
            adverbs: vec!["adverb"],
            names: vec!["name"],
        };
        assert_eq!(
            petnames.generate(&mut rand::thread_rng(), 3, "-"),
            "adverb-adjective-name"
        );
    }

    #[test]
    fn petname_renders_desired_number_of_words() {
        assert_eq!(petname(7, "-").split("-").count(), 7);
    }

    #[test]
    fn petname_renders_with_desired_separator() {
        assert_eq!(petname(7, "@").split("@").count(), 7);
    }
}
<commit_msg>Default word list is small.<commit_after>extern crate rand;

use self::rand::seq::SliceRandom;

/// Convenience function to generate a new petname from default word lists.
pub fn petname(words: u8, separator: &str) -> String {
    Petnames::default().generate(&mut rand::thread_rng(), words, separator)
}

/// Word lists and the logic to combine them into _petnames_.
///
/// A _petname_ with `n` words will contain, in order:
///
///   * 1 adjective when `n >= 2`, otherwise 0 adjectives.
///   * `n - 2` adverbs when `n >= 2`.
///   * 1 name / noun.
///
pub struct Petnames<'a> {
    pub adjectives: Vec<&'a str>,
    pub adverbs: Vec<&'a str>,
    pub names: Vec<&'a str>,
}

impl<'a> Petnames<'a> {
    /// Constructs a new `Petnames` from the default (small) word lists.
    pub fn default() -> Petnames<'a> {
        Self::small()
    }

    /// Constructs a new `Petnames` from the small word lists.
    pub fn small() -> Petnames<'a> {
        Self::init(
            include_str!("../words/small/adjectives.txt"),
            include_str!("../words/small/adverbs.txt"),
            include_str!("../words/small/names.txt"),
        )
    }

    /// Constructs a new `Petnames` from the medium word lists.
    pub fn medium() -> Petnames<'a> {
        Self::init(
            include_str!("../words/medium/adjectives.txt"),
            include_str!("../words/medium/adverbs.txt"),
            include_str!("../words/medium/names.txt"),
        )
    }

    /// Constructs a new `Petnames` from the large word lists.
    pub fn large() -> Petnames<'a> {
        Self::init(
            include_str!("../words/large/adjectives.txt"),
            include_str!("../words/large/adverbs.txt"),
            include_str!("../words/large/names.txt"),
        )
    }

    fn init(adjectives: &'a str, adverbs: &'a str, names: &'a str) -> Petnames<'a> {
        Self {
            adjectives: adjectives.split_whitespace().collect(),
            adverbs: adverbs.split_whitespace().collect(),
            names: names.split_whitespace().collect(),
        }
    }

    /// Generate a new petname.
    ///
    /// # Examples
    ///
    /// ```rust
    /// # extern crate rand;
    /// # extern crate petname;
    /// let mut rng = rand::thread_rng();
    /// petname::Petnames::default().generate(&mut rng, 7, ":");
    /// ```
    pub fn generate<RNG>(&self, rng: &mut RNG, words: u8, separator: &str) -> String
    where
        RNG: rand::Rng,
    {
        // Adverbs all the way, finishing with adjective then name.
        let mut parts = Vec::with_capacity(words as usize);
        for num in (0..words).rev() {
            parts.push(*match num {
                0 => self.names.choose(rng).unwrap(),
                1 => self.adjectives.choose(rng).unwrap(),
                _ => self.adverbs.choose(rng).unwrap(),
            });
        }
        parts.join(separator)
    }
}

#[cfg(test)]
mod tests {

    use super::{petname, rand, Petnames};

    #[test]
    fn default_petnames_has_adjectives() {
        let petnames = Petnames::default();
        assert_ne!(petnames.adjectives.len(), 0);
    }

    #[test]
    fn default_petnames_has_adverbs() {
        let petnames = Petnames::default();
        assert_ne!(petnames.adverbs.len(), 0);
    }

    #[test]
    fn default_petnames_has_names() {
        let petnames = Petnames::default();
        assert_ne!(petnames.names.len(), 0);
    }

    #[test]
    fn generate_uses_adverb_adjective_name() {
        let petnames = Petnames {
            adjectives: vec!["adjective"],
            adverbs: vec!["adverb"],
            names: vec!["name"],
        };
        assert_eq!(
            petnames.generate(&mut rand::thread_rng(), 3, "-"),
            "adverb-adjective-name"
        );
    }

    #[test]
    fn petname_renders_desired_number_of_words() {
        assert_eq!(petname(7, "-").split("-").count(), 7);
    }

    #[test]
    fn petname_renders_with_desired_separator() {
        assert_eq!(petname(7, "@").split("@").count(), 7);
    }
}
<|endoftext|>


<commit_before>#![feature(
    rustc_private,
    macro_at_most_once_rep,
    never_type,
    extern_crate_item_prelude
)]
#![allow(intra_doc_link_resolution_failure)]

extern crate byteorder;
extern crate syntax;
#[macro_use]
extern crate rustc;
extern crate rustc_allocator;
extern crate rustc_codegen_utils;
extern crate rustc_incremental;
extern crate rustc_mir;
extern crate rustc_target;
#[macro_use]
extern crate rustc_data_structures;

extern crate ar;
#[macro_use]
extern crate bitflags;
extern crate faerie;
//extern crate goblin;
extern crate cranelift;
extern crate cranelift_faerie;
extern crate cranelift_module;
extern crate cranelift_simplejit;
extern crate target_lexicon;

use std::any::Any;
use std::sync::mpsc;

use rustc::dep_graph::DepGraph;
use rustc::middle::cstore::MetadataLoader;
use rustc::session::{config::OutputFilenames, CompileIncomplete};
use rustc::ty::query::Providers;
use rustc_codegen_utils::codegen_backend::CodegenBackend;
use rustc_codegen_utils::link::out_filename;
use syntax::symbol::Symbol;

use cranelift::codegen::settings;
use cranelift_faerie::*;

struct NonFatal(pub String);

macro_rules! unimpl {
    ($($tt:tt)*) => {
        panic!(crate::NonFatal(format!($($tt)*)));
    };
}

mod abi;
mod allocator;
mod analyze;
mod base;
mod common;
mod constant;
mod intrinsics;
mod link;
mod main_shim;
mod metadata;
mod pretty_clif;
mod vtable;

mod prelude {
    pub use std::any::Any;
    pub use std::collections::{HashMap, HashSet};

    pub use syntax::ast::{FloatTy, IntTy, UintTy};
    pub use syntax::source_map::DUMMY_SP;

    pub use rustc::hir::def_id::{CrateNum, DefId, LOCAL_CRATE};
    pub use rustc::mir::{self, interpret::AllocId, *};
    pub use rustc::session::{config::{CrateType, Lto}, Session};
    pub use rustc::ty::layout::{self, Abi, LayoutOf, Scalar, Size, TyLayout};
    pub use rustc::ty::{
        self, subst::Substs, FnSig, Instance, InstanceDef, ParamEnv, PolyFnSig, Ty, TyCtxt,
        TypeAndMut, TypeFoldable,
    };
    pub use rustc_data_structures::{
        fx::{FxHashMap, FxHashSet},
        indexed_vec::Idx,
        sync::Lrc,
    };
    pub use rustc_mir::monomorphize::{collector, MonoItem};
    pub use rustc_codegen_utils::CompiledModule;

    pub use cranelift::codegen::ir::{
        condcodes::IntCC, function::Function, ExternalName, FuncRef, Inst, StackSlot,
    };
    pub use cranelift::codegen::isa::CallConv;
    pub use cranelift::codegen::Context;
    pub use cranelift::prelude::*;
    pub use cranelift_module::{Backend, DataContext, DataId, FuncId, Linkage, Module};
    pub use cranelift_simplejit::{SimpleJITBackend, SimpleJITBuilder};

    pub use crate::abi::*;
    pub use crate::base::{trans_operand, trans_place};
    pub use crate::common::*;
    pub use crate::{Caches, CodegenResults};
}

use std::fs::File;
use std::io::Write;

use crate::constant::ConstantCx;
use crate::prelude::*;

pub struct Caches<'tcx> {
    pub context: Context,
    pub vtables: HashMap<(Ty<'tcx>, ty::PolyExistentialTraitRef<'tcx>), DataId>,
}

impl<'tcx> Caches<'tcx> {
    fn new() -> Self {
        Caches {
            context: Context::new(),
            vtables: HashMap::new(),
        }
    }
}

struct CraneliftCodegenBackend;

pub struct CodegenResults {
    artifact: faerie::Artifact,
    metadata: Vec<u8>,
    crate_name: Symbol,
}

impl CodegenBackend for CraneliftCodegenBackend {
    fn init(&self, sess: &Session) {
        for cty in sess.opts.crate_types.iter() {
            match *cty {
                CrateType::Rlib | CrateType::Dylib | CrateType::Executable => {}
                _ => {
                    sess.err(&format!(
                        "Rustc codegen cranelift doesn't support output type {}",
                        cty
                    ));
                }
            }
        }
        match sess.lto() {
            Lto::Fat | Lto::Thin | Lto::ThinLocal => {
                sess.warn("Rustc codegen cranelift doesn't support lto");
            }
            Lto::No => {},
        }
        if sess.opts.cg.rpath {
            sess.err("rpath is not yet supported");
        }
        if sess.opts.debugging_opts.pgo_gen.is_some() {
            sess.err("pgo is not supported");
        }
    }

    fn metadata_loader(&self) -> Box<MetadataLoader + Sync> {
        Box::new(crate::metadata::CraneliftMetadataLoader)
    }

    fn provide(&self, providers: &mut Providers) {
        rustc_codegen_utils::symbol_names::provide(providers);
        rustc_codegen_utils::symbol_export::provide(providers);

        providers.target_features_whitelist = |_tcx, _cnum| Lrc::new(Default::default());
    }
    fn provide_extern(&self, providers: &mut Providers) {
        rustc_codegen_utils::symbol_export::provide_extern(providers);
    }

    fn codegen_crate<'a, 'tcx>(
        &self,
        tcx: TyCtxt<'a, 'tcx, 'tcx>,
        _rx: mpsc::Receiver<Box<Any + Send>>,
    ) -> Box<Any> {
        if !tcx.sess.crate_types.get().contains(&CrateType::Executable)
            && std::env::var("SHOULD_RUN").is_ok()
        {
            tcx.sess
                .err("Can't JIT run non executable (SHOULD_RUN env var is set)");
        }

        tcx.sess.abort_if_errors();

        let metadata = tcx.encode_metadata();

        let mut flags_builder = settings::builder();
        flags_builder.enable("is_pic").unwrap();
        let flags = settings::Flags::new(flags_builder);
        let isa =
            cranelift::codegen::isa::lookup(tcx.sess.target.target.llvm_target.parse().unwrap())
                .unwrap()
                .finish(flags);

        // TODO: move to the end of this function when compiling libcore doesn't have unimplemented stuff anymore
        save_incremental(tcx);
        tcx.sess.warn("Saved incremental data");

        let mut log = if cfg!(debug_assertions) {
            Some(File::create(concat!(env!("CARGO_MANIFEST_DIR"), "/target/out/log.txt"))
                    .unwrap())
        } else {
            None
        };

        if std::env::var("SHOULD_RUN").is_ok() {
            let mut jit_module: Module<SimpleJITBackend> = Module::new(SimpleJITBuilder::new());
            assert_eq!(pointer_ty(tcx), jit_module.target_config().pointer_type());

            let sig = Signature {
                params: vec![
                    AbiParam::new(jit_module.target_config().pointer_type()),
                    AbiParam::new(jit_module.target_config().pointer_type()),
                ],
                returns: vec![AbiParam::new(
                    jit_module.target_config().pointer_type(), /*isize*/
                )],
                call_conv: CallConv::SystemV,
            };
            let main_func_id = jit_module
                .declare_function("main", Linkage::Import, &sig)
                .unwrap();

            codegen_mono_items(tcx, &mut jit_module, &mut log);

            tcx.sess.abort_if_errors();
            println!("Compiled everything");
            println!("Rustc codegen cranelift will JIT run the executable, because the SHOULD_RUN env var is set");

            let finalized_main: *const u8 = jit_module.get_finalized_function(main_func_id);
            println!("🎉 Finalized everything");

            let f: extern "C" fn(isize, *const *const u8) -> isize =
                unsafe { ::std::mem::transmute(finalized_main) };
            let res = f(0, 0 as *const _);
            tcx.sess.warn(&format!("🚀 main returned {}", res));

            jit_module.finish();
            ::std::process::exit(0);
        } else {
            let mut faerie_module: Module<FaerieBackend> = Module::new(
                FaerieBuilder::new(
                    isa,
                    "some_file.o".to_string(),
                    FaerieTrapCollection::Disabled,
                    FaerieBuilder::default_libcall_names(),
                )
                .unwrap(),
            );
            assert_eq!(
                pointer_ty(tcx),
                faerie_module.target_config().pointer_type()
            );

            codegen_mono_items(tcx, &mut faerie_module, &mut log);

            tcx.sess.abort_if_errors();

            return Box::new(CodegenResults {
                artifact: faerie_module.finish().artifact,
                metadata: metadata.raw_data,
                crate_name: tcx.crate_name(LOCAL_CRATE),
            });
        }
    }

    fn join_codegen_and_link(
        &self,
        res: Box<Any>,
        sess: &Session,
        _dep_graph: &DepGraph,
        outputs: &OutputFilenames,
    ) -> Result<(), CompileIncomplete> {
        let res = *res
            .downcast::<CodegenResults>()
            .expect("Expected CraneliftCodegenBackend's CodegenResult, found Box<Any>");

        for &crate_type in sess.opts.crate_types.iter() {
            let output_name = out_filename(sess, crate_type, &outputs, &res.crate_name.as_str());
            match crate_type {
                CrateType::Rlib => link::link_rlib(sess, &res, output_name),
                CrateType::Executable => link::link_bin(sess, &res, output_name),
                _ => sess.fatal(&format!("Unsupported crate type: {:?}", crate_type)),
            }
        }
        Ok(())
    }
}

fn codegen_mono_items<'a, 'tcx: 'a>(
    tcx: TyCtxt<'a, 'tcx, 'tcx>,
    module: &mut Module<impl Backend + 'static>,
    log: &mut Option<File>,
) {
    let mut caches = Caches::new();
    let mut ccx = ConstantCx::default();

    let (_, cgus) = tcx.collect_and_partition_mono_items(LOCAL_CRATE);
    let mono_items = cgus
        .iter()
        .map(|cgu| cgu.items().iter())
        .flatten()
        .collect::<FxHashSet<(_, _)>>();

    let before = ::std::time::Instant::now();
    println!("[codegen mono items] start");

    for (&mono_item, &(_linkage, _vis)) in mono_items {
        let res = ::std::panic::catch_unwind(::std::panic::AssertUnwindSafe(|| {
            base::trans_mono_item(tcx, module, &mut caches, &mut ccx, mono_item);
        }));

        if let Err(err) = res {
            match err.downcast::<NonFatal>() {
                Ok(non_fatal) => {
                    if cfg!(debug_assertions) {
                        writeln!(log.as_mut().unwrap(), "{}", &non_fatal.0).unwrap();
                    }
                    tcx.sess.err(&non_fatal.0)
                }
                Err(err) => ::std::panic::resume_unwind(err),
            }
        }
    }

    crate::main_shim::maybe_create_entry_wrapper(tcx, module);

    let any_dynamic_crate = tcx
        .sess
        .dependency_formats
        .borrow()
        .iter()
        .any(|(_, list)| {
            use rustc::middle::dependency_format::Linkage;
            list.iter().any(|&linkage| linkage == Linkage::Dynamic)
        });
    if any_dynamic_crate {
    } else if let Some(kind) = *tcx.sess.allocator_kind.get() {
        allocator::codegen(module, kind);
    }

    ccx.finalize(tcx, module);
    module.finalize_definitions();

    let after = ::std::time::Instant::now();
    println!("[codegen mono items] end time: {:?}", after - before);
}

fn save_incremental<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
    rustc_incremental::assert_dep_graph(tcx);
    rustc_incremental::save_dep_graph(tcx);
    rustc_incremental::finalize_session_directory(tcx.sess, tcx.crate_hash(LOCAL_CRATE));
}

/// This is the entrypoint for a hot plugged rustc_codegen_cranelift
#[no_mangle]
pub fn __rustc_codegen_backend() -> Box<CodegenBackend> {
    Box::new(CraneliftCodegenBackend)
}
<commit_msg>Rustfmt<commit_after>#![feature(
    rustc_private,
    macro_at_most_once_rep,
    never_type,
    extern_crate_item_prelude
)]
#![allow(intra_doc_link_resolution_failure)]

extern crate byteorder;
extern crate syntax;
#[macro_use]
extern crate rustc;
extern crate rustc_allocator;
extern crate rustc_codegen_utils;
extern crate rustc_incremental;
extern crate rustc_mir;
extern crate rustc_target;
#[macro_use]
extern crate rustc_data_structures;

extern crate ar;
#[macro_use]
extern crate bitflags;
extern crate faerie;
//extern crate goblin;
extern crate cranelift;
extern crate cranelift_faerie;
extern crate cranelift_module;
extern crate cranelift_simplejit;
extern crate target_lexicon;

use std::any::Any;
use std::fs::File;
use std::io::Write;
use std::sync::mpsc;

use syntax::symbol::Symbol;

use rustc::dep_graph::DepGraph;
use rustc::middle::cstore::MetadataLoader;
use rustc::session::{config::OutputFilenames, CompileIncomplete};
use rustc::ty::query::Providers;
use rustc_codegen_utils::codegen_backend::CodegenBackend;
use rustc_codegen_utils::link::out_filename;

use cranelift::codegen::settings;
use cranelift_faerie::*;

use crate::constant::ConstantCx;
use crate::prelude::*;

struct NonFatal(pub String);

macro_rules! unimpl {
    ($($tt:tt)*) => {
        panic!(crate::NonFatal(format!($($tt)*)));
    };
}

mod abi;
mod allocator;
mod analyze;
mod base;
mod common;
mod constant;
mod intrinsics;
mod link;
mod main_shim;
mod metadata;
mod pretty_clif;
mod vtable;

mod prelude {
    pub use std::any::Any;
    pub use std::collections::{HashMap, HashSet};

    pub use syntax::ast::{FloatTy, IntTy, UintTy};
    pub use syntax::source_map::DUMMY_SP;

    pub use rustc::hir::def_id::{CrateNum, DefId, LOCAL_CRATE};
    pub use rustc::mir::{self, interpret::AllocId, *};
    pub use rustc::session::{
        config::{CrateType, Lto},
        Session,
    };
    pub use rustc::ty::layout::{self, Abi, LayoutOf, Scalar, Size, TyLayout};
    pub use rustc::ty::{
        self, subst::Substs, FnSig, Instance, InstanceDef, ParamEnv, PolyFnSig, Ty, TyCtxt,
        TypeAndMut, TypeFoldable,
    };
    pub use rustc_codegen_utils::CompiledModule;
    pub use rustc_data_structures::{
        fx::{FxHashMap, FxHashSet},
        indexed_vec::Idx,
        sync::Lrc,
    };
    pub use rustc_mir::monomorphize::{collector, MonoItem};

    pub use cranelift::codegen::ir::{
        condcodes::IntCC, function::Function, ExternalName, FuncRef, Inst, StackSlot,
    };
    pub use cranelift::codegen::isa::CallConv;
    pub use cranelift::codegen::Context;
    pub use cranelift::prelude::*;
    pub use cranelift_module::{Backend, DataContext, DataId, FuncId, Linkage, Module};
    pub use cranelift_simplejit::{SimpleJITBackend, SimpleJITBuilder};

    pub use crate::abi::*;
    pub use crate::base::{trans_operand, trans_place};
    pub use crate::common::*;
    pub use crate::{Caches, CodegenResults};
}

pub struct Caches<'tcx> {
    pub context: Context,
    pub vtables: HashMap<(Ty<'tcx>, ty::PolyExistentialTraitRef<'tcx>), DataId>,
}

impl<'tcx> Caches<'tcx> {
    fn new() -> Self {
        Caches {
            context: Context::new(),
            vtables: HashMap::new(),
        }
    }
}

struct CraneliftCodegenBackend;

pub struct CodegenResults {
    artifact: faerie::Artifact,
    metadata: Vec<u8>,
    crate_name: Symbol,
}

impl CodegenBackend for CraneliftCodegenBackend {
    fn init(&self, sess: &Session) {
        for cty in sess.opts.crate_types.iter() {
            match *cty {
                CrateType::Rlib | CrateType::Dylib | CrateType::Executable => {}
                _ => {
                    sess.err(&format!(
                        "Rustc codegen cranelift doesn't support output type {}",
                        cty
                    ));
                }
            }
        }
        match sess.lto() {
            Lto::Fat | Lto::Thin | Lto::ThinLocal => {
                sess.warn("Rustc codegen cranelift doesn't support lto");
            }
            Lto::No => {}
        }
        if sess.opts.cg.rpath {
            sess.err("rpath is not yet supported");
        }
        if sess.opts.debugging_opts.pgo_gen.is_some() {
            sess.err("pgo is not supported");
        }
    }

    fn metadata_loader(&self) -> Box<MetadataLoader + Sync> {
        Box::new(crate::metadata::CraneliftMetadataLoader)
    }

    fn provide(&self, providers: &mut Providers) {
        rustc_codegen_utils::symbol_names::provide(providers);
        rustc_codegen_utils::symbol_export::provide(providers);

        providers.target_features_whitelist = |_tcx, _cnum| Lrc::new(Default::default());
    }
    fn provide_extern(&self, providers: &mut Providers) {
        rustc_codegen_utils::symbol_export::provide_extern(providers);
    }

    fn codegen_crate<'a, 'tcx>(
        &self,
        tcx: TyCtxt<'a, 'tcx, 'tcx>,
        _rx: mpsc::Receiver<Box<Any + Send>>,
    ) -> Box<Any> {
        if !tcx.sess.crate_types.get().contains(&CrateType::Executable)
            && std::env::var("SHOULD_RUN").is_ok()
        {
            tcx.sess
                .err("Can't JIT run non executable (SHOULD_RUN env var is set)");
        }

        tcx.sess.abort_if_errors();

        let metadata = tcx.encode_metadata();

        let mut flags_builder = settings::builder();
        flags_builder.enable("is_pic").unwrap();
        let flags = settings::Flags::new(flags_builder);
        let isa =
            cranelift::codegen::isa::lookup(tcx.sess.target.target.llvm_target.parse().unwrap())
                .unwrap()
                .finish(flags);

        // TODO: move to the end of this function when compiling libcore doesn't have unimplemented stuff anymore
        save_incremental(tcx);
        tcx.sess.warn("Saved incremental data");

        let mut log = if cfg!(debug_assertions) {
            Some(File::create(concat!(env!("CARGO_MANIFEST_DIR"), "/target/out/log.txt")).unwrap())
        } else {
            None
        };

        if std::env::var("SHOULD_RUN").is_ok() {
            let mut jit_module: Module<SimpleJITBackend> = Module::new(SimpleJITBuilder::new());
            assert_eq!(pointer_ty(tcx), jit_module.target_config().pointer_type());

            let sig = Signature {
                params: vec![
                    AbiParam::new(jit_module.target_config().pointer_type()),
                    AbiParam::new(jit_module.target_config().pointer_type()),
                ],
                returns: vec![AbiParam::new(
                    jit_module.target_config().pointer_type(), /*isize*/
                )],
                call_conv: CallConv::SystemV,
            };
            let main_func_id = jit_module
                .declare_function("main", Linkage::Import, &sig)
                .unwrap();

            codegen_mono_items(tcx, &mut jit_module, &mut log);

            tcx.sess.abort_if_errors();
            println!("Compiled everything");
            println!("Rustc codegen cranelift will JIT run the executable, because the SHOULD_RUN env var is set");

            let finalized_main: *const u8 = jit_module.get_finalized_function(main_func_id);
            println!("🎉 Finalized everything");

            let f: extern "C" fn(isize, *const *const u8) -> isize =
                unsafe { ::std::mem::transmute(finalized_main) };
            let res = f(0, 0 as *const _);
            tcx.sess.warn(&format!("🚀 main returned {}", res));

            jit_module.finish();
            ::std::process::exit(0);
        } else {
            let mut faerie_module: Module<FaerieBackend> = Module::new(
                FaerieBuilder::new(
                    isa,
                    "some_file.o".to_string(),
                    FaerieTrapCollection::Disabled,
                    FaerieBuilder::default_libcall_names(),
                )
                .unwrap(),
            );
            assert_eq!(
                pointer_ty(tcx),
                faerie_module.target_config().pointer_type()
            );

            codegen_mono_items(tcx, &mut faerie_module, &mut log);

            tcx.sess.abort_if_errors();

            return Box::new(CodegenResults {
                artifact: faerie_module.finish().artifact,
                metadata: metadata.raw_data,
                crate_name: tcx.crate_name(LOCAL_CRATE),
            });
        }
    }

    fn join_codegen_and_link(
        &self,
        res: Box<Any>,
        sess: &Session,
        _dep_graph: &DepGraph,
        outputs: &OutputFilenames,
    ) -> Result<(), CompileIncomplete> {
        let res = *res
            .downcast::<CodegenResults>()
            .expect("Expected CraneliftCodegenBackend's CodegenResult, found Box<Any>");

        for &crate_type in sess.opts.crate_types.iter() {
            let output_name = out_filename(sess, crate_type, &outputs, &res.crate_name.as_str());
            match crate_type {
                CrateType::Rlib => link::link_rlib(sess, &res, output_name),
                CrateType::Executable => link::link_bin(sess, &res, output_name),
                _ => sess.fatal(&format!("Unsupported crate type: {:?}", crate_type)),
            }
        }
        Ok(())
    }
}

fn codegen_mono_items<'a, 'tcx: 'a>(
    tcx: TyCtxt<'a, 'tcx, 'tcx>,
    module: &mut Module<impl Backend + 'static>,
    log: &mut Option<File>,
) {
    let mut caches = Caches::new();
    let mut ccx = ConstantCx::default();

    let (_, cgus) = tcx.collect_and_partition_mono_items(LOCAL_CRATE);
    let mono_items = cgus
        .iter()
        .map(|cgu| cgu.items().iter())
        .flatten()
        .collect::<FxHashSet<(_, _)>>();

    let before = ::std::time::Instant::now();
    println!("[codegen mono items] start");

    for (&mono_item, &(_linkage, _vis)) in mono_items {
        let res = ::std::panic::catch_unwind(::std::panic::AssertUnwindSafe(|| {
            base::trans_mono_item(tcx, module, &mut caches, &mut ccx, mono_item);
        }));

        if let Err(err) = res {
            match err.downcast::<NonFatal>() {
                Ok(non_fatal) => {
                    if cfg!(debug_assertions) {
                        writeln!(log.as_mut().unwrap(), "{}", &non_fatal.0).unwrap();
                    }
                    tcx.sess.err(&non_fatal.0)
                }
                Err(err) => ::std::panic::resume_unwind(err),
            }
        }
    }

    crate::main_shim::maybe_create_entry_wrapper(tcx, module);

    let any_dynamic_crate = tcx
        .sess
        .dependency_formats
        .borrow()
        .iter()
        .any(|(_, list)| {
            use rustc::middle::dependency_format::Linkage;
            list.iter().any(|&linkage| linkage == Linkage::Dynamic)
        });
    if any_dynamic_crate {
    } else if let Some(kind) = *tcx.sess.allocator_kind.get() {
        allocator::codegen(module, kind);
    }

    ccx.finalize(tcx, module);
    module.finalize_definitions();

    let after = ::std::time::Instant::now();
    println!("[codegen mono items] end time: {:?}", after - before);
}

fn save_incremental<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
    rustc_incremental::assert_dep_graph(tcx);
    rustc_incremental::save_dep_graph(tcx);
    rustc_incremental::finalize_session_directory(tcx.sess, tcx.crate_hash(LOCAL_CRATE));
}

/// This is the entrypoint for a hot plugged rustc_codegen_cranelift
#[no_mangle]
pub fn __rustc_codegen_backend() -> Box<CodegenBackend> {
    Box::new(CraneliftCodegenBackend)
}
<|endoftext|>


<commit_before>//! This crate provides a configuration loader in the style of the [ruby dotenv
//! gem](https://github.com/bkeepers/dotenv). This library is meant to be used
//! on development or testing environments in which setting environment
//! variables is not practical. It loads environment variables from a .env
//! file, if available, and mashes those with the actual environment variables
//! provided by the operating system.

extern crate regex;

use std::fs::File;
use std::io::{BufReader, BufRead};
use std::env;
use std::result::Result;
use std::path::Path;
use regex::{Captures, Regex, Error};

#[derive(Debug, Clone)]
pub enum DotenvError {
    Parsing {
        line: String,
    },
    ParseFormatter,
    Io,
    ExecutableNotFound,
}

impl From<regex::Error> for DotenvError {
    fn from(_: regex::Error) -> DotenvError {
        DotenvError::ParseFormatter
    }
}

impl From<std::io::Error> for DotenvError {
    fn from(_: std::io::Error) -> DotenvError {
        DotenvError::Io
    }
}

// for readability's sake
type ParsedLine = Result<Option<(String, String)>, DotenvError>;
type ParsedLines = Result<Vec<(String, String)>, DotenvError>;

fn named_string(captures: &Captures, name: &str) -> Option<String> {
    captures.name(name).and_then(|v| Some(v.to_string()))
}

fn parse_value(input: &str) -> Result<String, DotenvError> {
    let mut strong_quote = false; // '
    let mut weak_quote = false; // "
    let mut escaped = false;
    let mut expecting_end = false;

    //FIXME can this be done without yet another allocation per line?
    let mut output = String::new();

    for c in input.chars() {
        //the regex _should_ already trim whitespace off the end
        //expecting_end is meant to permit: k=v #comment
        //without affecting: k=v#comment
        //and throwing on: k=v w
        if expecting_end {
            if c == ' ' || c == '\t' {
                continue;
            } else if c == '#' {
                break;
            } else {
                return Err(DotenvError::Parsing { line: input.to_owned() });
            }
        } else if strong_quote {
            if c == '\'' {
                strong_quote = false;
            } else {
                output.push(c);
            }
        } else if weak_quote {
            if escaped {
                //TODO variable expansion perhaps
                //not in this update but in the future
                //$ requires escape anyway for conformance
                //and so as not to make that future change breaking
                //TODO I tried handling literal \n \r but various issues
                //imo not worth worrying about until there's a use case
                //(actually handling backslash 0x10 would be a whole other matter)
                //then there's \v \f bell hex... etc
                match c {
                    '\\' | '"' | '$' => output.push(c),
                    _ => return Err(DotenvError::Parsing { line: input.to_owned() })
                }

                escaped = false;
            } else if c == '"' {
                    weak_quote = false;
            } else if c == '\\' {
                escaped = true;
            } else {
                output.push(c);
            }
        } else {
            if escaped {
                match c {
                    '\\' | '\'' | '"' | '$' | ' ' => output.push(c),
                    _ => return Err(DotenvError::Parsing { line: input.to_owned() })
                }

                escaped = false;
            } else if c == '\'' {
                strong_quote = true;
            } else if c == '"' {
                weak_quote = true;
            } else if c == '\\' {
                escaped = true;
            } else if c == '$' {
                //variable interpolation goes here later
                return Err(DotenvError::Parsing { line: input.to_owned() });
            } else if c == ' ' || c == '\t' {
                expecting_end = true;
            } else {
                output.push(c);
            }
        }
    }

    //XXX also fail if escaped? or...
    if strong_quote || weak_quote {
        Err(DotenvError::Parsing { line: input.to_owned() })
    } else {
        Ok(output)
    }
}

fn parse_line(line: String) -> ParsedLine {
    let line_regex = try!(Regex::new(concat!(r"^(\s*(",
                                        r"#.*|", // A comment, or...
                                        r"\s*|", // ...an empty string, or...
                                        r"(export\s+)?", // ...(optionally preceded by "export")...
                                        r"(?P<key>[A-Za-z_][A-Za-z0-9_]*)", // ...a key,...
                                        r"=", // ...then an equal sign,...
                                        r"(?P<value>.+?)", // ...and then its corresponding value.
                                        r")\s*)[\r\n]*$")));

    line_regex.captures(&line)
              .map_or(Err(DotenvError::Parsing { line: line.clone() }),
                      |captures| {
                          let key = named_string(&captures, "key");
                          let value = named_string(&captures, "value");

                          if key.is_some() && value.is_some() {
                              let value = value.unwrap();
                              let parsed_value = try!(parse_value(&value));

                              Ok(Some((key.unwrap(), parsed_value)))
                          } else {
                              // If there's no key and value, but capturing did not
                              // fail, then this means we're dealing with a comment
                              // or an empty string.
                              Ok(None)
                          }
                      })
}

/// Loads the specified file.
fn from_file(file: File) -> Result<(), DotenvError> {
    let reader = BufReader::new(file);
    for line in reader.lines() {
        let line = try!(line);
        let parsed = try!(parse_line(line));
        match parsed {
            Some((key, value)) => {
                if env::var(&key).is_err() {
                    env::set_var(&key, value);
                }
                ()
            }
            None => (),
        }
    }
    Ok(())
}

/// Attempts to load from parent directories until file is found or root is reached.
fn try_parent(path: &Path, filename: &str) -> Result<(), DotenvError> {
    match path.parent() {
        Some(parent) => {
            match from_path(&parent.join(filename)) {
                Ok(file) => Ok(file),
                Err(DotenvError::Io) => try_parent(parent, filename),
                err => err
            }
        },
        None => Err(DotenvError::Io)
    }
}

/// Loads the file at the specified absolute path.
///
/// Examples
///
/// ```
/// use dotenv;
/// use std::env;
/// use std::path::{Path};
///
/// let my_path = env::home_dir().and_then(|a| Some(a.join("/.env"))).unwrap();
/// dotenv::from_path(my_path.as_path());
/// ```
pub fn from_path(path: &Path) -> Result<(), DotenvError> {
    match File::open(path) {
        Ok(file) => from_file(file),
        Err(_) => Err(DotenvError::Io),
    }
}

/// Loads the specified file from the environment's current directory or its parents in sequence.
///
/// # Examples
/// ```
/// use dotenv;
/// dotenv::from_filename("custom.env").ok();
/// ```
///
/// It is also possible to do the following, but it is equivalent to using dotenv::dotenv(), which
/// is preferred.
///
/// ```
/// use dotenv;
/// dotenv::from_filename(".env").ok();
/// ```
pub fn from_filename(filename: &str) -> Result<(), DotenvError> {
    let path = match env::current_dir() {
        Ok(path) => path,
        Err(_) => return Err(DotenvError::Io)
    };

    match from_path(&path.join(filename)) {
        Ok(file) => Ok(file),
        Err(DotenvError::Io) => try_parent(&path, filename),
        err => err
    }
}

/// This is usually what you want.
/// It loads the .env file located in the environment's current directory or its parents in sequence.
///
/// # Examples
/// ```
/// use dotenv;
/// dotenv::dotenv().ok();
/// ```
pub fn dotenv() -> Result<(), DotenvError> {
    from_filename(&".env")
}

#[test]
fn test_parse_line_env() {
    let input_iter = vec!["KEY=1",
                          r#"KEY2="2""#,
                          "KEY3='3'",
                          "KEY4='fo ur'",
                          r#"KEY5="fi ve""#,
                          r"KEY6=s\ ix",
                          "export   SHELL_LOVER=1"]
                         .into_iter()
                         .map(|input| input.to_string());
    let actual_iter = input_iter.map(|input| parse_line(input));

    let expected_iter = vec![("KEY", "1"),
                             ("KEY2", "2"),
                             ("KEY3", "3"),
                             ("KEY4", "fo ur"),
                             ("KEY5", "fi ve"),
                             ("KEY6", "s ix"),
                             ("SHELL_LOVER", "1")]
                            .into_iter()
                            .map(|(key, value)| (key.to_string(), value.to_string()));

    for (expected, actual) in expected_iter.zip(actual_iter) {
        assert!(actual.is_ok());
        assert!(actual.clone().ok().unwrap().is_some());
        assert_eq!(expected, actual.ok().unwrap().unwrap());
    }
}

#[test]
fn test_parse_line_comment() {
    let input_iter = vec!["# foo=bar", "    #    "]
                         .into_iter()
                         .map(|input| input.to_string());
    let actual_iter = input_iter.map(|input| parse_line(input));

    for actual in actual_iter {
        assert!(actual.is_ok());
        assert!(actual.ok().unwrap().is_none());
    }
}

#[test]
fn test_parse_line_invalid() {
    let input_iter = vec!["  invalid    ", "KEY =val", "KEY2= val", "very bacon = yes indeed", "key=", "=value"]
                         .into_iter()
                         .map(|input| input.to_string());
    let actual_iter = input_iter.map(|input| parse_line(input));

    for actual in actual_iter {
        assert!(actual.is_err());
    }
}

#[test]
fn test_parse_value_escapes () {
    let input_iter = vec![r#"KEY=my\ cool\ value"#,
                          r#"KEY2=\$sweet"#,
                          r#"KEY3="awesome stuff \"mang\"""#,
                          r#"KEY4='sweet $\fgs'\''fds'"#,
                          r#"KEY5="'\"yay\\"\ "stuff""#,
                          r##"KEY6="lol" #well you see when I say lol wh"##]
                         .into_iter()
                         .map(|input| input.to_string());
    let actual_iter = input_iter.map(|input| parse_line(input));

    let expected_iter = vec![("KEY", r#"my cool value"#),
                             ("KEY2", r#"$sweet"#),
                             ("KEY3", r#"awesome stuff "mang""#),
                             ("KEY4", r#"sweet $\fgs'fds"#),
                             ("KEY5", r#"'"yay\ stuff"#),
                             ("KEY6", "lol")]
                            .into_iter()
                            .map(|(key, value)| (key.to_string(), value.to_string()));

    for (expected, actual) in expected_iter.zip(actual_iter) {
        assert!(actual.is_ok());
        assert!(actual.clone().ok().unwrap().is_some());
        assert_eq!(expected, actual.ok().unwrap().unwrap());
    }
}

#[test]
fn test_parse_value_escapes_invalid() {
    let input_iter = vec![r#"KEY=my uncool value"#,
                          r#"KEY2=$notcool"#,
                          r#"KEY3="why"#,
                          r#"KEY4='please stop''"#,
                          r#"KEY5=h\8u"#]
                         .into_iter()
                         .map(|input| input.to_string());
    let actual_iter = input_iter.map(|input| parse_line(input));

    for actual in actual_iter {
        assert!(actual.is_err());
    }
}
<commit_msg>Use a more succinct if-let<commit_after>//! This crate provides a configuration loader in the style of the [ruby dotenv
//! gem](https://github.com/bkeepers/dotenv). This library is meant to be used
//! on development or testing environments in which setting environment
//! variables is not practical. It loads environment variables from a .env
//! file, if available, and mashes those with the actual environment variables
//! provided by the operating system.

extern crate regex;

use std::fs::File;
use std::io::{BufReader, BufRead};
use std::env;
use std::result::Result;
use std::path::Path;
use regex::{Captures, Regex, Error};

#[derive(Debug, Clone)]
pub enum DotenvError {
    Parsing {
        line: String,
    },
    ParseFormatter,
    Io,
    ExecutableNotFound,
}

impl From<regex::Error> for DotenvError {
    fn from(_: regex::Error) -> DotenvError {
        DotenvError::ParseFormatter
    }
}

impl From<std::io::Error> for DotenvError {
    fn from(_: std::io::Error) -> DotenvError {
        DotenvError::Io
    }
}

// for readability's sake
type ParsedLine = Result<Option<(String, String)>, DotenvError>;
type ParsedLines = Result<Vec<(String, String)>, DotenvError>;

fn named_string(captures: &Captures, name: &str) -> Option<String> {
    captures.name(name).and_then(|v| Some(v.to_string()))
}

fn parse_value(input: &str) -> Result<String, DotenvError> {
    let mut strong_quote = false; // '
    let mut weak_quote = false; // "
    let mut escaped = false;
    let mut expecting_end = false;

    //FIXME can this be done without yet another allocation per line?
    let mut output = String::new();

    for c in input.chars() {
        //the regex _should_ already trim whitespace off the end
        //expecting_end is meant to permit: k=v #comment
        //without affecting: k=v#comment
        //and throwing on: k=v w
        if expecting_end {
            if c == ' ' || c == '\t' {
                continue;
            } else if c == '#' {
                break;
            } else {
                return Err(DotenvError::Parsing { line: input.to_owned() });
            }
        } else if strong_quote {
            if c == '\'' {
                strong_quote = false;
            } else {
                output.push(c);
            }
        } else if weak_quote {
            if escaped {
                //TODO variable expansion perhaps
                //not in this update but in the future
                //$ requires escape anyway for conformance
                //and so as not to make that future change breaking
                //TODO I tried handling literal \n \r but various issues
                //imo not worth worrying about until there's a use case
                //(actually handling backslash 0x10 would be a whole other matter)
                //then there's \v \f bell hex... etc
                match c {
                    '\\' | '"' | '$' => output.push(c),
                    _ => return Err(DotenvError::Parsing { line: input.to_owned() })
                }

                escaped = false;
            } else if c == '"' {
                    weak_quote = false;
            } else if c == '\\' {
                escaped = true;
            } else {
                output.push(c);
            }
        } else {
            if escaped {
                match c {
                    '\\' | '\'' | '"' | '$' | ' ' => output.push(c),
                    _ => return Err(DotenvError::Parsing { line: input.to_owned() })
                }

                escaped = false;
            } else if c == '\'' {
                strong_quote = true;
            } else if c == '"' {
                weak_quote = true;
            } else if c == '\\' {
                escaped = true;
            } else if c == '$' {
                //variable interpolation goes here later
                return Err(DotenvError::Parsing { line: input.to_owned() });
            } else if c == ' ' || c == '\t' {
                expecting_end = true;
            } else {
                output.push(c);
            }
        }
    }

    //XXX also fail if escaped? or...
    if strong_quote || weak_quote {
        Err(DotenvError::Parsing { line: input.to_owned() })
    } else {
        Ok(output)
    }
}

fn parse_line(line: String) -> ParsedLine {
    let line_regex = try!(Regex::new(concat!(r"^(\s*(",
                                        r"#.*|", // A comment, or...
                                        r"\s*|", // ...an empty string, or...
                                        r"(export\s+)?", // ...(optionally preceded by "export")...
                                        r"(?P<key>[A-Za-z_][A-Za-z0-9_]*)", // ...a key,...
                                        r"=", // ...then an equal sign,...
                                        r"(?P<value>.+?)", // ...and then its corresponding value.
                                        r")\s*)[\r\n]*$")));

    line_regex.captures(&line)
              .map_or(Err(DotenvError::Parsing { line: line.clone() }),
                      |captures| {
                          let key = named_string(&captures, "key");
                          let value = named_string(&captures, "value");

                          if key.is_some() && value.is_some() {
                              let value = value.unwrap();
                              let parsed_value = try!(parse_value(&value));

                              Ok(Some((key.unwrap(), parsed_value)))
                          } else {
                              // If there's no key and value, but capturing did not
                              // fail, then this means we're dealing with a comment
                              // or an empty string.
                              Ok(None)
                          }
                      })
}

/// Loads the specified file.
fn from_file(file: File) -> Result<(), DotenvError> {
    let reader = BufReader::new(file);
    for line in reader.lines() {
        let line = try!(line);
        let parsed = try!(parse_line(line));
        if let Some((key, value)) = parsed {
            if env::var(&key).is_err() {
                env::set_var(&key, value);
            }
        }
    }
    Ok(())
}

/// Attempts to load from parent directories until file is found or root is reached.
fn try_parent(path: &Path, filename: &str) -> Result<(), DotenvError> {
    match path.parent() {
        Some(parent) => {
            match from_path(&parent.join(filename)) {
                Ok(file) => Ok(file),
                Err(DotenvError::Io) => try_parent(parent, filename),
                err => err
            }
        },
        None => Err(DotenvError::Io)
    }
}

/// Loads the file at the specified absolute path.
///
/// Examples
///
/// ```
/// use dotenv;
/// use std::env;
/// use std::path::{Path};
///
/// let my_path = env::home_dir().and_then(|a| Some(a.join("/.env"))).unwrap();
/// dotenv::from_path(my_path.as_path());
/// ```
pub fn from_path(path: &Path) -> Result<(), DotenvError> {
    match File::open(path) {
        Ok(file) => from_file(file),
        Err(_) => Err(DotenvError::Io),
    }
}

/// Loads the specified file from the environment's current directory or its parents in sequence.
///
/// # Examples
/// ```
/// use dotenv;
/// dotenv::from_filename("custom.env").ok();
/// ```
///
/// It is also possible to do the following, but it is equivalent to using dotenv::dotenv(), which
/// is preferred.
///
/// ```
/// use dotenv;
/// dotenv::from_filename(".env").ok();
/// ```
pub fn from_filename(filename: &str) -> Result<(), DotenvError> {
    let path = match env::current_dir() {
        Ok(path) => path,
        Err(_) => return Err(DotenvError::Io)
    };

    match from_path(&path.join(filename)) {
        Ok(file) => Ok(file),
        Err(DotenvError::Io) => try_parent(&path, filename),
        err => err
    }
}

/// This is usually what you want.
/// It loads the .env file located in the environment's current directory or its parents in sequence.
///
/// # Examples
/// ```
/// use dotenv;
/// dotenv::dotenv().ok();
/// ```
pub fn dotenv() -> Result<(), DotenvError> {
    from_filename(&".env")
}

#[test]
fn test_parse_line_env() {
    let input_iter = vec!["KEY=1",
                          r#"KEY2="2""#,
                          "KEY3='3'",
                          "KEY4='fo ur'",
                          r#"KEY5="fi ve""#,
                          r"KEY6=s\ ix",
                          "export   SHELL_LOVER=1"]
                         .into_iter()
                         .map(|input| input.to_string());
    let actual_iter = input_iter.map(|input| parse_line(input));

    let expected_iter = vec![("KEY", "1"),
                             ("KEY2", "2"),
                             ("KEY3", "3"),
                             ("KEY4", "fo ur"),
                             ("KEY5", "fi ve"),
                             ("KEY6", "s ix"),
                             ("SHELL_LOVER", "1")]
                            .into_iter()
                            .map(|(key, value)| (key.to_string(), value.to_string()));

    for (expected, actual) in expected_iter.zip(actual_iter) {
        assert!(actual.is_ok());
        assert!(actual.clone().ok().unwrap().is_some());
        assert_eq!(expected, actual.ok().unwrap().unwrap());
    }
}

#[test]
fn test_parse_line_comment() {
    let input_iter = vec!["# foo=bar", "    #    "]
                         .into_iter()
                         .map(|input| input.to_string());
    let actual_iter = input_iter.map(|input| parse_line(input));

    for actual in actual_iter {
        assert!(actual.is_ok());
        assert!(actual.ok().unwrap().is_none());
    }
}

#[test]
fn test_parse_line_invalid() {
    let input_iter = vec!["  invalid    ", "KEY =val", "KEY2= val", "very bacon = yes indeed", "key=", "=value"]
                         .into_iter()
                         .map(|input| input.to_string());
    let actual_iter = input_iter.map(|input| parse_line(input));

    for actual in actual_iter {
        assert!(actual.is_err());
    }
}

#[test]
fn test_parse_value_escapes () {
    let input_iter = vec![r#"KEY=my\ cool\ value"#,
                          r#"KEY2=\$sweet"#,
                          r#"KEY3="awesome stuff \"mang\"""#,
                          r#"KEY4='sweet $\fgs'\''fds'"#,
                          r#"KEY5="'\"yay\\"\ "stuff""#,
                          r##"KEY6="lol" #well you see when I say lol wh"##]
                         .into_iter()
                         .map(|input| input.to_string());
    let actual_iter = input_iter.map(|input| parse_line(input));

    let expected_iter = vec![("KEY", r#"my cool value"#),
                             ("KEY2", r#"$sweet"#),
                             ("KEY3", r#"awesome stuff "mang""#),
                             ("KEY4", r#"sweet $\fgs'fds"#),
                             ("KEY5", r#"'"yay\ stuff"#),
                             ("KEY6", "lol")]
                            .into_iter()
                            .map(|(key, value)| (key.to_string(), value.to_string()));

    for (expected, actual) in expected_iter.zip(actual_iter) {
        assert!(actual.is_ok());
        assert!(actual.clone().ok().unwrap().is_some());
        assert_eq!(expected, actual.ok().unwrap().unwrap());
    }
}

#[test]
fn test_parse_value_escapes_invalid() {
    let input_iter = vec![r#"KEY=my uncool value"#,
                          r#"KEY2=$notcool"#,
                          r#"KEY3="why"#,
                          r#"KEY4='please stop''"#,
                          r#"KEY5=h\8u"#]
                         .into_iter()
                         .map(|input| input.to_string());
    let actual_iter = input_iter.map(|input| parse_line(input));

    for actual in actual_iter {
        assert!(actual.is_err());
    }
}
<|endoftext|>


<commit_before>/// A simple dsp node for multiplying the amplitude of its inputs by some given multiplier.

extern crate dsp;
extern crate time_calc as time;

/// A simple dsp node for multiplying the amplitude of its inputs by the held multiplier.
#[derive(Copy, Clone, Debug)]
pub struct Volume {
    maybe_prev: Option<f32>,
    pub current: f32,
    pub interpolation_ms: time::calc::Ms,
}

impl Volume {

    /// Constructor for a new default volume. The default volume is 1.0, having no impact on the
    /// input signal. The default interpolation_ms is 10ms to avoid clipping.
    pub fn new() -> Volume {
        Volume {
            maybe_prev: None,
            current: 1.0,
            interpolation_ms: 10.0,
        }
    }

    /// Builder for constructing a Volume with some given volume.
    pub fn volume(mut self, volume: f32) -> Volume {
        self.current = volume;
        self
    }

    /// Builder for constructing a Volume with some given interpolation length in Ms.
    /// The interpolation length is how long it takes the volume to progress from some previous
    /// volume to a new current volume. It is mainly used to avoid clipping.
    ///
    /// The default interpolation_ms is 10ms - just enough to avoid clipping.
    pub fn interpolation_ms(mut self, ms: time::calc::Ms) -> Volume {
        self.interpolation_ms = ms;
        self
    }

    /// Set the new current volume.
    pub fn set(&mut self, volume: f32) {
        self.current = volume;
    }

}

impl<S> dsp::Node<S> for Volume where S: dsp::Sample {

    #[inline]
    fn audio_requested(&mut self, buffer: &mut [S], settings: dsp::Settings) {
        match self.maybe_prev {

            // If the volume used for the previous buffer is different to the volume used for the
            // current buffer, we should interpolate from it to the current volume to avoid
            // clipping.
            Some(prev) if prev != self.current && self.interpolation_ms > 0.0 => {

                // Calculate the interpolation duration in frames along with the volume increment
                // to use for interpolation.
                let interpolation_frames = ::std::cmp::min(
                    settings.frames as usize,
                    time::Ms(self.interpolation_ms).samples(settings.sample_hz as f64) as usize
                );
                let volume_diff = self.current - prev;
                let volume_increment = volume_diff * (1.0 / interpolation_frames as f32);
                let mut volume = prev;

                // Interpolated frames.
                for frame in 0..interpolation_frames {
                    volume += volume_increment;
                    for channel in 0..(settings.channels as usize) {
                        let idx = frame * (settings.channels as usize) + channel;
                        let sample = &mut buffer[idx];
                        *sample = sample.mul_amp(volume);
                    }
                }

                // Remaining frames.
                let start_of_remaining = interpolation_frames * settings.channels as usize;
                for idx in start_of_remaining..buffer.len() {
                    let sample = &mut buffer[idx];
                    *sample = sample.mul_amp(volume);
                }
            },

            // Otherwise, simply multiply every sample by the current volume.
            _ => for sample in buffer.iter_mut() {
                *sample = sample.mul_amp(self.current);
            },

        }

        // Always set the current volume as the new `maybe_prev`.
        self.maybe_prev = Some(self.current);
    }

}

<commit_msg>Update to latest changes in dsp-chain and sample crates<commit_after>/// A simple dsp node for multiplying the amplitude of its inputs by some given multiplier.

extern crate dsp;
extern crate time_calc as time;

/// A simple dsp node for multiplying the amplitude of its inputs by the held multiplier.
#[derive(Copy, Clone, Debug)]
pub struct Volume {
    maybe_prev: Option<f32>,
    pub current: f32,
    pub interpolation_ms: time::calc::Ms,
}

impl Volume {

    /// Constructor for a new default volume. The default volume is 1.0, having no impact on the
    /// input signal. The default interpolation_ms is 10ms to avoid clipping.
    pub fn new() -> Volume {
        Volume {
            maybe_prev: None,
            current: 1.0,
            interpolation_ms: 10.0,
        }
    }

    /// Builder for constructing a Volume with some given volume.
    pub fn volume(mut self, volume: f32) -> Volume {
        self.current = volume;
        self
    }

    /// Builder for constructing a Volume with some given interpolation length in Ms.
    /// The interpolation length is how long it takes the volume to progress from some previous
    /// volume to a new current volume. It is mainly used to avoid clipping.
    ///
    /// The default interpolation_ms is 10ms - just enough to avoid clipping.
    pub fn interpolation_ms(mut self, ms: time::calc::Ms) -> Volume {
        self.interpolation_ms = ms;
        self
    }

    /// Set the new current volume.
    pub fn set(&mut self, volume: f32) {
        self.current = volume;
    }

}

impl<S> dsp::Node<S> for Volume
    where S: dsp::Sample + dsp::FromSample<f32>,
          f32: dsp::FromSample<S>,
{

    #[inline]
    fn audio_requested(&mut self, buffer: &mut [S], settings: dsp::Settings) {
        use dsp::Sample;
        match self.maybe_prev {

            // If the volume used for the previous buffer is different to the volume used for the
            // current buffer, we should interpolate from it to the current volume to avoid
            // clipping.
            Some(prev) if prev != self.current && self.interpolation_ms > 0.0 => {

                // Calculate the interpolation duration in frames along with the volume increment
                // to use for interpolation.
                let interpolation_frames = ::std::cmp::min(
                    settings.frames as usize,
                    time::Ms(self.interpolation_ms).samples(settings.sample_hz as f64) as usize
                );
                let volume_diff = self.current - prev;
                let volume_increment = volume_diff * (1.0 / interpolation_frames as f32);
                let mut volume = prev;

                // Interpolated frames.
                for frame in 0..interpolation_frames {
                    volume += volume_increment;
                    for channel in 0..(settings.channels as usize) {
                        let idx = frame * (settings.channels as usize) + channel;
                        let sample = &mut buffer[idx];
                        *sample = (sample.to_sample::<f32>() * volume).to_sample();
                    }
                }

                // Remaining frames.
                let start_of_remaining = interpolation_frames * settings.channels as usize;
                for idx in start_of_remaining..buffer.len() {
                    let sample = &mut buffer[idx];
                    *sample = (sample.to_sample::<f32>() * volume).to_sample();
                }
            },

            // Otherwise, simply multiply every sample by the current volume.
            _ => for sample in buffer.iter_mut() {
                *sample = (sample.to_sample::<f32>() * self.current).to_sample();
            },

        }

        // Always set the current volume as the new `maybe_prev`.
        self.maybe_prev = Some(self.current);
    }

}

<|endoftext|>


<commit_before>//! MySQL Proxy Server

#[macro_use]
extern crate log;
extern crate env_logger;
#[macro_use]
extern crate futures;
#[macro_use]
extern crate tokio_core;
extern crate futures_cpupool;
extern crate byteorder;

use std::cell::RefCell;
use std::rc::Rc;
use std::env;
use std::io::{self, Read, Write, Error, ErrorKind};
use std::net::{SocketAddr, Ipv4Addr, Ipv6Addr, SocketAddrV4, SocketAddrV6};
use std::net::Shutdown;
use std::str;
use std::time::Duration;

use futures::{Future, Poll, Async};
use futures::stream::Stream;
use futures_cpupool::CpuPool;
use tokio_core::{Loop, LoopHandle, TcpStream};
use tokio_core::io::{read_exact, write_all, Window};

use byteorder::*;

#[derive(Copy,Clone)]
pub enum PacketType {
    ComSleep = 0x00,
    ComQuit = 0x01,
    ComInitDb = 0x02,
    ComQuery = 0x03,
    ComFieldList = 0x04,
    ComCreateDb = 0x05,
    ComDropDb = 0x06,
    ComRefresh = 0x07,
    ComShutdown = 0x08,
    ComStatistics = 0x09,
    ComProcessInfo = 0x0a,
    ComConnect = 0x0b,
    ComProcessKill= 0x0c,
    ComDebug = 0x0d,
    ComPing = 0x0e,
    ComTime = 0x0f,
    ComDelayedInsert = 0x10,
    ComChangeUser = 0x11,
    ComBinlogDump = 0x12,
    ComTableDump = 0x13,
    ComConnectOut = 0x14,
    ComRegisterSlave = 0x15,
    ComStmtPrepare = 0x16,
    ComStmtExecute = 0x17,
    ComStmtSendLongData = 0x18,
    ComStmtClose = 0x19,
    ComStmtReset = 0x1a,
    ComDaemon= 0x1d,
    ComBinlogDumpGtid = 0x1e,
    ComResetConnection = 0x1f,
}

pub struct Packet {
    pub bytes: Vec<u8>
}

impl Packet {

    pub fn error_packet(code: u16, state: [u8; 5], msg: String) -> Self {
        let mut err_header: Vec<u8> = vec![];
        let mut err_wtr: Vec<u8> = vec![];

        // start building payload
        err_wtr.push(0xff);  // packet type
        err_wtr.write_u16::<LittleEndian>(code).unwrap(); // error code
        err_wtr.extend_from_slice("#".as_bytes()); // sql_state_marker
        err_wtr.extend_from_slice(&state); // SQL STATE
        err_wtr.extend_from_slice(msg.as_bytes());

        // create header with length and sequence id
        err_header.write_u32::<LittleEndian>(err_wtr.len() as u32).unwrap();
        err_header.pop(); // we need 3 byte length, so discard last byte
        err_header.push(1); // sequence_id

        let mut write_buf: Vec<u8> = Vec::new();
        write_buf.extend_from_slice(&err_header);
        write_buf.extend_from_slice(&err_wtr);

        Packet { bytes: write_buf }
    }

    pub fn sequence_id(&self) -> u8 {
        self.bytes[3]
    }

    //TODO: should return Result<PacketType, ?>
    pub fn packet_type(&self) -> PacketType {
        match self.bytes[4] {
            0x00 => PacketType::ComSleep,
            0x01 => PacketType::ComQuit,
            0x02 => PacketType::ComInitDb,
            0x03 => PacketType::ComQuery,
            0x04 => PacketType::ComFieldList,
            0x05 => PacketType::ComCreateDb,
            0x06 => PacketType::ComDropDb,
            0x07 => PacketType::ComRefresh,
            0x08 => PacketType::ComShutdown,
            0x09 => PacketType::ComStatistics,
            0x0a => PacketType::ComProcessInfo,
            0x0b => PacketType::ComConnect,
            0x0c => PacketType::ComProcessKill,
            0x0d => PacketType::ComDebug,
            0x0e => PacketType::ComPing,
            0x0f => PacketType::ComTime,
            0x10 => PacketType::ComDelayedInsert,
            0x11 => PacketType::ComChangeUser,
            0x12 => PacketType::ComBinlogDump,
            0x13 => PacketType::ComTableDump,
            0x14 => PacketType::ComConnectOut,
            0x15 => PacketType::ComRegisterSlave,
            0x16 => PacketType::ComStmtPrepare,
            0x17 => PacketType::ComStmtExecute,
            0x18 => PacketType::ComStmtSendLongData,
            0x19 => PacketType::ComStmtClose,
            0x1a => PacketType::ComStmtReset,
            0x1d => PacketType::ComDaemon,
            0x1e => PacketType::ComBinlogDumpGtid,
            0x1f => PacketType::ComResetConnection,
            _ => panic!("Unsupported packet type")
        }
    }

}

pub enum Action {
    Forward,                // forward the packet unmodified
    Mutate(Packet),         // mutate the packet
    Respond(Vec<Packet>)    // handle directly and optionally return some packets
}

pub trait PacketHandler {
    fn handle_request(&self, p: &Packet) -> Action;
    fn handle_response(&self, p: &Packet) -> Action;
}

fn parse_packet_length(header: &[u8]) -> usize {
    (((header[2] as u32) << 16) |
    ((header[1] as u32) << 8) |
    header[0] as u32) as usize
}

pub struct Client {
    pub pool: CpuPool,
    pub handle: LoopHandle,
}

impl Client {

    pub fn serve<H: PacketHandler + 'static>(self, conn: TcpStream,
                                             handler: H,
                                        ) -> Box<Future<Item = (u64, u64), Error = Error>> {

        let addr = Ipv4Addr::new(127, 0, 0, 1);
        let port = 3306;
        let addr = SocketAddr::V4(SocketAddrV4::new(addr, port));

        let handle = self.handle.clone();
        let connected = handle.tcp_connect(&addr);

        let pair = connected.and_then(move |server| Ok((conn,server)));

        Box::new(pair.and_then(move |(c1, c2)| {
            let c1 = Rc::new(c1);
            let c2 = Rc::new(c2);
            Pipe::new(c1, c2, handler)
        }))
    }
}

#[derive(Debug)]
enum Direction {
    Client,
    Server
}

struct ConnReader {
    direction: Direction,
    stream: Rc<TcpStream>,
    read_buf: Vec<u8>,
    read_pos: usize,
    read_amt: u64,
}

struct ConnWriter {
    direction: Direction,
    stream: Rc<TcpStream>,
    write_buf: Vec<u8>,
    write_pos: usize,
    write_amt: u64,
}

impl ConnReader {

    fn new(stream: Rc<TcpStream>, direction: Direction) -> Self {
        ConnReader {
            stream: stream,
            direction: direction,
            read_buf: vec![0u8; 4096],
            read_pos: 0,
            read_amt: 0,
        }
    }

    /// Read from the socket until the status is NotReady
    fn read(&mut self) -> Poll<(), io::Error> {
//        println!("{:?} read()", self.direction);
        loop {
//            println!("{:?} before poll_read()", self.direction);
            try_ready!(self.stream.poll_read());
//            println!("{:?} before try_nb()", self.direction);
            //TODO: ensure capacity first
            let n = try_nb!((&*self.stream).read(&mut self.read_buf[self.read_pos..]));
            if n == 0 {
//                println!("{:?} Detected connection closed", self.direction);
                return Err(Error::new(ErrorKind::Other, "connection closed"));
            }
//            println!("{:?} read() read {} bytes", self.direction, n);
            self.read_amt += n as u64;
            self.read_pos += n;
        }
    }

    fn next(&mut self) -> Option<Packet> {
        // do we have a header
        if self.read_pos > 3 {
            let l = parse_packet_length(&self.read_buf);
            // do we have the whole packet?
            let s = 4 + l;
            if self.read_pos >= s {

                //TODO: clean up this hack
                let mut temp : Vec<u8> = vec![];
                temp.extend_from_slice( &self.read_buf[0..s]);
                let p = Packet { bytes: temp };

                // shift data down
                let mut j = 0;
                for i in s .. self.read_buf.len() {
                    self.read_buf[j] = self.read_buf[i];
                    j += 1;
                }
                self.read_pos -= s;

//                println!("{:?} parse_packet(): read_pos={}, returning packet:", self.direction, self.read_pos);
//                print_packet_bytes(&p.bytes);
//                print_packet_chars(&p.bytes);

                Some(p)
            } else {
                None
            }
        } else {
            None
        }
    }
}

impl ConnWriter{

    fn new(stream: Rc<TcpStream>, direction: Direction) -> Self {
        ConnWriter{
            stream: stream,
            direction: direction,
            write_buf: vec![0u8; 4096],
            write_pos: 0,
            write_amt: 0
        }
    }

    /// Write a packet to the write buffer
    fn push(&mut self, p: &Packet) {
        self.write_buf.truncate(self.write_pos);
        self.write_buf.extend_from_slice(&p.bytes);
        self.write_pos += p.bytes.len();
//        println!("{:?} extended write buffer by {} bytes", self.direction, p.bytes.len());
    }

    /// Writes the contents of the write buffer to the socket
    fn write(&mut self) -> Poll<(), io::Error> {
//        println!("{:?} write()", self.direction);
        while self.write_pos > 0 {
            try_ready!(self.stream.poll_write());
            let s = try!((&*self.stream).write(&self.write_buf[0..self.write_pos]));
//            println!("{:?} Wrote {} bytes", self.direction, s);

            let mut j = 0;
            for i in s .. self.write_buf.len() {
                self.write_buf[j] = self.write_buf[i];
                j += 1;
            }
            self.write_pos -= s;

        }
        return Ok(Async::Ready(()));
    }
}

struct Pipe<H: PacketHandler + 'static> {
    client_reader: ConnReader,
    client_writer: ConnWriter,
    server_reader: ConnReader,
    server_writer: ConnWriter,
    handler: H,
}

impl<H> Pipe<H> where H: PacketHandler + 'static {
    fn new(client: Rc<TcpStream>,
           server: Rc<TcpStream>,
           handler: H
           ) -> Pipe<H> {

        Pipe {
            client_reader: ConnReader::new(client.clone(), Direction::Client),
            client_writer: ConnWriter::new(client, Direction::Client),
            server_reader: ConnReader::new(server.clone(), Direction::Server),
            server_writer: ConnWriter::new(server, Direction::Server),
            handler: handler,
        }
    }
}

impl<H> Future for Pipe<H> where H: PacketHandler + 'static {
    type Item = (u64, u64);
    type Error = Error;

    fn poll(&mut self) -> Poll<(u64, u64), io::Error> {
        //println!("poll()");

        loop {
            // try reading from client
//            println!("CLIENT READ");
            let client_read = self.client_reader.read();

            // if the client connection has closed, close the server connection too
            match &client_read {
                &Err(ref e) => { self.server_writer.stream.shutdown(Shutdown::Write); },
                _ => {}
            }

            // process buffered requests
            while let Some(request) = self.client_reader.next() {
                match self.handler.handle_request(&request) {
                    Action::Forward => self.server_writer.push(&request),
                    Action::Mutate(ref p2) => self.server_writer.push(p2),
                    Action::Respond(ref v) => {
                        for p in v {
                            self.client_writer.push(&p);
                        }
                    }
                };
            }

            // try writing to server
//            println!("SERVER WRITE");
            let server_write = self.server_writer.write();

            // try reading from server
//            println!("SERVER READ");
            let server_read = self.server_reader.read();

            // if the server connection has closed, close the client connection too
            match &server_read {
                &Err(ref e) => { self.client_writer.stream.shutdown(Shutdown::Write); },
                _ => {}
            }

            // process buffered responses
            while let Some(response) = self.server_reader.next() {
                match self.handler.handle_response(&response) {
                    Action::Forward => self.client_writer.push(&response),
                    Action::Mutate(ref p2) => self.client_writer.push(p2),
                    Action::Respond(ref v) => {
                        for p in v {
                            self.server_writer.push(&p);
                        }
                    }
                };
            }

            // try writing to client
//            println!("CLIENT WRITE");
            let client_write = self.client_writer.write();

//            println!("client_read = {:?}", client_read);
//            println!("client_write = {:?}", client_write);
//            println!("server_read = {:?}", server_read);
//            println!("server_write = {:?}", server_write);

            try_ready!(client_read);
            try_ready!(client_write);
            try_ready!(server_read);
            try_ready!(server_write);
        }

    }

}

#[allow(dead_code)]
pub fn print_packet_chars(buf: &[u8]) {
    print!("[");
    for i in 0..buf.len() {
        print!("{} ", buf[i] as char);
    }
    println!("]");
}

#[allow(dead_code)]
pub fn print_packet_bytes(buf: &[u8]) {
    print!("[");
    for i in 0..buf.len() {
        if i%8==0 { println!(""); }
        print!("{:#04x} ",buf[i]);
    }
    println!("]");
}

<commit_msg>avoid truncating and extending buffer<commit_after>//! MySQL Proxy Server

#[macro_use]
extern crate log;
extern crate env_logger;
#[macro_use]
extern crate futures;
#[macro_use]
extern crate tokio_core;
extern crate futures_cpupool;
extern crate byteorder;

use std::cell::RefCell;
use std::rc::Rc;
use std::env;
use std::io::{self, Read, Write, Error, ErrorKind};
use std::net::{SocketAddr, Ipv4Addr, Ipv6Addr, SocketAddrV4, SocketAddrV6};
use std::net::Shutdown;
use std::str;
use std::time::Duration;

use futures::{Future, Poll, Async};
use futures::stream::Stream;
use futures_cpupool::CpuPool;
use tokio_core::{Loop, LoopHandle, TcpStream};
use tokio_core::io::{read_exact, write_all, Window};

use byteorder::*;

#[derive(Copy,Clone)]
pub enum PacketType {
    ComSleep = 0x00,
    ComQuit = 0x01,
    ComInitDb = 0x02,
    ComQuery = 0x03,
    ComFieldList = 0x04,
    ComCreateDb = 0x05,
    ComDropDb = 0x06,
    ComRefresh = 0x07,
    ComShutdown = 0x08,
    ComStatistics = 0x09,
    ComProcessInfo = 0x0a,
    ComConnect = 0x0b,
    ComProcessKill= 0x0c,
    ComDebug = 0x0d,
    ComPing = 0x0e,
    ComTime = 0x0f,
    ComDelayedInsert = 0x10,
    ComChangeUser = 0x11,
    ComBinlogDump = 0x12,
    ComTableDump = 0x13,
    ComConnectOut = 0x14,
    ComRegisterSlave = 0x15,
    ComStmtPrepare = 0x16,
    ComStmtExecute = 0x17,
    ComStmtSendLongData = 0x18,
    ComStmtClose = 0x19,
    ComStmtReset = 0x1a,
    ComDaemon= 0x1d,
    ComBinlogDumpGtid = 0x1e,
    ComResetConnection = 0x1f,
}

pub struct Packet {
    pub bytes: Vec<u8>
}

impl Packet {

    pub fn error_packet(code: u16, state: [u8; 5], msg: String) -> Self {
        let mut err_header: Vec<u8> = vec![];
        let mut err_wtr: Vec<u8> = vec![];

        // start building payload
        err_wtr.push(0xff);  // packet type
        err_wtr.write_u16::<LittleEndian>(code).unwrap(); // error code
        err_wtr.extend_from_slice("#".as_bytes()); // sql_state_marker
        err_wtr.extend_from_slice(&state); // SQL STATE
        err_wtr.extend_from_slice(msg.as_bytes());

        // create header with length and sequence id
        err_header.write_u32::<LittleEndian>(err_wtr.len() as u32).unwrap();
        err_header.pop(); // we need 3 byte length, so discard last byte
        err_header.push(1); // sequence_id

        let mut write_buf: Vec<u8> = Vec::new();
        write_buf.extend_from_slice(&err_header);
        write_buf.extend_from_slice(&err_wtr);

        Packet { bytes: write_buf }
    }

    pub fn sequence_id(&self) -> u8 {
        self.bytes[3]
    }

    //TODO: should return Result<PacketType, ?>
    pub fn packet_type(&self) -> PacketType {
        match self.bytes[4] {
            0x00 => PacketType::ComSleep,
            0x01 => PacketType::ComQuit,
            0x02 => PacketType::ComInitDb,
            0x03 => PacketType::ComQuery,
            0x04 => PacketType::ComFieldList,
            0x05 => PacketType::ComCreateDb,
            0x06 => PacketType::ComDropDb,
            0x07 => PacketType::ComRefresh,
            0x08 => PacketType::ComShutdown,
            0x09 => PacketType::ComStatistics,
            0x0a => PacketType::ComProcessInfo,
            0x0b => PacketType::ComConnect,
            0x0c => PacketType::ComProcessKill,
            0x0d => PacketType::ComDebug,
            0x0e => PacketType::ComPing,
            0x0f => PacketType::ComTime,
            0x10 => PacketType::ComDelayedInsert,
            0x11 => PacketType::ComChangeUser,
            0x12 => PacketType::ComBinlogDump,
            0x13 => PacketType::ComTableDump,
            0x14 => PacketType::ComConnectOut,
            0x15 => PacketType::ComRegisterSlave,
            0x16 => PacketType::ComStmtPrepare,
            0x17 => PacketType::ComStmtExecute,
            0x18 => PacketType::ComStmtSendLongData,
            0x19 => PacketType::ComStmtClose,
            0x1a => PacketType::ComStmtReset,
            0x1d => PacketType::ComDaemon,
            0x1e => PacketType::ComBinlogDumpGtid,
            0x1f => PacketType::ComResetConnection,
            _ => panic!("Unsupported packet type")
        }
    }

}

pub enum Action {
    Forward,                // forward the packet unmodified
    Mutate(Packet),         // mutate the packet
    Respond(Vec<Packet>)    // handle directly and optionally return some packets
}

pub trait PacketHandler {
    fn handle_request(&self, p: &Packet) -> Action;
    fn handle_response(&self, p: &Packet) -> Action;
}

fn parse_packet_length(header: &[u8]) -> usize {
    (((header[2] as u32) << 16) |
    ((header[1] as u32) << 8) |
    header[0] as u32) as usize
}

pub struct Client {
    pub pool: CpuPool,
    pub handle: LoopHandle,
}

impl Client {

    pub fn serve<H: PacketHandler + 'static>(self, conn: TcpStream,
                                             handler: H,
                                        ) -> Box<Future<Item = (u64, u64), Error = Error>> {

        let addr = Ipv4Addr::new(127, 0, 0, 1);
        let port = 3306;
        let addr = SocketAddr::V4(SocketAddrV4::new(addr, port));

        let handle = self.handle.clone();
        let connected = handle.tcp_connect(&addr);

        let pair = connected.and_then(move |server| Ok((conn,server)));

        Box::new(pair.and_then(move |(c1, c2)| {
            let c1 = Rc::new(c1);
            let c2 = Rc::new(c2);
            Pipe::new(c1, c2, handler)
        }))
    }
}

#[derive(Debug)]
enum Direction {
    Client,
    Server
}

struct ConnReader {
    direction: Direction,
    stream: Rc<TcpStream>,
    read_buf: Vec<u8>,
    read_pos: usize,
    read_amt: u64,
}

struct ConnWriter {
    direction: Direction,
    stream: Rc<TcpStream>,
    write_buf: Vec<u8>,
    write_pos: usize,
    write_amt: u64,
}

impl ConnReader {

    fn new(stream: Rc<TcpStream>, direction: Direction) -> Self {
        ConnReader {
            stream: stream,
            direction: direction,
            read_buf: vec![0u8; 4096],
            read_pos: 0,
            read_amt: 0,
        }
    }

    /// Read from the socket until the status is NotReady
    fn read(&mut self) -> Poll<(), io::Error> {
//        println!("{:?} read()", self.direction);
        loop {
//            println!("{:?} before poll_read()", self.direction);
            try_ready!(self.stream.poll_read());
//            println!("{:?} before try_nb()", self.direction);
            //TODO: ensure capacity first
            let n = try_nb!((&*self.stream).read(&mut self.read_buf[self.read_pos..]));
            if n == 0 {
//                println!("{:?} Detected connection closed", self.direction);
                return Err(Error::new(ErrorKind::Other, "connection closed"));
            }
//            println!("{:?} read() read {} bytes", self.direction, n);
            self.read_amt += n as u64;
            self.read_pos += n;
        }
    }

    fn next(&mut self) -> Option<Packet> {
        // do we have a header
        if self.read_pos > 3 {
            let l = parse_packet_length(&self.read_buf);
            // do we have the whole packet?
            let s = 4 + l;
            if self.read_pos >= s {

                //TODO: clean up this hack
                let mut temp : Vec<u8> = vec![];
                temp.extend_from_slice( &self.read_buf[0..s]);
                let p = Packet { bytes: temp };

                // shift data down
                let mut j = 0;
                for i in s .. self.read_buf.len() {
                    self.read_buf[j] = self.read_buf[i];
                    j += 1;
                }
                self.read_pos -= s;

//                println!("{:?} parse_packet(): read_pos={}, returning packet:", self.direction, self.read_pos);
//                print_packet_bytes(&p.bytes);
//                print_packet_chars(&p.bytes);

                Some(p)
            } else {
                None
            }
        } else {
            None
        }
    }
}

impl ConnWriter{

    fn new(stream: Rc<TcpStream>, direction: Direction) -> Self {
        ConnWriter{
            stream: stream,
            direction: direction,
            write_buf: vec![0u8; 4096],
            write_pos: 0,
            write_amt: 0
        }
    }

    /// Write a packet to the write buffer
    fn push(&mut self, p: &Packet) {
        for i in 0 .. p.bytes.len() {
            self.write_buf[self.write_pos + i] = p.bytes[i];
        }
        self.write_pos += p.bytes.len();

//        self.write_buf.truncate(self.write_pos);
//        self.write_buf.extend_from_slice(&p.bytes);
//        self.write_pos += p.bytes.len();
//        println!("{:?} extended write buffer by {} bytes", self.direction, p.bytes.len());
    }

    /// Writes the contents of the write buffer to the socket
    fn write(&mut self) -> Poll<(), io::Error> {
//        println!("{:?} write()", self.direction);
        while self.write_pos > 0 {
            try_ready!(self.stream.poll_write());
            let s = try!((&*self.stream).write(&self.write_buf[0..self.write_pos]));
//            println!("{:?} Wrote {} bytes", self.direction, s);

            let mut j = 0;
            for i in s .. self.write_buf.len() {
                self.write_buf[j] = self.write_buf[i];
                j += 1;
            }
            self.write_pos -= s;

        }
        return Ok(Async::Ready(()));
    }
}

struct Pipe<H: PacketHandler + 'static> {
    client_reader: ConnReader,
    client_writer: ConnWriter,
    server_reader: ConnReader,
    server_writer: ConnWriter,
    handler: H,
}

impl<H> Pipe<H> where H: PacketHandler + 'static {
    fn new(client: Rc<TcpStream>,
           server: Rc<TcpStream>,
           handler: H
           ) -> Pipe<H> {

        Pipe {
            client_reader: ConnReader::new(client.clone(), Direction::Client),
            client_writer: ConnWriter::new(client, Direction::Client),
            server_reader: ConnReader::new(server.clone(), Direction::Server),
            server_writer: ConnWriter::new(server, Direction::Server),
            handler: handler,
        }
    }
}

impl<H> Future for Pipe<H> where H: PacketHandler + 'static {
    type Item = (u64, u64);
    type Error = Error;

    fn poll(&mut self) -> Poll<(u64, u64), io::Error> {
        //println!("poll()");

        loop {
            // try reading from client
//            println!("CLIENT READ");
            let client_read = self.client_reader.read();

            // if the client connection has closed, close the server connection too
            match &client_read {
                &Err(ref e) => { self.server_writer.stream.shutdown(Shutdown::Write); },
                _ => {}
            }

            // process buffered requests
            while let Some(request) = self.client_reader.next() {
                match self.handler.handle_request(&request) {
                    Action::Forward => self.server_writer.push(&request),
                    Action::Mutate(ref p2) => self.server_writer.push(p2),
                    Action::Respond(ref v) => {
                        for p in v {
                            self.client_writer.push(&p);
                        }
                    }
                };
            }

            // try writing to server
//            println!("SERVER WRITE");
            let server_write = self.server_writer.write();

            // try reading from server
//            println!("SERVER READ");
            let server_read = self.server_reader.read();

            // if the server connection has closed, close the client connection too
            match &server_read {
                &Err(ref e) => { self.client_writer.stream.shutdown(Shutdown::Write); },
                _ => {}
            }

            // process buffered responses
            while let Some(response) = self.server_reader.next() {
                match self.handler.handle_response(&response) {
                    Action::Forward => self.client_writer.push(&response),
                    Action::Mutate(ref p2) => self.client_writer.push(p2),
                    Action::Respond(ref v) => {
                        for p in v {
                            self.server_writer.push(&p);
                        }
                    }
                };
            }

            // try writing to client
//            println!("CLIENT WRITE");
            let client_write = self.client_writer.write();

//            println!("client_read = {:?}", client_read);
//            println!("client_write = {:?}", client_write);
//            println!("server_read = {:?}", server_read);
//            println!("server_write = {:?}", server_write);

            try_ready!(client_read);
            try_ready!(client_write);
            try_ready!(server_read);
            try_ready!(server_write);
        }

    }

}

#[allow(dead_code)]
pub fn print_packet_chars(buf: &[u8]) {
    print!("[");
    for i in 0..buf.len() {
        print!("{} ", buf[i] as char);
    }
    println!("]");
}

#[allow(dead_code)]
pub fn print_packet_bytes(buf: &[u8]) {
    print!("[");
    for i in 0..buf.len() {
        if i%8==0 { println!(""); }
        print!("{:#04x} ",buf[i]);
    }
    println!("]");
}

<|endoftext|>


<commit_before>//! A simple implementation of Conway's Game of Life for terminal.
//!
//! # About
//!
//! This library is not meant for general usage.
//!
//! It does not use any of the established file formats for the Game of Life,
//! nor does it make any particular attempt at speed.
//!
//! It can parse a [`String`] to create a [`Grid`], make it tick, and print it.
//!
//! [`World`] will do the same and keep track of the generation as well.
//!
//! # Grid format
//!
//! Grids must be rectangular. Whitespace is ignored.
//!
//! ‘·’ (U+00B7 MIDDLE DOT) is a dead cell. Anything else is a living cell.

#![warn(missing_docs)]
#![warn(clippy::pedantic)]
#![warn(clippy::cargo)]
#![warn(clippy::nursery)]
#![deny(unsafe_code)]

use std::{
    fmt::{self, Display},
    str::FromStr,
};

pub use grid::{
    cell::Cell,
    error::{GridSizeError, ParseGridError},
    Grid,
};

mod grid;

/// A convenience wrapper for [`Grid`]. It keeps track of the generation.
///
/// It will print the size of the grid and the generation as well.
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct World {
    /// The grid of cells.
    grid: Grid,
    /// Number of generations passed.
    ///
    /// Starts at zero (the seed) and increases by one for every call to
    /// [`tick`](Self::tick).
    generation: u64,
}

impl FromStr for World {
    type Err = ParseGridError;

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        Ok(Self::new(s.parse()?))
    }
}

impl Display for World {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "{}\n{:?}, generation: {}", self.grid, self.grid.size(), self.generation)
    }
}

impl World {
    /// Make time tick. The next generation of cells will replace
    /// the current one.
    ///
    /// Births and deaths happen simultaneously according to the rules
    /// of Conway's Game of Life, after which the grid contains
    /// the next generation.
    pub fn tick(&mut self) {
        self.generation += 1;
        self.grid.tick();
    }
}

impl World {
    /// Creates a new `World` from a seed (generation 0).
    #[must_use]
    const fn new(seed: Grid) -> Self {
        Self { grid: seed, generation: 0 }
    }
}
<commit_msg>Make `World` more public<commit_after>//! A simple implementation of Conway's Game of Life for terminal.
//!
//! # About
//!
//! This library is not meant for general usage.
//!
//! It does not use any of the established file formats for the Game of Life,
//! nor does it make any particular attempt at speed.
//!
//! It can parse a [`String`] to create a [`Grid`], make it tick, and print it.
//!
//! [`World`] will do the same and keep track of the generation as well.
//!
//! # Grid format
//!
//! Grids must be rectangular. Whitespace is ignored.
//!
//! ‘·’ (U+00B7 MIDDLE DOT) is a dead cell. Anything else is a living cell.

#![warn(missing_docs)]
#![warn(clippy::pedantic)]
#![warn(clippy::cargo)]
#![warn(clippy::nursery)]
#![deny(unsafe_code)]

use std::{
    fmt::{self, Display},
    str::FromStr,
};

pub use grid::{
    cell::Cell,
    error::{GridSizeError, ParseGridError},
    Grid,
};

mod grid;

/// A convenience wrapper for [`Grid`]. It keeps track of the generation.
///
/// It will print the size of the grid and the generation as well.
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct World {
    /// The grid of cells.
    pub grid: Grid,
    /// Number of generations passed.
    ///
    /// Starts at zero (the seed) and increases by one for every call to
    /// [`tick`](Self::tick).
    pub generation: u64,
}

impl FromStr for World {
    type Err = ParseGridError;

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        Ok(Self::new(s.parse()?))
    }
}

impl Display for World {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "{}\n{:?}, generation: {}", self.grid, self.grid.size(), self.generation)
    }
}

impl World {
    /// Creates a new `World` from a seed (generation 0).
    #[must_use]
    pub const fn new(seed: Grid) -> Self {
        Self { grid: seed, generation: 0 }
    }

    /// Make time tick. The next generation of cells will replace
    /// the current one.
    ///
    /// Births and deaths happen simultaneously according to the rules
    /// of Conway's Game of Life, after which the grid contains
    /// the next generation.
    pub fn tick(&mut self) {
        self.generation += 1;
        self.grid.tick();
    }
}
<|endoftext|>