<commit_before>//! Zero-cost Futures in Rust
//!
//! This library is an implementation of futures in Rust which aims to provide
//! a robust implementation of handling asynchronous computations, ergonomic
//! composition and usage, and zero-cost abstractions over what would otherwise
//! be written by hand.
//!
//! Futures are a concept for an object which is a proxy for another value that
//! may not be ready yet. For example issuing an HTTP request may return a
//! future for the HTTP response, as it probably hasn't arrived yet. With an
//! object representing a value that will eventually be available, futures allow
//! for powerful composition of tasks through basic combinators that can perform
//! operations like chaining computations, changing the types of futures, or
//! waiting for two futures to complete at the same time.
//!
//! You can find extensive tutorials and documentations at [https://tokio.rs]
//! for both this crate (asynchronous programming in general) as well as the
//! Tokio stack to perform async I/O with.
//!
//! [https://tokio.rs]: https://tokio.rs
//!
//! ## Installation
//!
//! Add this to your `Cargo.toml`:
//!
//! ```toml
//! [dependencies]
//! futures = "0.1"
//! ```
//!
//! ## Examples
//!
//! Let's take a look at a few examples of how futures might be used:
//!
//! ```
//! extern crate futures;
//!
//! use std::io;
//! use std::time::Duration;
//! use futures::future::{Future, Map};
//!
//! // A future is actually a trait implementation, so we can generically take a
//! // future of any integer and return back a future that will resolve to that
//! // value plus 10 more.
//! //
//! // Note here that like iterators, we're returning the `Map` combinator in
//! // the futures crate, not a boxed abstraction. This is a zero-cost
//! // construction of a future.
//! fn add_ten<F>(future: F) -> Map<F, fn(i32) -> i32>
//!     where F: Future<Item=i32>,
//! {
//!     fn add(a: i32) -> i32 { a + 10 }
//!     future.map(add)
//! }
//!
//! // Not only can we modify one future, but we can even compose them together!
//! // Here we have a function which takes two futures as input, and returns a
//! // future that will calculate the sum of their two values.
//! //
//! // Above we saw a direct return value of the `Map` combinator, but
//! // performance isn't always critical and sometimes it's more ergonomic to
//! // return a trait object like we do here. Note though that there's only one
//! // allocation here, not any for the intermediate futures.
//! fn add<'a, A, B>(a: A, b: B) -> Box<Future<Item=i32, Error=A::Error> + 'a>
//!     where A: Future<Item=i32> + 'a,
//!           B: Future<Item=i32, Error=A::Error> + 'a,
//! {
//!     Box::new(a.join(b).map(|(a, b)| a + b))
//! }
//!
//! // Futures also allow chaining computations together, starting another after
//! // the previous finishes. Here we wait for the first computation to finish,
//! // and then decide what to do depending on the result.
//! fn download_timeout(url: &str,
//!                     timeout_dur: Duration)
//!                     -> Box<Future<Item=Vec<u8>, Error=io::Error>> {
//!     use std::io;
//!     use std::net::{SocketAddr, TcpStream};
//!
//!     type IoFuture<T> = Box<Future<Item=T, Error=io::Error>>;
//!
//!     // First thing to do is we need to resolve our URL to an address. This
//!     // will likely perform a DNS lookup which may take some time.
//!     let addr = resolve(url);
//!
//!     // After we acquire the address, we next want to open up a TCP
//!     // connection.
//!     let tcp = addr.and_then(|addr| connect(&addr));
//!
//!     // After the TCP connection is established and ready to go, we're off to
//!     // the races!
//!     let data = tcp.and_then(|conn| download(conn));
//!
//!     // That all might take awhile, though, so let's not wait too long for it
//!     // to all come back. The `select` combinator here returns a future which
//!     // resolves to the first value that's ready plus the next future.
//!     //
//!     // Note we can also use the `then` combinator which which is similar to
//!     // `and_then` above except that it receives the result of the
//!     // computation, not just the successful value.
//!     //
//!     // Again note that all the above calls to `and_then` and the below calls
//!     // to `map` and such require no allocations. We only ever allocate once
//!     // we hit the `.boxed()` call at the end here, which means we've built
//!     // up a relatively involved computation with only one box, and even that
//!     // was optional!
//!
//!     let data = data.map(Ok);
//!     let timeout = timeout(timeout_dur).map(Err);
//!
//!     let ret = data.select(timeout).then(|result| {
//!         match result {
//!             // One future succeeded, and it was the one which was
//!             // downloading data from the connection.
//!             Ok((Ok(data), _other_future)) => Ok(data),
//!
//!             // The timeout fired, and otherwise no error was found, so
//!             // we translate this to an error.
//!             Ok((Err(_timeout), _other_future)) => {
//!                 Err(io::Error::new(io::ErrorKind::Other, "timeout"))
//!             }
//!
//!             // A normal I/O error happened, so we pass that on through.
//!             Err((e, _other_future)) => Err(e),
//!         }
//!     });
//!     return Box::new(ret);
//!
//!     fn resolve(url: &str) -> IoFuture<SocketAddr> {
//!         // ...
//! #       panic!("unimplemented");
//!     }
//!
//!     fn connect(hostname: &SocketAddr) -> IoFuture<TcpStream> {
//!         // ...
//! #       panic!("unimplemented");
//!     }
//!
//!     fn download(stream: TcpStream) -> IoFuture<Vec<u8>> {
//!         // ...
//! #       panic!("unimplemented");
//!     }
//!
//!     fn timeout(stream: Duration) -> IoFuture<()> {
//!         // ...
//! #       panic!("unimplemented");
//!     }
//! }
//! # fn main() {}
//! ```
//!
//! Some more information can also be found in the [README] for now, but
//! otherwise feel free to jump in to the docs below!
//!
//! [README]: https://github.com/alexcrichton/futures-rs#futures-rs

#![no_std]
#![deny(missing_docs)]
#![doc(html_root_url = "https://docs.rs/futures/0.1")]

#[macro_use]
#[cfg(feature = "use_std")]
extern crate std;

#[macro_use]
extern crate log;

macro_rules! if_std {
    ($($i:item)*) => ($(
        #[cfg(feature = "use_std")]
        $i
    )*)
}

#[macro_use]
mod poll;
pub use poll::{Poll, Async, AsyncSink, StartSend};

pub mod future;
pub use future::{Future, IntoFuture};

pub mod stream;
pub use stream::Stream;

pub mod sink;
pub use sink::Sink;

#[deprecated(since = "0.1.4", note = "import through the future module instead")]
#[cfg(feature = "with-deprecated")]
#[doc(hidden)]
pub use future::{done, empty, failed, finished, lazy};

#[doc(hidden)]
#[cfg(feature = "with-deprecated")]
#[deprecated(since = "0.1.4", note = "import through the future module instead")]
pub use future::{
    Done, Empty, Failed, Finished, Lazy, AndThen, Flatten, FlattenStream, Fuse, IntoStream,
    Join, Join3, Join4, Join5, Map, MapErr, OrElse, Select,
    SelectNext, Then
};

if_std! {
    mod lock;
    mod task_impl;
    mod stack;

    pub mod task;
    pub mod executor;
    pub mod sync;

    #[doc(hidden)]
    #[deprecated(since = "0.1.4", note = "use sync::oneshot::channel instead")]
    #[cfg(feature = "with-deprecated")]
    pub use sync::oneshot::channel as oneshot;

    #[doc(hidden)]
    #[deprecated(since = "0.1.4", note = "use sync::oneshot::Receiver instead")]
    #[cfg(feature = "with-deprecated")]
    pub use sync::oneshot::Receiver as Oneshot;

    #[doc(hidden)]
    #[deprecated(since = "0.1.4", note = "use sync::oneshot::Sender instead")]
    #[cfg(feature = "with-deprecated")]
    pub use sync::oneshot::Sender as Complete;

    #[doc(hidden)]
    #[deprecated(since = "0.1.4", note = "use sync::oneshot::Canceled instead")]
    #[cfg(feature = "with-deprecated")]
    pub use sync::oneshot::Canceled;

    #[doc(hidden)]
    #[deprecated(since = "0.1.4", note = "import through the future module instead")]
    #[cfg(feature = "with-deprecated")]
    pub use future::{BoxFuture, collect, select_all, select_ok};

    #[doc(hidden)]
    #[deprecated(since = "0.1.4", note = "import through the future module instead")]
    #[cfg(feature = "with-deprecated")]
    pub use future::{SelectAll, SelectAllNext, Collect, SelectOk};
}
<commit_msg>Correct comment in docs<commit_after>//! Zero-cost Futures in Rust
//!
//! This library is an implementation of futures in Rust which aims to provide
//! a robust implementation of handling asynchronous computations, ergonomic
//! composition and usage, and zero-cost abstractions over what would otherwise
//! be written by hand.
//!
//! Futures are a concept for an object which is a proxy for another value that
//! may not be ready yet. For example issuing an HTTP request may return a
//! future for the HTTP response, as it probably hasn't arrived yet. With an
//! object representing a value that will eventually be available, futures allow
//! for powerful composition of tasks through basic combinators that can perform
//! operations like chaining computations, changing the types of futures, or
//! waiting for two futures to complete at the same time.
//!
//! You can find extensive tutorials and documentations at [https://tokio.rs]
//! for both this crate (asynchronous programming in general) as well as the
//! Tokio stack to perform async I/O with.
//!
//! [https://tokio.rs]: https://tokio.rs
//!
//! ## Installation
//!
//! Add this to your `Cargo.toml`:
//!
//! ```toml
//! [dependencies]
//! futures = "0.1"
//! ```
//!
//! ## Examples
//!
//! Let's take a look at a few examples of how futures might be used:
//!
//! ```
//! extern crate futures;
//!
//! use std::io;
//! use std::time::Duration;
//! use futures::future::{Future, Map};
//!
//! // A future is actually a trait implementation, so we can generically take a
//! // future of any integer and return back a future that will resolve to that
//! // value plus 10 more.
//! //
//! // Note here that like iterators, we're returning the `Map` combinator in
//! // the futures crate, not a boxed abstraction. This is a zero-cost
//! // construction of a future.
//! fn add_ten<F>(future: F) -> Map<F, fn(i32) -> i32>
//!     where F: Future<Item=i32>,
//! {
//!     fn add(a: i32) -> i32 { a + 10 }
//!     future.map(add)
//! }
//!
//! // Not only can we modify one future, but we can even compose them together!
//! // Here we have a function which takes two futures as input, and returns a
//! // future that will calculate the sum of their two values.
//! //
//! // Above we saw a direct return value of the `Map` combinator, but
//! // performance isn't always critical and sometimes it's more ergonomic to
//! // return a trait object like we do here. Note though that there's only one
//! // allocation here, not any for the intermediate futures.
//! fn add<'a, A, B>(a: A, b: B) -> Box<Future<Item=i32, Error=A::Error> + 'a>
//!     where A: Future<Item=i32> + 'a,
//!           B: Future<Item=i32, Error=A::Error> + 'a,
//! {
//!     Box::new(a.join(b).map(|(a, b)| a + b))
//! }
//!
//! // Futures also allow chaining computations together, starting another after
//! // the previous finishes. Here we wait for the first computation to finish,
//! // and then decide what to do depending on the result.
//! fn download_timeout(url: &str,
//!                     timeout_dur: Duration)
//!                     -> Box<Future<Item=Vec<u8>, Error=io::Error>> {
//!     use std::io;
//!     use std::net::{SocketAddr, TcpStream};
//!
//!     type IoFuture<T> = Box<Future<Item=T, Error=io::Error>>;
//!
//!     // First thing to do is we need to resolve our URL to an address. This
//!     // will likely perform a DNS lookup which may take some time.
//!     let addr = resolve(url);
//!
//!     // After we acquire the address, we next want to open up a TCP
//!     // connection.
//!     let tcp = addr.and_then(|addr| connect(&addr));
//!
//!     // After the TCP connection is established and ready to go, we're off to
//!     // the races!
//!     let data = tcp.and_then(|conn| download(conn));
//!
//!     // That all might take awhile, though, so let's not wait too long for it
//!     // to all come back. The `select` combinator here returns a future which
//!     // resolves to the first value that's ready plus the next future.
//!     //
//!     // Note we can also use the `then` combinator which which is similar to
//!     // `and_then` above except that it receives the result of the
//!     // computation, not just the successful value.
//!     //
//!     // Again note that all the above calls to `and_then` and the below calls
//!     // to `map` and such require no allocations. We only ever allocate once
//!     // we hit the `Box::new()` call at the end here, which means we've built
//!     // up a relatively involved computation with only one box, and even that
//!     // was optional!
//!
//!     let data = data.map(Ok);
//!     let timeout = timeout(timeout_dur).map(Err);
//!
//!     let ret = data.select(timeout).then(|result| {
//!         match result {
//!             // One future succeeded, and it was the one which was
//!             // downloading data from the connection.
//!             Ok((Ok(data), _other_future)) => Ok(data),
//!
//!             // The timeout fired, and otherwise no error was found, so
//!             // we translate this to an error.
//!             Ok((Err(_timeout), _other_future)) => {
//!                 Err(io::Error::new(io::ErrorKind::Other, "timeout"))
//!             }
//!
//!             // A normal I/O error happened, so we pass that on through.
//!             Err((e, _other_future)) => Err(e),
//!         }
//!     });
//!     return Box::new(ret);
//!
//!     fn resolve(url: &str) -> IoFuture<SocketAddr> {
//!         // ...
//! #       panic!("unimplemented");
//!     }
//!
//!     fn connect(hostname: &SocketAddr) -> IoFuture<TcpStream> {
//!         // ...
//! #       panic!("unimplemented");
//!     }
//!
//!     fn download(stream: TcpStream) -> IoFuture<Vec<u8>> {
//!         // ...
//! #       panic!("unimplemented");
//!     }
//!
//!     fn timeout(stream: Duration) -> IoFuture<()> {
//!         // ...
//! #       panic!("unimplemented");
//!     }
//! }
//! # fn main() {}
//! ```
//!
//! Some more information can also be found in the [README] for now, but
//! otherwise feel free to jump in to the docs below!
//!
//! [README]: https://github.com/alexcrichton/futures-rs#futures-rs

#![no_std]
#![deny(missing_docs)]
#![doc(html_root_url = "https://docs.rs/futures/0.1")]

#[macro_use]
#[cfg(feature = "use_std")]
extern crate std;

#[macro_use]
extern crate log;

macro_rules! if_std {
    ($($i:item)*) => ($(
        #[cfg(feature = "use_std")]
        $i
    )*)
}

#[macro_use]
mod poll;
pub use poll::{Poll, Async, AsyncSink, StartSend};

pub mod future;
pub use future::{Future, IntoFuture};

pub mod stream;
pub use stream::Stream;

pub mod sink;
pub use sink::Sink;

#[deprecated(since = "0.1.4", note = "import through the future module instead")]
#[cfg(feature = "with-deprecated")]
#[doc(hidden)]
pub use future::{done, empty, failed, finished, lazy};

#[doc(hidden)]
#[cfg(feature = "with-deprecated")]
#[deprecated(since = "0.1.4", note = "import through the future module instead")]
pub use future::{
    Done, Empty, Failed, Finished, Lazy, AndThen, Flatten, FlattenStream, Fuse, IntoStream,
    Join, Join3, Join4, Join5, Map, MapErr, OrElse, Select,
    SelectNext, Then
};

if_std! {
    mod lock;
    mod task_impl;
    mod stack;

    pub mod task;
    pub mod executor;
    pub mod sync;

    #[doc(hidden)]
    #[deprecated(since = "0.1.4", note = "use sync::oneshot::channel instead")]
    #[cfg(feature = "with-deprecated")]
    pub use sync::oneshot::channel as oneshot;

    #[doc(hidden)]
    #[deprecated(since = "0.1.4", note = "use sync::oneshot::Receiver instead")]
    #[cfg(feature = "with-deprecated")]
    pub use sync::oneshot::Receiver as Oneshot;

    #[doc(hidden)]
    #[deprecated(since = "0.1.4", note = "use sync::oneshot::Sender instead")]
    #[cfg(feature = "with-deprecated")]
    pub use sync::oneshot::Sender as Complete;

    #[doc(hidden)]
    #[deprecated(since = "0.1.4", note = "use sync::oneshot::Canceled instead")]
    #[cfg(feature = "with-deprecated")]
    pub use sync::oneshot::Canceled;

    #[doc(hidden)]
    #[deprecated(since = "0.1.4", note = "import through the future module instead")]
    #[cfg(feature = "with-deprecated")]
    pub use future::{BoxFuture, collect, select_all, select_ok};

    #[doc(hidden)]
    #[deprecated(since = "0.1.4", note = "import through the future module instead")]
    #[cfg(feature = "with-deprecated")]
    pub use future::{SelectAll, SelectAllNext, Collect, SelectOk};
}
<|endoftext|>


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

extern crate byteorder;
extern crate syntax;
#[macro_use]
extern crate rustc;
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::sync::{mpsc, Arc};

use crate::rustc::dep_graph::DepGraph;
use crate::rustc::middle::cstore::MetadataLoader;
use crate::rustc::session::{config::OutputFilenames, CompileIncomplete};
use crate::rustc::ty::query::Providers;
use crate::rustc_codegen_utils::codegen_backend::CodegenBackend;
use crate::rustc_codegen_utils::link::out_filename;
use crate::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 analyze;
mod base;
mod common;
mod constant;
mod intrinsics;
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 crate::rustc::hir::def_id::{DefId, LOCAL_CRATE};
    pub use crate::rustc::mir;
    pub use crate::rustc::mir::interpret::AllocId;
    pub use crate::rustc::mir::*;
    pub use crate::rustc::session::{config::CrateType, Session};
    pub use crate::rustc::ty::layout::{self, Abi, LayoutOf, Scalar, Size, TyLayout};
    pub use crate::rustc::ty::{
        self, subst::Substs, FnSig, Instance, InstanceDef, ParamEnv, PolyFnSig, Ty, TyCtxt,
        TypeAndMut, TypeFoldable,
    };
    pub use crate::rustc_data_structures::{
        fx::{FxHashMap, FxHashSet},
        indexed_vec::Idx,
        sync::Lrc,
    };
    pub use crate::rustc_mir::monomorphize::{collector, MonoItem};
    pub use crate::syntax::ast::{FloatTy, IntTy, UintTy};
    pub use crate::syntax::source_map::DUMMY_SP;

    pub use cranelift::codegen::isa::CallConv;
    pub use cranelift::codegen::ir::{
        condcodes::IntCC, function::Function, ExternalName, FuncRef, Inst, StackSlot,
    };
    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;

    pub fn should_codegen(_sess: &Session) -> bool {
        true
        //::std::env::var("SHOULD_CODEGEN").is_ok()
        //    || sess.crate_types.get().contains(&CrateType::Executable)
    }
}

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;

struct OngoingCodegen {
    product: cranelift_faerie::FaerieProduct,
    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
                    ));
                }
            }
        }
    }

    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);

        providers.target_features_whitelist = |_tcx, _cnum| Lrc::new(Default::default());
        providers.is_reachable_non_generic = |_tcx, _defid| true;
        providers.exported_symbols = |_tcx, _crate| Arc::new(Vec::new());
        providers.upstream_monomorphizations = |_tcx, _cnum| Lrc::new(FxHashMap::default());
        providers.upstream_monomorphizations_for = |tcx, def_id| {
            debug_assert!(!def_id.is_local());
            tcx.upstream_monomorphizations(LOCAL_CRATE)
                .get(&def_id)
                .cloned()
        };
    }
    fn provide_extern(&self, providers: &mut Providers) {
        providers.is_reachable_non_generic = |_tcx, _defid| true;
    }

    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);

        let mono_items =
            collector::collect_crate_mono_items(tcx, collector::MonoItemCollectionMode::Lazy).0;

        // 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");

        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());

            codegen_mono_items(tcx, &mut jit_module, mono_items);

            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 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();

            jit_module.finalize_definitions();
            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, mono_items);

            tcx.sess.abort_if_errors();

            if should_codegen(tcx.sess) {
                faerie_module.finalize_definitions();
            }

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

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

        let artifact = ongoing_codegen.product.artifact;
        let metadata = ongoing_codegen.metadata;

        /*
        artifact
            .declare_with(
                &metadata_name,
                faerie::artifact::Decl::Data {
                    global: true,
                    writable: false,
                },
                metadata.clone(),
            )
            .unwrap();
        */

        for &crate_type in sess.opts.crate_types.iter() {
            match crate_type {
                // TODO: link executable
                CrateType::Executable | CrateType::Rlib => {
                    let output_name = out_filename(
                        sess,
                        crate_type,
                        &outputs,
                        &ongoing_codegen.crate_name.as_str(),
                    );
                    let file = File::create(&output_name).unwrap();
                    let mut builder = ar::Builder::new(file);

                    if should_codegen(sess) {
                        // Add main object file
                        let obj = artifact.emit().unwrap();
                        builder
                            .append(
                                &ar::Header::new(b"data.o".to_vec(), obj.len() as u64),
                                ::std::io::Cursor::new(obj),
                            )
                            .unwrap();
                    }

                    // Non object files need to be added after object files, because ranlib will
                    // try to read the native architecture from the first file, even if it isn't
                    // an object file
                    if crate_type != CrateType::Executable {
                        builder
                            .append(
                                &ar::Header::new(
                                    metadata::METADATA_FILE.to_vec(),
                                    metadata.len() as u64,
                                ),
                                ::std::io::Cursor::new(metadata.clone()),
                            )
                            .unwrap();
                    }

                    // Finalize archive
                    std::mem::drop(builder);

                    // Run ranlib to be able to link the archive
                    let status = std::process::Command::new("ranlib")
                        .arg(output_name)
                        .status()
                        .expect("Couldn't run ranlib");
                    if !status.success() {
                        sess.fatal(&format!("Ranlib exited with code {:?}", status.code()));
                    }
                }
                _ => 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>,
    mono_items: FxHashSet<MonoItem<'tcx>>,
) {
    use std::io::Write;

    let mut caches = Caches::new();
    let mut ccx = ConstantCx::default();

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

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

    for mono_item 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);
                    }
                    tcx.sess.err(&non_fatal.0)
                }
                Err(err) => ::std::panic::resume_unwind(err),
            }
        }
    }

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

    ccx.finalize(tcx, module);

    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>Use cg_utils::symbol_export::provide{,_extern}<commit_after>#![feature(rustc_private, macro_at_most_once_rep, never_type)]
#![allow(intra_doc_link_resolution_failure)]

extern crate byteorder;
extern crate syntax;
#[macro_use]
extern crate rustc;
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::sync::{mpsc, Arc};

use crate::rustc::dep_graph::DepGraph;
use crate::rustc::middle::cstore::MetadataLoader;
use crate::rustc::session::{config::OutputFilenames, CompileIncomplete};
use crate::rustc::ty::query::Providers;
use crate::rustc_codegen_utils::codegen_backend::CodegenBackend;
use crate::rustc_codegen_utils::link::out_filename;
use crate::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 analyze;
mod base;
mod common;
mod constant;
mod intrinsics;
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 crate::rustc::hir::def_id::{DefId, LOCAL_CRATE};
    pub use crate::rustc::mir;
    pub use crate::rustc::mir::interpret::AllocId;
    pub use crate::rustc::mir::*;
    pub use crate::rustc::session::{config::CrateType, Session};
    pub use crate::rustc::ty::layout::{self, Abi, LayoutOf, Scalar, Size, TyLayout};
    pub use crate::rustc::ty::{
        self, subst::Substs, FnSig, Instance, InstanceDef, ParamEnv, PolyFnSig, Ty, TyCtxt,
        TypeAndMut, TypeFoldable,
    };
    pub use crate::rustc_data_structures::{
        fx::{FxHashMap, FxHashSet},
        indexed_vec::Idx,
        sync::Lrc,
    };
    pub use crate::rustc_mir::monomorphize::{collector, MonoItem};
    pub use crate::syntax::ast::{FloatTy, IntTy, UintTy};
    pub use crate::syntax::source_map::DUMMY_SP;

    pub use cranelift::codegen::isa::CallConv;
    pub use cranelift::codegen::ir::{
        condcodes::IntCC, function::Function, ExternalName, FuncRef, Inst, StackSlot,
    };
    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;

    pub fn should_codegen(_sess: &Session) -> bool {
        true
        //::std::env::var("SHOULD_CODEGEN").is_ok()
        //    || sess.crate_types.get().contains(&CrateType::Executable)
    }
}

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;

struct OngoingCodegen {
    product: cranelift_faerie::FaerieProduct,
    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
                    ));
                }
            }
        }
    }

    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);

        let mono_items =
            collector::collect_crate_mono_items(tcx, collector::MonoItemCollectionMode::Lazy).0;

        // 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");

        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());

            codegen_mono_items(tcx, &mut jit_module, mono_items);

            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 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();

            jit_module.finalize_definitions();
            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, mono_items);

            tcx.sess.abort_if_errors();

            if should_codegen(tcx.sess) {
                faerie_module.finalize_definitions();
            }

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

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

        let artifact = ongoing_codegen.product.artifact;
        let metadata = ongoing_codegen.metadata;

        /*
        artifact
            .declare_with(
                &metadata_name,
                faerie::artifact::Decl::Data {
                    global: true,
                    writable: false,
                },
                metadata.clone(),
            )
            .unwrap();
        */

        for &crate_type in sess.opts.crate_types.iter() {
            match crate_type {
                // TODO: link executable
                CrateType::Executable | CrateType::Rlib => {
                    let output_name = out_filename(
                        sess,
                        crate_type,
                        &outputs,
                        &ongoing_codegen.crate_name.as_str(),
                    );
                    let file = File::create(&output_name).unwrap();
                    let mut builder = ar::Builder::new(file);

                    if should_codegen(sess) {
                        // Add main object file
                        let obj = artifact.emit().unwrap();
                        builder
                            .append(
                                &ar::Header::new(b"data.o".to_vec(), obj.len() as u64),
                                ::std::io::Cursor::new(obj),
                            )
                            .unwrap();
                    }

                    // Non object files need to be added after object files, because ranlib will
                    // try to read the native architecture from the first file, even if it isn't
                    // an object file
                    if crate_type != CrateType::Executable {
                        builder
                            .append(
                                &ar::Header::new(
                                    metadata::METADATA_FILE.to_vec(),
                                    metadata.len() as u64,
                                ),
                                ::std::io::Cursor::new(metadata.clone()),
                            )
                            .unwrap();
                    }

                    // Finalize archive
                    std::mem::drop(builder);

                    // Run ranlib to be able to link the archive
                    let status = std::process::Command::new("ranlib")
                        .arg(output_name)
                        .status()
                        .expect("Couldn't run ranlib");
                    if !status.success() {
                        sess.fatal(&format!("Ranlib exited with code {:?}", status.code()));
                    }
                }
                _ => 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>,
    mono_items: FxHashSet<MonoItem<'tcx>>,
) {
    use std::io::Write;

    let mut caches = Caches::new();
    let mut ccx = ConstantCx::default();

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

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

    for mono_item 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);
                    }
                    tcx.sess.err(&non_fatal.0)
                }
                Err(err) => ::std::panic::resume_unwind(err),
            }
        }
    }

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

    ccx.finalize(tcx, module);

    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>#[macro_use]
extern crate log;

extern crate regex;
use std::path::PathBuf;
use std::fs::File;
use std::io::Read;
use regex::Regex;
use std::io::Write;

mod ast;
mod context;
mod error;
mod evaluator;
mod sass;
mod optimizer;
mod parser;
mod token;
mod tokenizer;

use context::Context;
use error::Result;
use tokenizer::Tokenizer;
use parser::Parser;
use sass::output_style::SassOutputStyle;

fn resolve_imports(inputpath: &PathBuf) -> Result<String> {
    let mut file = try!(File::open(&inputpath));
    let mut sass = String::new();

    try!(file.read_to_string(&mut sass));

    let mut imports_resolved = String::new();
    for line in sass.split("\n") {
        let re = Regex::new("@import \"([^\"]*)\";").unwrap();

        match re.captures(line) {
            Some(caps) => {
                let imported = try!(resolve_imports(&inputpath.with_file_name(caps.at(1).unwrap())));
                imports_resolved.push_str(&imported);
            },
            None => {
                imports_resolved.push_str(line);
            },
        }
        imports_resolved.push_str("\n");
    }
    Ok(imports_resolved)
}

pub fn compile<W: Write>(input_filename: &str, output: &mut W, style: &str) -> Result<()> {
    let input_path = PathBuf::from(input_filename);
    let imports_resolved = try!(resolve_imports(&input_path));

    let style: SassOutputStyle = try!(style.parse());

    match style {
        SassOutputStyle::Tokens => {
            let mut tokenizer = Tokenizer::new(&imports_resolved);
            while let Some(token) = tokenizer.next() {
                try!(write!(output, "{:?}\n", token))
            }
        },
        SassOutputStyle::AST => {
            let mut parser = Parser::new(&imports_resolved);
            while let Some(ast_node) = parser.next() {
                try!(write!(output, "{:?}\n", ast_node));
            }
        },
        other_style => {
            let mut parser  = Parser::new(&imports_resolved);
            let mut context = Context::new();
            while let Some(Ok(ast_node)) = parser.next() {
                let evaluated = evaluator::evaluate(ast_node, &mut context);
                if let Some(root) = evaluated {
                    let optimized = optimizer::optimize(root);
                    for r in optimized {
                        try!(r.stream(output, other_style));
                    }
                }
            }
        },
    }

    Ok(())
}
<commit_msg>Rename local variable ast_node to ast_root<commit_after>#[macro_use]
extern crate log;

extern crate regex;
use std::path::PathBuf;
use std::fs::File;
use std::io::Read;
use regex::Regex;
use std::io::Write;

mod ast;
mod context;
mod error;
mod evaluator;
mod sass;
mod optimizer;
mod parser;
mod token;
mod tokenizer;

use context::Context;
use error::Result;
use tokenizer::Tokenizer;
use parser::Parser;
use sass::output_style::SassOutputStyle;

fn resolve_imports(inputpath: &PathBuf) -> Result<String> {
    let mut file = try!(File::open(&inputpath));
    let mut sass = String::new();

    try!(file.read_to_string(&mut sass));

    let mut imports_resolved = String::new();
    for line in sass.split("\n") {
        let re = Regex::new("@import \"([^\"]*)\";").unwrap();

        match re.captures(line) {
            Some(caps) => {
                let imported = try!(resolve_imports(&inputpath.with_file_name(caps.at(1).unwrap())));
                imports_resolved.push_str(&imported);
            },
            None => {
                imports_resolved.push_str(line);
            },
        }
        imports_resolved.push_str("\n");
    }
    Ok(imports_resolved)
}

pub fn compile<W: Write>(input_filename: &str, output: &mut W, style: &str) -> Result<()> {
    let input_path = PathBuf::from(input_filename);
    let imports_resolved = try!(resolve_imports(&input_path));

    let style: SassOutputStyle = try!(style.parse());

    match style {
        SassOutputStyle::Tokens => {
            let mut tokenizer = Tokenizer::new(&imports_resolved);
            while let Some(token) = tokenizer.next() {
                try!(write!(output, "{:?}\n", token))
            }
        },
        SassOutputStyle::AST => {
            let mut parser = Parser::new(&imports_resolved);
            while let Some(ast_root) = parser.next() {
                try!(write!(output, "{:?}\n", ast_root));
            }
        },
        other_style => {
            let mut parser  = Parser::new(&imports_resolved);
            let mut context = Context::new();
            while let Some(Ok(ast_root)) = parser.next() {
                let evaluated = evaluator::evaluate(ast_root, &mut context);
                if let Some(root) = evaluated {
                    let optimized = optimizer::optimize(root);
                    for r in optimized {
                        try!(r.stream(output, other_style));
                    }
                }
            }
        },
    }

    Ok(())
}
<|endoftext|>


<commit_before>//! Atomic counting semaphore that can help you control access to a common resource
//! by multiple processes in a concurrent system.
//!
//! ## Features
//!
//! - Fully lock-free* semantics
//! - Provides RAII-style acquire/release API
//! - Implements `Send`, `Sync` and `Clone`
//!
//! _* when not using the `shutdown` API_

extern crate parking_lot;

use std::ops::Deref;
use std::sync::Arc;

use parking_lot::RwLock;

mod raw;
use raw::RawSemaphore;

#[derive(Debug)]
/// An error indicating a failure to acquire access to the resource
/// behind the semaphore.
///
/// Returned from `Semaphore::try_access`.
pub enum TryAccessError {
    /// The capacity of the semaphore was exceeded.
    CapacityExceeded,
    /// The semaphore has been shut down.
    Shutdown
}

/// An atomic counter which can be shared across processes.
pub struct Semaphore<T> {
    raw: Arc<RawSemaphore>,
    resource: Arc<RwLock<Option<Arc<T>>>>
}

impl<T> Clone for Semaphore<T> {
    fn clone(&self) -> Semaphore<T> {
        Semaphore {
            raw: self.raw.clone(),
            resource: self.resource.clone()
        }
    }
}

impl<T> Semaphore<T> {
    /// Create a new semaphore with the given limit.
    pub fn new(limit: usize, resource: T) -> Self {
        Semaphore {
            raw: Arc::new(RawSemaphore::new(limit)),
            resource: Arc::new(RwLock::new(Some(Arc::new(resource))))
        }
    }

    #[inline]
    /// Attempt to access the underlying resource of this semaphore.
    ///
    /// This function will try to acquire access, and then return an RAII
    /// guard structure which will release the access when it falls out of scope.
    ///
    /// If the semaphore is at limit or currently shutting down,
    /// a `TryAccessError` will be returned.
    pub fn try_access(&self) -> Result<Guard<T>, TryAccessError> {
        if let Some(ref resource) = *self.resource.read() {
            if self.raw.try_acquire() {
                Ok(Guard { raw: self.raw.clone(), resource: resource.clone() })
            } else {
                Err(TryAccessError::CapacityExceeded)
            }
        } else {
            Err(TryAccessError::Shutdown)
        }
    }

    /// Shut down the semaphore.
    ///
    /// This prevents any further access from being granted to the underlying resource.
    ///
    /// As soon as the last access is released and the returned handle goes out of scope,
    /// the resource will be dropped.
    ///
    /// Does _not_ block until the resource is no longer in use. If you would like to do that,
    /// you can call `wait` on the returned handle.
    pub fn shutdown(&self) -> ShutdownHandle<T> {
        ShutdownHandle {
            raw: self.raw.clone(),
            _resource: self.resource.write().take()
        }
    }
}

/// A handle representing the shutdown process of a semaphore.
pub struct ShutdownHandle<T> {
    raw: Arc<RawSemaphore>,
    _resource: Option<Arc<T>>
}

impl<T> ShutdownHandle<T> {
    /// Block until the resource is not being accessed anymore.
    ///
    /// Please note that this does not take into account any unguarded
    /// references. This means that after the method returned the resource
    /// could still be kept alive by one or more unguarded references.
    pub fn wait(&self) {
        self.raw.wait_until_all_released()
    }
}

/// An RAII guard used to release a semaphore automatically when it falls out of scope.
pub struct Guard<T> {
    raw: Arc<RawSemaphore>,
    resource: Arc<T>
}

impl<T> Guard<T> {
    #[inline]
    /// Spawns an unguarded reference to the resource.
    pub fn as_unguarded(&self) -> UnguardedRef<T> {
        UnguardedRef { resource: self.resource.clone() }
    }
}

impl<T> Drop for Guard<T> {
    #[inline]
    fn drop(&mut self) {
        self.raw.release()
    }
}

impl<T: Sized> Deref for Guard<T> {
    type Target = T;

    #[inline]
    fn deref(&self) -> &T {
        self.resource.deref()
    }
}

/// An unguarded reference to a resource.
///
/// Can be created via `Guard::unguard`.
///
/// This reference is not tracked by the semaphore around the resource.
/// It can therefore be used in situations where after acquiring access
/// you want to split access to the resource.
///
/// Caution is advised as the existence of unguarded references will cause
/// the resource to be retained, even when the semaphore has fully shut down.
pub struct UnguardedRef<T> {
    resource: Arc<T>
}

impl<T: Sized> Deref for UnguardedRef<T> {
    type Target = T;

    #[inline]
    fn deref(&self) -> &T {
        self.resource.deref()
    }
}

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

    #[test]
    fn succeeds_to_acquire_when_empty() {
        let sema = Semaphore::new(1, ());
        assert!(sema.try_access().ok().is_some());
    }

    #[test]
    fn fails_to_acquire_when_full() {
        let sema = Semaphore::new(4, ());
        let guards = (0..4).map(|_| {
            sema.try_access().expect("guard acquisition failed")
        }).collect::<Vec<_>>();
        assert!(sema.try_access().err().is_some());
        drop(guards);
    }

    #[test]
    fn dropping_guard_frees_capacity() {
        let sema = Semaphore::new(1, ());
        let guard = sema.try_access().expect("guard acquisition failed");
        drop(guard);
        assert!(sema.try_access().ok().is_some());
    }
}
<commit_msg>introduce cloning for guards<commit_after>//! Atomic counting semaphore that can help you control access to a common resource
//! by multiple processes in a concurrent system.
//!
//! ## Features
//!
//! - Fully lock-free* semantics
//! - Provides RAII-style acquire/release API
//! - Implements `Send`, `Sync` and `Clone`
//!
//! _* when not using the `shutdown` API_

extern crate parking_lot;

use std::ops::Deref;
use std::sync::Arc;

use parking_lot::RwLock;

mod raw;
use raw::RawSemaphore;

#[derive(Debug)]
/// An error indicating a failure to acquire access to the resource
/// behind the semaphore.
///
/// Returned from `Semaphore::try_access`.
pub enum TryAccessError {
    /// The capacity of the semaphore was exceeded.
    CapacityExceeded,
    /// The semaphore has been shut down.
    Shutdown
}

/// An atomic counter that can help you control shared access to a resource.
pub struct Semaphore<T> {
    raw: Arc<RawSemaphore>,
    resource: Arc<RwLock<Option<Arc<T>>>>
}

impl<T> Clone for Semaphore<T> {
    fn clone(&self) -> Semaphore<T> {
        Semaphore {
            raw: self.raw.clone(),
            resource: self.resource.clone()
        }
    }
}

impl<T> Semaphore<T> {
    /// Create a new semaphore around a resource with the given limit.
    pub fn new(limit: usize, resource: T) -> Self {
        Semaphore {
            raw: Arc::new(RawSemaphore::new(limit)),
            resource: Arc::new(RwLock::new(Some(Arc::new(resource))))
        }
    }

    #[inline]
    /// Attempt to access the underlying resource of this semaphore.
    ///
    /// This function will try to acquire access, and then return an RAII
    /// guard structure which will release the access when it falls out of scope.
    ///
    /// If the semaphore is at limit or currently shutting down,
    /// a `TryAccessError` will be returned.
    pub fn try_access(&self) -> Result<Guard<T>, TryAccessError> {
        if let Some(ref resource) = *self.resource.read() {
            if self.raw.try_acquire() {
                Ok(Guard { raw: self.raw.clone(), resource: Arc::new(resource.clone()) })
            } else {
                Err(TryAccessError::CapacityExceeded)
            }
        } else {
            Err(TryAccessError::Shutdown)
        }
    }

    /// Shut down the semaphore.
    ///
    /// This prevents any further access from being granted to the underlying resource.
    ///
    /// As soon as the last access is released and the returned handle goes out of scope,
    /// the resource will be dropped.
    ///
    /// Does _not_ block until the resource is no longer in use. If you would like to do that,
    /// you can call `wait` on the returned handle.
    pub fn shutdown(&self) -> ShutdownHandle<T> {
        ShutdownHandle {
            raw: self.raw.clone(),
            _resource: self.resource.write().take()
        }
    }
}

/// A handle representing the shutdown process of a semaphore.
pub struct ShutdownHandle<T> {
    raw: Arc<RawSemaphore>,
    _resource: Option<Arc<T>>
}

impl<T> ShutdownHandle<T> {
    /// Block until the resource is not being accessed anymore.
    ///
    /// Please note that this does not take into account any unguarded
    /// references. This means that after the method returned the resource
    /// could still be kept alive by one or more unguarded references.
    pub fn wait(&self) {
        self.raw.wait_until_all_released()
    }
}

/// An RAII guard used to release access to the semaphore automatically when it falls out of scope.
///
/// Guards can be cloned, in which case the original guard and all descendent grants need
/// to go out of scope for the single access to be released on the semaphore.
pub struct Guard<T> {
    raw: Arc<RawSemaphore>,
    resource: Arc<Arc<T>>
}

impl<T> Clone for Guard<T> {
    #[inline]
    fn clone(&self) -> Guard<T> {
        Guard { raw: self.raw.clone(), resource: self.resource.clone() }
    }
}

impl<T> Guard<T> {
    #[inline]
    #[deprecated(since="0.2.1", note="please use `Grant::clone` instead")]
    /// Spawns an unguarded reference to the resource.
    pub fn as_unguarded(&self) -> UnguardedRef<T> {
        UnguardedRef { resource: (*self.resource).clone() }
    }
}

impl<T> Drop for Guard<T> {
    #[inline]
    fn drop(&mut self) {
        self.raw.release()
    }
}

impl<T: Sized> Deref for Guard<T> {
    type Target = T;

    #[inline]
    fn deref(&self) -> &T {
        self.resource.deref()
    }
}

/// An unguarded reference to a resource.
///
/// Can be created via `Guard::as_unguarded`.
///
/// This reference is not tracked by the semaphore around the resource.
/// It can therefore be used in situations where after acquiring access
/// you want to split access to the resource.
///
/// Caution is advised as the existence of unguarded references will cause
/// the resource to be retained, even when the semaphore has fully shut down.
pub struct UnguardedRef<T> {
    resource: Arc<T>
}

impl<T: Sized> Deref for UnguardedRef<T> {
    type Target = T;

    #[inline]
    fn deref(&self) -> &T {
        self.resource.deref()
    }
}

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

    #[test]
    fn succeeds_to_acquire_when_empty() {
        let sema = Semaphore::new(1, ());
        assert!(sema.try_access().ok().is_some());
    }

    #[test]
    fn fails_to_acquire_when_full() {
        let sema = Semaphore::new(4, ());
        let guards = (0..4).map(|_| {
            sema.try_access().expect("guard acquisition failed")
        }).collect::<Vec<_>>();
        assert!(sema.try_access().err().is_some());
        drop(guards);
    }

    #[test]
    fn dropping_guard_frees_capacity() {
        let sema = Semaphore::new(1, ());
        let guard = sema.try_access().expect("guard acquisition failed");
        drop(guard);
        assert!(sema.try_access().ok().is_some());
    }
}
<|endoftext|>


<commit_before>// Copyright © 2015 by Michael Dilger (of New Zealand)
// This code is licensed under the MIT license (see LICENSE-MIT for details)

//! This crate parses and processes a stream of data that contains
//! `multipart/form-data` content.
//!
//! The main entry point is `read_formdata`

#![cfg_attr(feature="clippy", feature(plugin))]
#![cfg_attr(feature="clippy", plugin(clippy))]

extern crate httparse;
extern crate hyper;
#[macro_use]
extern crate mime;
extern crate textnonce;
#[macro_use]
extern crate log;
extern crate encoding;

extern crate mime_multipart;

mod error;
mod form_data;
#[cfg(test)]
mod mock;

pub use error::Error;
pub use form_data::FormData;

use std::io::Read;
use hyper::header::{Headers, ContentDisposition, DispositionParam};
use mime_multipart::Node;

/// Parse MIME `multipart/form-data` information from a stream as a `FormData`.
pub fn read_formdata<S: Read>(stream: &mut S, headers: &Headers) -> Result<FormData, Error>
{
    let nodes = try!(mime_multipart::read_multipart_body(stream, headers, false));

    let mut formdata = FormData::new();
    try!(fill_formdata(&mut formdata, nodes));
    Ok(formdata)
}

// order and nesting are irrelevant, so we interate through the nodes and put them
// into one of two buckets (fields and files);  If a multipart node is found, it uses
// the name in its headers as the key (rather than the name in the headers of the
// subparts), which is how multiple file uploads work.
fn fill_formdata(formdata: &mut FormData, nodes: Vec<Node>) -> Result<(), Error>
{
    for node in nodes {
        match node {
            Node::Part(part) => {
                let cd_name: Option<String> = {
                    let cd: &ContentDisposition = match part.headers.get() {
                        Some(cd) => cd,
                        None => return Err(Error::MissingDisposition),
                    };
                    get_content_disposition_name(&cd)
                };
                let key = try!(cd_name.ok_or(Error::NoName));
                let val = try!(String::from_utf8(part.body));
                formdata.fields.push((key, val));
            },
            Node::File(part) => {
                let cd_name: Option<String> = {
                    let cd: &ContentDisposition = match part.headers.get() {
                        Some(cd) => cd,
                        None => return Err(Error::MissingDisposition),
                    };
                    get_content_disposition_name(&cd)
                };
                let key = try!(cd_name.ok_or(Error::NoName));
                formdata.files.push((key, part));
            }
            Node::Multipart((headers, nodes)) => {
                let cd_name: Option<String> = {
                    let cd: &ContentDisposition = match headers.get() {
                        Some(cd) => cd,
                        None => return Err(Error::MissingDisposition),
                    };
                    get_content_disposition_name(&cd)
                };
                let key = try!(cd_name.ok_or(Error::NoName));
                for node in nodes {
                    match node {
                        Node::Part(part) => {
                            let val = try!(String::from_utf8(part.body));
                            formdata.fields.push((key.clone(), val));
                        },
                        Node::File(part) => {
                            formdata.files.push((key.clone(), part));
                        },
                        _ => { } // don't recurse deeper
                    }
                }
            }
        }
    }
    Ok(())
}

#[inline]
fn get_content_disposition_name(cd: &ContentDisposition) -> Option<String> {
    if let Some(&DispositionParam::Ext(_, ref value)) = cd.parameters.iter()
        .find(|&x| match *x {
            DispositionParam::Ext(ref token,_) => &*token == "name",
            _ => false,
        })
    {
        Some(value.clone())
    } else {
        None
    }
}

#[cfg(test)]
mod tests {
    extern crate tempdir;

    use super::*;

    use std::net::SocketAddr;

    use hyper::buffer::BufReader;
    use hyper::net::NetworkStream;
    use hyper::server::Request as HyperRequest;

    use mock::MockStream;

    #[test]
    fn parser() {
        let input = b"POST / HTTP/1.1\r\n\
                      Host: example.domain\r\n\
                      Content-Type: multipart/form-data; boundary=\"abcdefg\"\r\n\
                      Content-Length: 1000\r\n\
                      \r\n\
                      --abcdefg\r\n\
                      Content-Disposition: form-data; name=\"field1\"\r\n\
                      \r\n\
                      data1\r\n\
                      --abcdefg\r\n\
                      Content-Disposition: form-data; name=\"field2\"; filename=\"image.gif\"\r\n\
                      Content-Type: image/gif\r\n\
                      \r\n\
                      This is a file\r\n\
                      with two lines\r\n\
                      --abcdefg\r\n\
                      Content-Disposition: form-data; name=\"field3\"; filename=\"file.txt\"\r\n\
                      \r\n\
                      This is a file\r\n\
                      --abcdefg--";

        let mut mock = MockStream::with_input(input);

        let mock: &mut NetworkStream = &mut mock;
        let mut stream = BufReader::new(mock);
        let sock: SocketAddr = "127.0.0.1:80".parse().unwrap();
        let req = HyperRequest::new(&mut stream, sock).unwrap();
        let (_, _, headers, _, _, mut reader) = req.deconstruct();

        match read_formdata(&mut reader, &headers) {
            Ok(form_data) => {
                assert_eq!(form_data.fields.len(), 1);
                for (key, val) in form_data.fields {
                    if &key == "field1" {
                        assert_eq!(&val, "data1");
                    }
                }

                assert_eq!(form_data.files.len(), 2);
                for (key, file) in form_data.files {
                    if &key == "field2" {
                        assert_eq!(file.size, Some(30));
                        assert_eq!(&*file.filename().unwrap().unwrap(), "image.gif");
                        assert_eq!(file.content_type().unwrap(), mime!(Image/Gif));
                    } else if &key == "field3" {
                        assert_eq!(file.size, Some(14));
                        assert_eq!(&*file.filename().unwrap().unwrap(), "file.txt");
                        assert!(file.content_type().is_none());
                    }
                }
            },
            Err(err) => panic!("{}", err),
        }
    }

    #[test]
    fn multi_file_parser() {
        let input = b"POST / HTTP/1.1\r\n\
                      Host: example.domain\r\n\
                      Content-Type: multipart/form-data; boundary=\"abcdefg\"\r\n\
                      Content-Length: 1000\r\n\
                      \r\n\
                      --abcdefg\r\n\
                      Content-Disposition: form-data; name=\"field1\"\r\n\
                      \r\n\
                      data1\r\n\
                      --abcdefg\r\n\
                      Content-Disposition: form-data; name=\"field2\"; filename=\"image.gif\"\r\n\
                      Content-Type: image/gif\r\n\
                      \r\n\
                      This is a file\r\n\
                      with two lines\r\n\
                      --abcdefg\r\n\
                      Content-Disposition: form-data; name=\"field2\"; filename=\"file.txt\"\r\n\
                      \r\n\
                      This is a file\r\n\
                      --abcdefg--";

        let mut mock = MockStream::with_input(input);

        let mock: &mut NetworkStream = &mut mock;
        let mut stream = BufReader::new(mock);
        let sock: SocketAddr = "127.0.0.1:80".parse().unwrap();
        let req = HyperRequest::new(&mut stream, sock).unwrap();
        let (_, _, headers, _, _, mut reader) = req.deconstruct();

        match read_formdata(&mut reader, &headers) {
            Ok(form_data) => {
                assert_eq!(form_data.fields.len(), 1);
                for (key, val) in form_data.fields {
                    if &key == "field1" {
                        assert_eq!(&val, "data1");
                    }
                }

                assert_eq!(form_data.files.len(), 2);
                let (ref key, ref file) = form_data.files[0];

                assert_eq!(key, "field2");
                assert_eq!(file.size, Some(30));
                assert_eq!(&*file.filename().unwrap().unwrap(), "image.gif");
                assert_eq!(file.content_type().unwrap(), mime!(Image/Gif));

                let (ref key, ref file) = form_data.files[1];
                assert!(key == "field2");
                assert_eq!(file.size, Some(14));
                assert_eq!(&*file.filename().unwrap().unwrap(), "file.txt");
                assert!(file.content_type().is_none());

            },
            Err(err) => panic!("{}", err),
        }
    }

    #[test]
    fn mixed_parser() {
        let input = b"POST / HTTP/1.1\r\n\
                      Host: example.domain\r\n\
                      Content-Type: multipart/form-data; boundary=AaB03x\r\n\
                      Content-Length: 1000\r\n\
                      \r\n\
                      --AaB03x\r\n\
                      Content-Disposition: form-data; name=\"submit-name\"\r\n\
                      \r\n\
                      Larry\r\n\
                      --AaB03x\r\n\
                      Content-Disposition: form-data; name=\"files\"\r\n\
                      Content-Type: multipart/mixed; boundary=BbC04y\r\n\
                      \r\n\
                      --BbC04y\r\n\
                      Content-Disposition: file; filename=\"file1.txt\"\r\n\
                      \r\n\
                      ... contents of file1.txt ...\r\n\
                      --BbC04y\r\n\
                      Content-Disposition: file; filename=\"awesome_image.gif\"\r\n\
                      Content-Type: image/gif\r\n\
                      Content-Transfer-Encoding: binary\r\n\
                      \r\n\
                      ... contents of awesome_image.gif ...\r\n\
                      --BbC04y--\r\n\
                      --AaB03x--";

        let mut mock = MockStream::with_input(input);

        let mock: &mut NetworkStream = &mut mock;
        let mut stream = BufReader::new(mock);
        let sock: SocketAddr = "127.0.0.1:80".parse().unwrap();
        let req = HyperRequest::new(&mut stream, sock).unwrap();
        let (_, _, headers, _, _, mut reader) = req.deconstruct();

        match read_formdata(&mut reader, &headers) {
            Ok(form_data) => {
                assert_eq!(form_data.fields.len(), 1);
                for (key, val) in form_data.fields {
                    if &key == "submit-name" {
                        assert_eq!(&val, "Larry");
                    }
                }

                assert_eq!(form_data.files.len(), 2);
                for (key, file) in form_data.files {
                    assert_eq!(&key, "files");
                    match &file.filename().unwrap().unwrap()[..] {
                        "file1.txt" => {
                            assert_eq!(file.size, Some(29));
                            assert!(file.content_type().is_none());
                        }
                        "awesome_image.gif" => {
                            assert_eq!(file.size, Some(37));
                            assert_eq!(file.content_type().unwrap(), mime!(Image/Gif));
                        },
                        _ => unreachable!(),
                    }
                }
            },
            Err(err) => panic!("{}", err),
        }
    }
}
<commit_msg>Implement write_formdata()<commit_after>// Copyright © 2015 by Michael Dilger (of New Zealand)
// This code is licensed under the MIT license (see LICENSE-MIT for details)

//! This crate parses and processes a stream of data that contains
//! `multipart/form-data` content.
//!
//! The main entry point is `read_formdata`

#![cfg_attr(feature="clippy", feature(plugin))]
#![cfg_attr(feature="clippy", plugin(clippy))]

extern crate httparse;
extern crate hyper;
#[macro_use]
extern crate mime;
extern crate textnonce;
#[macro_use]
extern crate log;
extern crate encoding;

extern crate mime_multipart;

mod error;
mod form_data;
#[cfg(test)]
mod mock;

pub use error::Error;
pub use form_data::FormData;

use std::io::{Read, Write};
use hyper::header::{Headers, ContentDisposition, DispositionParam, ContentType,
                    DispositionType};
use mime_multipart::{Node, Part};
use mime::{Mime, TopLevel, SubLevel};

/// Parse MIME `multipart/form-data` information from a stream as a `FormData`.
pub fn read_formdata<S: Read>(stream: &mut S, headers: &Headers) -> Result<FormData, Error>
{
    let nodes = try!(mime_multipart::read_multipart_body(stream, headers, false));

    let mut formdata = FormData::new();
    try!(fill_formdata(&mut formdata, nodes));
    Ok(formdata)
}

// order and nesting are irrelevant, so we interate through the nodes and put them
// into one of two buckets (fields and files);  If a multipart node is found, it uses
// the name in its headers as the key (rather than the name in the headers of the
// subparts), which is how multiple file uploads work.
fn fill_formdata(formdata: &mut FormData, nodes: Vec<Node>) -> Result<(), Error>
{
    for node in nodes {
        match node {
            Node::Part(part) => {
                let cd_name: Option<String> = {
                    let cd: &ContentDisposition = match part.headers.get() {
                        Some(cd) => cd,
                        None => return Err(Error::MissingDisposition),
                    };
                    get_content_disposition_name(&cd)
                };
                let key = try!(cd_name.ok_or(Error::NoName));
                let val = try!(String::from_utf8(part.body));
                formdata.fields.push((key, val));
            },
            Node::File(part) => {
                let cd_name: Option<String> = {
                    let cd: &ContentDisposition = match part.headers.get() {
                        Some(cd) => cd,
                        None => return Err(Error::MissingDisposition),
                    };
                    get_content_disposition_name(&cd)
                };
                let key = try!(cd_name.ok_or(Error::NoName));
                formdata.files.push((key, part));
            }
            Node::Multipart((headers, nodes)) => {
                let cd_name: Option<String> = {
                    let cd: &ContentDisposition = match headers.get() {
                        Some(cd) => cd,
                        None => return Err(Error::MissingDisposition),
                    };
                    get_content_disposition_name(&cd)
                };
                let key = try!(cd_name.ok_or(Error::NoName));
                for node in nodes {
                    match node {
                        Node::Part(part) => {
                            let val = try!(String::from_utf8(part.body));
                            formdata.fields.push((key.clone(), val));
                        },
                        Node::File(part) => {
                            formdata.files.push((key.clone(), part));
                        },
                        _ => { } // don't recurse deeper
                    }
                }
            }
        }
    }
    Ok(())
}

#[inline]
fn get_content_disposition_name(cd: &ContentDisposition) -> Option<String> {
    if let Some(&DispositionParam::Ext(_, ref value)) = cd.parameters.iter()
        .find(|&x| match *x {
            DispositionParam::Ext(ref token,_) => &*token == "name",
            _ => false,
        })
    {
        Some(value.clone())
    } else {
        None
    }
}

/// Stream out `multipart/form-data` body content matching the passed in `formdata`.  This
/// does not stream out headers, so the caller must stream those out before calling
/// write_formdata().
///
/// Note: File field names to be set in the headers in the FilePart; the FormData.files vector
/// pair first elements are not used herein.

pub fn write_formdata<S: Write>(stream: &mut S, formdata: &FormData) -> Result<usize, Error>
{
    // Translate to Nodes
    let mut nodes: Vec<Node> = Vec::with_capacity(formdata.fields.len() + formdata.files.len());

    for &(ref name, ref value) in &formdata.fields {
        let mut h = Headers::new();
        h.set(ContentType(Mime(TopLevel::Text, SubLevel::Plain, vec![])));
        h.set(ContentDisposition {
            disposition: DispositionType::Ext("form-data".to_owned()),
            parameters: vec![DispositionParam::Ext("name".to_owned(), name.clone())],
        });
        nodes.push( Node::Part( Part {
            headers: h,
            body: value.as_bytes().to_owned(),
        }));
    }

    for &(ref _name, ref filepart) in &formdata.files {
        // FIXME: maybe ensure the content-disposition formdata 'name' equals `_name`
        nodes.push( Node::File( filepart.clone() ) );
    }

    let boundary = ::mime_multipart::generate_boundary();

    // Write out
    let count = try!(::mime_multipart::write_multipart(stream, &boundary, &nodes));

    Ok(count)
}

#[cfg(test)]
mod tests {
    extern crate tempdir;

    use super::*;

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

    use hyper::buffer::BufReader;
    use hyper::net::NetworkStream;
    use hyper::server::Request as HyperRequest;
    use hyper::header::{Headers, ContentDisposition, DispositionParam, ContentType,
                        DispositionType};
    use mime_multipart::FilePart;
    use mime::{Mime, TopLevel, SubLevel};

    use mock::MockStream;

    #[test]
    fn parser() {
        let input = b"POST / HTTP/1.1\r\n\
                      Host: example.domain\r\n\
                      Content-Type: multipart/form-data; boundary=\"abcdefg\"\r\n\
                      Content-Length: 1000\r\n\
                      \r\n\
                      --abcdefg\r\n\
                      Content-Disposition: form-data; name=\"field1\"\r\n\
                      \r\n\
                      data1\r\n\
                      --abcdefg\r\n\
                      Content-Disposition: form-data; name=\"field2\"; filename=\"image.gif\"\r\n\
                      Content-Type: image/gif\r\n\
                      \r\n\
                      This is a file\r\n\
                      with two lines\r\n\
                      --abcdefg\r\n\
                      Content-Disposition: form-data; name=\"field3\"; filename=\"file.txt\"\r\n\
                      \r\n\
                      This is a file\r\n\
                      --abcdefg--";

        let mut mock = MockStream::with_input(input);

        let mock: &mut NetworkStream = &mut mock;
        let mut stream = BufReader::new(mock);
        let sock: SocketAddr = "127.0.0.1:80".parse().unwrap();
        let req = HyperRequest::new(&mut stream, sock).unwrap();
        let (_, _, headers, _, _, mut reader) = req.deconstruct();

        match read_formdata(&mut reader, &headers) {
            Ok(form_data) => {
                assert_eq!(form_data.fields.len(), 1);
                for (key, val) in form_data.fields {
                    if &key == "field1" {
                        assert_eq!(&val, "data1");
                    }
                }

                assert_eq!(form_data.files.len(), 2);
                for (key, file) in form_data.files {
                    if &key == "field2" {
                        assert_eq!(file.size, Some(30));
                        assert_eq!(&*file.filename().unwrap().unwrap(), "image.gif");
                        assert_eq!(file.content_type().unwrap(), mime!(Image/Gif));
                    } else if &key == "field3" {
                        assert_eq!(file.size, Some(14));
                        assert_eq!(&*file.filename().unwrap().unwrap(), "file.txt");
                        assert!(file.content_type().is_none());
                    }
                }
            },
            Err(err) => panic!("{}", err),
        }
    }

    #[test]
    fn multi_file_parser() {
        let input = b"POST / HTTP/1.1\r\n\
                      Host: example.domain\r\n\
                      Content-Type: multipart/form-data; boundary=\"abcdefg\"\r\n\
                      Content-Length: 1000\r\n\
                      \r\n\
                      --abcdefg\r\n\
                      Content-Disposition: form-data; name=\"field1\"\r\n\
                      \r\n\
                      data1\r\n\
                      --abcdefg\r\n\
                      Content-Disposition: form-data; name=\"field2\"; filename=\"image.gif\"\r\n\
                      Content-Type: image/gif\r\n\
                      \r\n\
                      This is a file\r\n\
                      with two lines\r\n\
                      --abcdefg\r\n\
                      Content-Disposition: form-data; name=\"field2\"; filename=\"file.txt\"\r\n\
                      \r\n\
                      This is a file\r\n\
                      --abcdefg--";

        let mut mock = MockStream::with_input(input);

        let mock: &mut NetworkStream = &mut mock;
        let mut stream = BufReader::new(mock);
        let sock: SocketAddr = "127.0.0.1:80".parse().unwrap();
        let req = HyperRequest::new(&mut stream, sock).unwrap();
        let (_, _, headers, _, _, mut reader) = req.deconstruct();

        match read_formdata(&mut reader, &headers) {
            Ok(form_data) => {
                assert_eq!(form_data.fields.len(), 1);
                for (key, val) in form_data.fields {
                    if &key == "field1" {
                        assert_eq!(&val, "data1");
                    }
                }

                assert_eq!(form_data.files.len(), 2);
                let (ref key, ref file) = form_data.files[0];

                assert_eq!(key, "field2");
                assert_eq!(file.size, Some(30));
                assert_eq!(&*file.filename().unwrap().unwrap(), "image.gif");
                assert_eq!(file.content_type().unwrap(), mime!(Image/Gif));

                let (ref key, ref file) = form_data.files[1];
                assert!(key == "field2");
                assert_eq!(file.size, Some(14));
                assert_eq!(&*file.filename().unwrap().unwrap(), "file.txt");
                assert!(file.content_type().is_none());

            },
            Err(err) => panic!("{}", err),
        }
    }

    #[test]
    fn mixed_parser() {
        let input = b"POST / HTTP/1.1\r\n\
                      Host: example.domain\r\n\
                      Content-Type: multipart/form-data; boundary=AaB03x\r\n\
                      Content-Length: 1000\r\n\
                      \r\n\
                      --AaB03x\r\n\
                      Content-Disposition: form-data; name=\"submit-name\"\r\n\
                      \r\n\
                      Larry\r\n\
                      --AaB03x\r\n\
                      Content-Disposition: form-data; name=\"files\"\r\n\
                      Content-Type: multipart/mixed; boundary=BbC04y\r\n\
                      \r\n\
                      --BbC04y\r\n\
                      Content-Disposition: file; filename=\"file1.txt\"\r\n\
                      \r\n\
                      ... contents of file1.txt ...\r\n\
                      --BbC04y\r\n\
                      Content-Disposition: file; filename=\"awesome_image.gif\"\r\n\
                      Content-Type: image/gif\r\n\
                      Content-Transfer-Encoding: binary\r\n\
                      \r\n\
                      ... contents of awesome_image.gif ...\r\n\
                      --BbC04y--\r\n\
                      --AaB03x--";

        let mut mock = MockStream::with_input(input);

        let mock: &mut NetworkStream = &mut mock;
        let mut stream = BufReader::new(mock);
        let sock: SocketAddr = "127.0.0.1:80".parse().unwrap();
        let req = HyperRequest::new(&mut stream, sock).unwrap();
        let (_, _, headers, _, _, mut reader) = req.deconstruct();

        match read_formdata(&mut reader, &headers) {
            Ok(form_data) => {
                assert_eq!(form_data.fields.len(), 1);
                for (key, val) in form_data.fields {
                    if &key == "submit-name" {
                        assert_eq!(&val, "Larry");
                    }
                }

                assert_eq!(form_data.files.len(), 2);
                for (key, file) in form_data.files {
                    assert_eq!(&key, "files");
                    match &file.filename().unwrap().unwrap()[..] {
                        "file1.txt" => {
                            assert_eq!(file.size, Some(29));
                            assert!(file.content_type().is_none());
                        }
                        "awesome_image.gif" => {
                            assert_eq!(file.size, Some(37));
                            assert_eq!(file.content_type().unwrap(), mime!(Image/Gif));
                        },
                        _ => unreachable!(),
                    }
                }
            },
            Err(err) => panic!("{}", err),
        }
    }

    #[test]
    fn simple_writer() {
        // Create a simple short file for testing
        let tmpdir = tempdir::TempDir::new("formdata_test").unwrap();
        let tmppath = tmpdir.path().join("testfile");
        let mut tmpfile = File::create(tmppath.clone()).unwrap();
        writeln!(tmpfile, "this is example file content").unwrap();

        let mut photo_headers = Headers::new();
        photo_headers.set(ContentType(Mime(TopLevel::Image, SubLevel::Gif, vec![])));
        photo_headers.set(ContentDisposition {
            disposition: DispositionType::Ext("form-data".to_owned()),
            parameters: vec![DispositionParam::Ext("name".to_owned(), "photo".to_owned()),
                             DispositionParam::Ext("filename".to_owned(), "mike.gif".to_owned())],
        });

        let formdata = FormData {
            fields: vec![ ("name".to_owned(), "Mike".to_owned()),
                            ("age".to_owned(), "46".to_owned()) ],
            files: vec![ ("photo".to_owned(), FilePart::new(photo_headers, &tmppath)) ],
        };

        let mut output: Vec<u8> = Vec::new();
        match write_formdata(&mut output, &formdata) {
            Ok(count) => assert_eq!(count, 568),
            Err(e) => panic!("Unable to write formdata: {}", e),
        }

        println!("{}", String::from_utf8_lossy(&output));
    }
}
<|endoftext|>