<commit_before>#[macro_export]
macro_rules! delegate_method {
    {impl $($tt:tt)*} =>
    {delegate_method!{@impl_collect () $($tt)*}};

    {@impl_collect ($($headtt:tt)*) {$($tailtt:tt)*}} =>
    {delegate_method!{@impl_expansion ($($headtt)*) ($($tailtt)*) ()}};

    {@impl_collect ($($headtt:tt)*) $tt:tt $($tailtt:tt)*} =>
    {delegate_method!{@impl_collect ($($headtt)* $tt) $($tailtt)*}};

    {@impl_expansion_impl ($($headtt:tt)*) ($($itemtt:tt)*) ($($resttt:tt)*) ($($tailtt:tt)*)} =>
    {delegate_method!{@impl_expansion ($($headtt)*) ($($resttt)*) ($($tailtt)* $($itemtt)*)}};

    (@impl_finalization ($($headtt:tt)*) ($($tailtt:tt)*)) =>
    {delegate_method!(@as_item #[allow(dead_code)]impl $($headtt)* { $($tailtt)* });};

    (@as_item $i:item) => { $i };

    {@impl_expansion ($($headtt:tt)*) () ($($tailtt:tt)*)} =>
    {delegate_method!(@impl_finalization ($($headtt)*) ($($tailtt)*));};

    {@impl_expansion ($($headtt:tt)*)
     ($fld:tt $(as $fldty:ty)* : ) ($($tailtt:tt)*)} =>
    {delegate_method!(@impl_expansion ($($headtt)*) () ($($tailtt)*));};

    {@impl_expansion ($($headtt:tt)*)
     ($fld_last:tt $(as $fldty_last:ty)* :
      $fld:tt $(as $fldty:ty)* : $($resttt:tt)*) ($($tailtt:tt)*)} =>
    {delegate_method!(@impl_expansion ($($headtt)*)
                      ($fld $(as $fldty)* : $($resttt)*) ($($tailtt)*));};

    {@impl_expansion ($($headtt:tt)*)
     ($fld:tt : $($resttt:tt)*) ($($tailtt:tt)*)} =>
    {delegate_method!(@impl_expansion ($($headtt)*) ($fld as () : $($resttt)*) ($($tailtt)*))};

    {@impl_expansion ($($headtt:tt)*)
     ($fld:tt as $fldty:ty :
      pub fn $fcn:ident $(< $($lt:tt),* >)* ($($args:tt)*) $(-> $r:ty)* ; $($resttt:tt)* )
     ($($tailtt:tt)*)} =>
    {delegate_method!(@impl_expansion_item ($($headtt)*)
                      ($fld) ($fldty) ($fcn) (pub fn) ($($($lt),*),*) ($($args)*) ($(-> $r)*)
                      ($fld as $fldty : $($resttt)*) ($($tailtt)*));};

    {@impl_expansion ($($headtt:tt)*)
     ($fld:tt as $fldty:ty :
      fn $fcn:ident $(< $($lt:tt),* >)* ($($args:tt)*) $(-> $r:ty)* ; $($resttt:tt)* )
     ($($tailtt:tt)*)} =>
    {delegate_method!(@impl_expansion_item ($($headtt)*)
                      ($fld) ($fldty) ($fcn) (fn) ($($($lt),*),*) ($($args)*) ($(-> $r)*)
                      ($fld as $fldty : $($resttt)*) ($($tailtt)*));};

    (@impl_expansion_item ($($headtt:tt)*)
     ($fld:tt) ($fldty:ty) ($fcn:ident) ($($kwtt:tt)*) ($($gp:tt)+) ($($args:tt)*) ($($r:tt)*)
     ($($resttt:tt)*) ($($tailtt:tt)*)) =>
    {delegate_method!(@impl_expansion_gp ($($headtt)*)
                      ($fld) ($fldty) ($fcn) ($($kwtt)*) (<$($gp)*>) ($($args)*) ($($r)*)
                      ($($resttt)*) ($($tailtt)*));};

    (@impl_expansion_item ($($headtt:tt)*)
     ($fld:tt) ($fldty:ty) ($fcn:ident) ($($kwtt:tt)*) () ($($args:tt)*) ($($r:tt)*)
     ($($resttt:tt)*) ($($tailtt:tt)*)) =>
    {delegate_method!(@impl_expansion_gp ($($headtt)*)
                      ($fld) ($fldty) ($fcn) ($($kwtt)*) () ($($args)*) ($($r)*)
                      ($($resttt)*) ($($tailtt)*));};

    (@impl_expansion_gp ($($headtt:tt)*)
     ($fld:tt) ($fldty:ty) ($fcn:ident) ($($kwtt:tt)*) ($($gp:tt)*) (self) ($($r:tt)*)
     ($($resttt:tt)*) ($($tailtt:tt)*)) =>
    {delegate_method!(@impl_expansion_impl ($($headtt)*)
                      ($($kwtt)* $fcn $($gp)* (self) $($r)* { (self.$fld).$fcn() })
                      ($($resttt)*) ($($tailtt)*));};

    (@impl_expansion_gp ($($headtt:tt)*)
     ($fld:tt) ($fldty:ty) ($fcn:ident) ($($kwtt:tt)*) ($($gp:tt)*) (&self) ($($r:tt)*)
     ($($resttt:tt)*) ($($tailtt:tt)*)) =>
    {delegate_method!(@impl_expansion_impl ($($headtt)*)
                      ($($kwtt)* $fcn $($gp)* (&self) $($r)* { (self.$fld).$fcn() })
      ($($resttt)*) ($($tailtt)*));};

    (@impl_expansion_gp ($($headtt:tt)*)
    ($fld:tt) ($fldty:ty) ($fcn:ident) ($($kwtt:tt)*) ($($gp:tt)*) (&mut self) ($($r:tt)*)
    ($($resttt:tt)*) ($($tailtt:tt)*)) =>
    {delegate_method!(@impl_expansion_impl ($($headtt)*)
      ($($kwtt)* $fcn $($gp)* (&mut self) $($r)* { (self.$fld).$fcn() })
      ($($resttt)*) ($($tailtt)*));};

    (@impl_expansion_gp ($($headtt:tt)*)
   ($fld:tt) ($fldty:ty) ($fcn:ident) ($($kwtt:tt)*) ($($gp:tt)*)
   (self, $( $a:ident : $at:ty ),*) ($($r:tt)*)
    ($($resttt:tt)*) ($($tailtt:tt)*)) =>
    {delegate_method!(@impl_expansion_impl ($($headtt)*)
      ($($kwtt)* $fcn $($gp)* (self,$($a : $at)*) $($r)* { (self.$fld).$fcn($($a),*) })
      ($($resttt)*) ($($tailtt)*));};

    (@impl_expansion_gp ($($headtt:tt)*)
   ($fld:tt) ($fldty:ty) ($fcn:ident) ($($kwtt:tt)*) ($($gp:tt)*)
   (&self, $( $a:ident : $at:ty ),*) ($($r:tt)*)
    ($($resttt:tt)*) ($($tailtt:tt)*)) =>
    {delegate_method!(@impl_expansion_impl ($($headtt)*)
      ($($kwtt)* $fcn $($gp)* (&self,$($a : $at)*) $($r)* { (self.$fld).$fcn($($a),*) })
      ($($resttt)*) ($($tailtt)*));};

    (@impl_expansion_gp ($($headtt:tt)*)
   ($fld:tt) ($fldty:ty) ($fcn:ident) ($($kwtt:tt)*) ($($gp:tt)*)
   (&mut self, $( $a:ident : $at:ty ),*) ($($r:tt)*)
    ($($resttt:tt)*) ($($tailtt:tt)*)) =>
    {delegate_method!(@impl_expansion_impl ($($headtt)*)
      ($($kwtt)* $fcn $($gp)* (&mut self,$($a : $at)*) $($r)* { (self.$fld).$fcn($($a),*) })
      ($($resttt)*) ($($tailtt)*));};

    (@impl_expansion_gp ($($headtt:tt)*)
   ($fld:tt) ($fldty:ty) ($fcn:ident) ($($kwtt:tt)*) ($($gp:tt)*)
   ($( $a:ident : $at:ty ),*) ($($r:tt)*)
    ($($resttt:tt)*) ($($tailtt:tt)*)) =>
    {delegate_method!(@ impl_expansion_impl ($($headtt)*)
      ($($kwtt)* $fcn $($gp)* ($($a : $at)*) $($r)* { <$fldty>::$fcn($($a),*) })
      ($($resttt)*) ($($tailtt)*));};
}

#[cfg(test)]
mod tests {
    #[derive(Copy, Clone)]
    struct Inner {
        data: usize,
    }

    impl Inner {
        pub fn new_inner() -> Self {
            Inner { data: 42 }
        }

        pub fn new_inner_add(val: usize) -> Self {
            Inner { data: 42 + val }
        }

        pub fn noop(&self) {}

        pub fn str_to_owned<'a>(str: &'a str) -> String {
            str.to_owned()
        }

        pub fn get(&self) -> usize {
            self.data
        }

        pub fn get_add(&self, val: usize) -> usize {
            self.data + val
        }

        pub fn reset(&mut self) -> usize {
            self.data = 0;
            self.data
        }

        pub fn set(&mut self, val: usize) -> usize {
            self.data = val;
            self.data
        }

        pub fn to_data(self) -> usize {
            self.data
        }

        pub fn to_data_add(self, val: usize) -> usize {
            self.data + val
        }
    }

    #[test]
    fn test_delegate() {
        #[derive(Copy, Clone)]
        struct Outer {
            inner: Inner,
        }

        delegate_method! {
			      impl Outer {
                inner as Inner:
                fn new_inner() -> Inner;
                fn new_inner_add(val: usize) -> Inner;
                fn noop(&self);
				        fn str_to_owned<'a>(str: &'a str) -> String;
                fn get(&self) -> usize;
                fn get_add(&self, val: usize) -> usize;
                fn reset(&mut self) -> usize;
                fn set(&mut self, val: usize) -> usize;
                inner as Inner:
                fn to_data(self) -> usize;
                fn to_data_add(self, val: usize) -> usize;
            }
        }

        assert_eq!(Outer::new_inner().get(), 42);
        assert_eq!(Outer::new_inner_add(58).get(), 100);

        assert_eq!(Outer::str_to_owned("Hello"), "Hello".to_owned());

        let mut x = Outer { inner: Inner::new_inner() };

        assert_eq!(x.get(), 42);
        assert_eq!(x.get_add(58), 100);
        x.noop();

        x.reset();
        assert_eq!(x.get(), 0);

        x.set(36);
        assert_eq!(x.get(), 36);

        assert_eq!(x.clone().to_data(), 36);
        assert_eq!(x.clone().to_data_add(4), 40);
    }
}
<commit_msg>Add support for associated types and #[inline] for function definitions<commit_after>#[macro_export]
macro_rules! delegate_method {
    {impl $($tt:tt)*} =>
    {delegate_method!{@impl_collect () $($tt)*}};

    {@impl_collect ($($headtt:tt)*) {$($tailtt:tt)*}} =>
    {delegate_method!{@impl_expansion ($($headtt)*) ($($tailtt)*) ()}};

    {@impl_collect ($($headtt:tt)*) $tt:tt $($tailtt:tt)*} =>
    {delegate_method!{@impl_collect ($($headtt)* $tt) $($tailtt)*}};

    {@impl_expansion_impl ($($headtt:tt)*) ($($itemtt:tt)*) ($($resttt:tt)*) ($($tailtt:tt)*)} =>
    {delegate_method!{@impl_expansion ($($headtt)*) ($($resttt)*) ($($tailtt)* #[inline] $($itemtt)*)}};

    (@impl_finalization ($($headtt:tt)*) ($($tailtt:tt)*)) =>
    {delegate_method!(@as_item #[allow(dead_code)]impl $($headtt)* { $($tailtt)* });};

    (@as_item $i:item) => { $i };

    {@impl_expansion ($($headtt:tt)*) () ($($tailtt:tt)*)} =>
    {delegate_method!(@impl_finalization ($($headtt)*) ($($tailtt)*));};

    {@impl_expansion ($($headtt:tt)*)
     (type $ascty:ty = $dstty:ty; $($resttt:tt)*) ($($tailtt:tt)*)} =>
    {delegate_method!(@impl_expansion ($($headtt)*) ($($resttt)*) ($($tailtt)* type $ascty = $dstty; ))};

    {@impl_expansion ($($headtt:tt)*)
     ($fld:tt $(as $fldty:ty)* : ) ($($tailtt:tt)*)} =>
    {delegate_method!(@impl_expansion ($($headtt)*) () ($($tailtt)*));};

    {@impl_expansion ($($headtt:tt)*)
     ($fld_last:tt $(as $fldty_last:ty)* :
      $fld:tt $(as $fldty:ty)* : $($resttt:tt)*) ($($tailtt:tt)*)} =>
    {delegate_method!(@impl_expansion ($($headtt)*)
                      ($fld $(as $fldty)* : $($resttt)*) ($($tailtt)*));};

    {@impl_expansion ($($headtt:tt)*)
     ($fld:tt : $($resttt:tt)*) ($($tailtt:tt)*)} =>
    {delegate_method!(@impl_expansion ($($headtt)*) ($fld as () : $($resttt)*) ($($tailtt)*))};

    {@impl_expansion ($($headtt:tt)*)
     ($fld:tt as $fldty:ty :
      pub fn $fcn:ident $(< $($lt:tt),* >)* ($($args:tt)*) $(-> $r:ty)* ; $($resttt:tt)* )
     ($($tailtt:tt)*)} =>
    {delegate_method!(@impl_expansion_item ($($headtt)*)
                      ($fld) ($fldty) ($fcn) (pub fn) ($($($lt),*),*) ($($args)*) ($(-> $r)*)
                      ($fld as $fldty : $($resttt)*) ($($tailtt)*));};

    {@impl_expansion ($($headtt:tt)*)
     ($fld:tt as $fldty:ty :
      fn $fcn:ident $(< $($lt:tt),* >)* ($($args:tt)*) $(-> $r:ty)* ; $($resttt:tt)* )
     ($($tailtt:tt)*)} =>
    {delegate_method!(@impl_expansion_item ($($headtt)*)
                      ($fld) ($fldty) ($fcn) (fn) ($($($lt),*),*) ($($args)*) ($(-> $r)*)
                      ($fld as $fldty : $($resttt)*) ($($tailtt)*));};

    (@impl_expansion_item ($($headtt:tt)*)
     ($fld:tt) ($fldty:ty) ($fcn:ident) ($($kwtt:tt)*) ($($gp:tt)+) ($($args:tt)*) ($($r:tt)*)
     ($($resttt:tt)*) ($($tailtt:tt)*)) =>
    {delegate_method!(@impl_expansion_gp ($($headtt)*)
                      ($fld) ($fldty) ($fcn) ($($kwtt)*) (<$($gp)*>) ($($args)*) ($($r)*)
                      ($($resttt)*) ($($tailtt)*));};

    (@impl_expansion_item ($($headtt:tt)*)
     ($fld:tt) ($fldty:ty) ($fcn:ident) ($($kwtt:tt)*) () ($($args:tt)*) ($($r:tt)*)
     ($($resttt:tt)*) ($($tailtt:tt)*)) =>
    {delegate_method!(@impl_expansion_gp ($($headtt)*)
                      ($fld) ($fldty) ($fcn) ($($kwtt)*) () ($($args)*) ($($r)*)
                      ($($resttt)*) ($($tailtt)*));};

    (@impl_expansion_gp ($($headtt:tt)*)
     ($fld:tt) ($fldty:ty) ($fcn:ident) ($($kwtt:tt)*) ($($gp:tt)*) (self) ($($r:tt)*)
     ($($resttt:tt)*) ($($tailtt:tt)*)) =>
    {delegate_method!(@impl_expansion_impl ($($headtt)*)
                      ($($kwtt)* $fcn $($gp)* (self) $($r)* { (self.$fld).$fcn() })
                      ($($resttt)*) ($($tailtt)*));};

    (@impl_expansion_gp ($($headtt:tt)*)
     ($fld:tt) ($fldty:ty) ($fcn:ident) ($($kwtt:tt)*) ($($gp:tt)*) (&self) ($($r:tt)*)
     ($($resttt:tt)*) ($($tailtt:tt)*)) =>
    {delegate_method!(@impl_expansion_impl ($($headtt)*)
                      ($($kwtt)* $fcn $($gp)* (&self) $($r)* { (self.$fld).$fcn() })
      ($($resttt)*) ($($tailtt)*));};

    (@impl_expansion_gp ($($headtt:tt)*)
    ($fld:tt) ($fldty:ty) ($fcn:ident) ($($kwtt:tt)*) ($($gp:tt)*) (&mut self) ($($r:tt)*)
    ($($resttt:tt)*) ($($tailtt:tt)*)) =>
    {delegate_method!(@impl_expansion_impl ($($headtt)*)
      ($($kwtt)* $fcn $($gp)* (&mut self) $($r)* { (self.$fld).$fcn() })
      ($($resttt)*) ($($tailtt)*));};

    (@impl_expansion_gp ($($headtt:tt)*)
   ($fld:tt) ($fldty:ty) ($fcn:ident) ($($kwtt:tt)*) ($($gp:tt)*)
   (self, $( $a:ident : $at:ty ),*) ($($r:tt)*)
    ($($resttt:tt)*) ($($tailtt:tt)*)) =>
    {delegate_method!(@impl_expansion_impl ($($headtt)*)
      ($($kwtt)* $fcn $($gp)* (self,$($a : $at)*) $($r)* { (self.$fld).$fcn($($a),*) })
      ($($resttt)*) ($($tailtt)*));};

    (@impl_expansion_gp ($($headtt:tt)*)
   ($fld:tt) ($fldty:ty) ($fcn:ident) ($($kwtt:tt)*) ($($gp:tt)*)
   (&self, $( $a:ident : $at:ty ),*) ($($r:tt)*)
    ($($resttt:tt)*) ($($tailtt:tt)*)) =>
    {delegate_method!(@impl_expansion_impl ($($headtt)*)
      ($($kwtt)* $fcn $($gp)* (&self,$($a : $at)*) $($r)* { (self.$fld).$fcn($($a),*) })
      ($($resttt)*) ($($tailtt)*));};

    (@impl_expansion_gp ($($headtt:tt)*)
   ($fld:tt) ($fldty:ty) ($fcn:ident) ($($kwtt:tt)*) ($($gp:tt)*)
   (&mut self, $( $a:ident : $at:ty ),*) ($($r:tt)*)
    ($($resttt:tt)*) ($($tailtt:tt)*)) =>
    {delegate_method!(@impl_expansion_impl ($($headtt)*)
      ($($kwtt)* $fcn $($gp)* (&mut self,$($a : $at)*) $($r)* { (self.$fld).$fcn($($a),*) })
      ($($resttt)*) ($($tailtt)*));};

    (@impl_expansion_gp ($($headtt:tt)*)
   ($fld:tt) ($fldty:ty) ($fcn:ident) ($($kwtt:tt)*) ($($gp:tt)*)
   ($( $a:ident : $at:ty ),*) ($($r:tt)*)
    ($($resttt:tt)*) ($($tailtt:tt)*)) =>
    {delegate_method!(@ impl_expansion_impl ($($headtt)*)
      ($($kwtt)* $fcn $($gp)* ($($a : $at)*) $($r)* { <$fldty>::$fcn($($a),*) })
      ($($resttt)*) ($($tailtt)*));};
}

#[cfg(test)]
mod tests {
    #[derive(Copy, Clone)]
    struct Inner {
        data: usize,
    }

    impl Inner {
        pub fn new_inner() -> Self {
            Inner { data: 42 }
        }

        pub fn new_inner_add(val: usize) -> Self {
            Inner { data: 42 + val }
        }

        pub fn noop(&self) {}

        pub fn str_to_owned<'a>(str: &'a str) -> String {
            str.to_owned()
        }

        pub fn get(&self) -> usize {
            self.data
        }

        pub fn get_add(&self, val: usize) -> usize {
            self.data + val
        }

        pub fn reset(&mut self) -> usize {
            self.data = 0;
            self.data
        }

        pub fn set(&mut self, val: usize) -> usize {
            self.data = val;
            self.data
        }

        pub fn to_data(self) -> usize {
            self.data
        }

        pub fn to_data_add(self, val: usize) -> usize {
            self.data + val
        }
    }

    #[test]
    fn test_delegate() {
        #[derive(Copy, Clone)]
        struct Outer {
            inner: Inner,
        }

        delegate_method! {
			      impl Outer {
                inner as Inner:
                fn new_inner() -> Inner;
                fn new_inner_add(val: usize) -> Inner;
                fn noop(&self);
				        fn str_to_owned<'a>(str: &'a str) -> String;
                fn get(&self) -> usize;
                fn get_add(&self, val: usize) -> usize;
                fn reset(&mut self) -> usize;
                fn set(&mut self, val: usize) -> usize;
                inner as Inner:
                fn to_data(self) -> usize;
                fn to_data_add(self, val: usize) -> usize;
            }
        }

        assert_eq!(Outer::new_inner().get(), 42);
        assert_eq!(Outer::new_inner_add(58).get(), 100);

        assert_eq!(Outer::str_to_owned("Hello"), "Hello".to_owned());

        let mut x = Outer { inner: Inner::new_inner() };

        assert_eq!(x.get(), 42);
        assert_eq!(x.get_add(58), 100);
        x.noop();

        x.reset();
        assert_eq!(x.get(), 0);

        x.set(36);
        assert_eq!(x.get(), 36);

        assert_eq!(x.clone().to_data(), 36);
        assert_eq!(x.clone().to_data_add(4), 40);
    }
}
<|endoftext|>


<commit_before>#![deny(missing_docs)]
#![doc(html_root_url = "https://dabo.guru/rust/throw/throw/")]
//! Throw!
//! ------
//!
//! Throw is a new experimental rust error handling library, meant to assist and build on existing
//! error handling systems.
//!
//! Throw exports two structs, `throw::ErrorPoint` and `throw::Error`. `throw::Error` stores a
//! single `original_error` variable which it is created from, and then a list of `ErrorPoint`s
//! which starts out with the original point of creation with `throw!()`, and is added to every
//! time you propagate the error upwards with `up!()`.
//!
//! *Throw does not replace existing error handling systems*. The `throw::Error` type has a type
//! parameter `E` which represents an internal error type stored. `throw::Error` just wraps your
//! error type and stores ErrorPoints alongside it.
//!
//! Throw helps you better keep track of your errors. Instead of seeing a generic "No such file or
//! directory" message, you get a stack trace of functions which propagated the error as well.
//!
//! Instead of:
//!
//! ```text
//! IO Error: failed to lookup address information: Name or service not known
//! ```
//!
//! Get:
//!
//! ```text
//! Error: IO Error: failed to lookup address information: Name or service not known
//!     at 79:17 in zaldinar::startup (src/startup.rs)
//!     at 104:4 in zaldinar::startup (src/startup.rs)
//!     at 28:17 in zaldinar_irclib (/home/daboross/Projects/Rust/zaldinar/zaldinar-irclib/src/lib.rs)
//! ```
//!
//! ---
//!
//! Using throw!
//! ---
//!
//! The main way you use throw is through two macros, `throw!()` and `up!()`. `throw!()` is used
//! when you have a regular (non-throw) result coming from some library function that you want to
//! propagate upwards in case of an error. `up!()` is used when you have an error which was
//! created using `throw!()` in a sub-function which you want to add an error point to and
//! propagate upwards.
//!
//! Here's an example of throw in action:
//!
//! ```rust
//! #[macro_use]
//! extern crate throw;
//!
//! use std::io::prelude::*;
//! use std::io;
//! use std::fs::File;
//!
//! fn read_log() -> Result<String, throw::Error<io::Error>> {
//!     let mut file = throw!(File::open("some_file.log"));
//!     let mut buf = String::new();
//!     throw!(file.read_to_string(&mut buf));
//!     Ok((buf))
//! }
//!
//! fn do_things() -> Result<(), throw::Error<io::Error>> {
//!     let log_contents = up!(read_log());
//!     println!("Log contents: {}", log_contents);
//!
//!     Ok(())
//! }
//!
//! fn main() {
//!     let result = do_things();
//!     if let Err(e) = result {
//! #       /*
//!         panic!("{}", e);
//! #       */
//! #       assert_eq!(format!("{}", e), "Error: No such file or directory (os error 2)\
//! #       \n\tat 16:23 in rust_out (<anon>)\
//! #       \n\tat 9:19 in rust_out (<anon>)");
//!     }
//! }
//! ```
//!
//! This simple program behaves exactly as if `Result<_, io::Error>` directly when it functions
//! correctly. When the program encounters is when throw really shines.  This will result in an
//! error message:
//!
//! ```text
//! Error: No such file or directory (os error 2)
//!    at 16:23 in main (src/main.rs)
//!    at 9:19 in main (src/main.rs)
//! ```
//!
//! These stack traces are stored inside throw::Error, and are recorded automatically when
//! `throw!()` or `up!()` returns an Err value.
//!
//! In each `at` line, the `16:23` represents `line_num:column_num`, the `main` represents the
//! module path (for example `my_program::sub_module`), and `src/main.rs` represents the path of
//! the file in which `throw!()` was used in.
//!
//! ---
//!
//! Throwing directly from a function is also supported, using `throw_new!()`:
//!
//! ```
//! # #[macro_use]
//! # extern crate throw;
//! fn possibly_fails() -> Result<(), throw::Error<&'static str>> {
//!     if true {
//!         // throw_new!() will always return directly
//!         throw_new!("oops");
//!     }
//!
//!     Ok(())
//! }
//!
//! fn main() {
//! #   /*
//!     possibly_fails().unwrap()
//! #   */
//! #   assert_eq!(format!("{}", possibly_fails().unwrap_err()), "Error: oops\
//! #   \n\tat 6:8 in rust_out (<anon>)")
//! }
//! ```
//!
//! ```text
//! called `Result::unwrap()` on an `Err` value: Error: "oops"
//!    at 6:8 in main (src/main.rs)
//! ```
//!
//! `throw_new!()` differs from `throw!()` in that it takes a parameter directly to pass to a
//! `throw::Error`, rather than a `Result<>` to match on. `throw_new!()` will always return
//! directly from the function.

use std::fmt;

/// Result alias for a result containing a throw::Error.
pub type Result<T, E> = std::result::Result<T, Error<E>>;

/// Represents a location at which an error was thrown via throw!()
pub struct ErrorPoint {
    line: u32,
    column: u32,
    module_path: &'static str,
    file: &'static str,
}

impl ErrorPoint {
    /// The line throw!() occurred at, retrieved by line!()
    #[inline]
    pub fn line(&self) -> u32 {
        self.line
    }

    /// The column throw!() occurred at, retrieved by column!()
    #[inline]
    pub fn column(&self) -> u32 {
        self.column
    }

    /// The module throw!() occurred in, retrieved by module_path!()
    #[inline]
    pub fn module_path(&self) -> &'static str {
        self.module_path
    }

    /// The file throw!() occurred in, retrieved by file!()
    #[inline]
    pub fn file(&self) -> &'static str {
        self.file
    }

    #[doc(hidden)]
    pub fn __construct(line: u32, column: u32, module_path: &'static str, file: &'static str)
            -> ErrorPoint {
        ErrorPoint {
            line: line,
            column: column,
            module_path: module_path,
            file: file,
        }
    }
}

/// Represents an error. Stores an original error of type E, and any number of ErrorPoints at
/// which the error was propagated.
pub struct Error<E> {
    points: Vec<ErrorPoint>,
    original_error: E,
}

impl<E> Error<E> {
    /// Creates a new Error with no ErrorPoints
    pub fn new(error: E) -> Error<E> {
        Error {
            points: Vec::new(),
            original_error: error,
        }
    }

    /// For macro use only
    #[doc(hidden)]
    pub fn __push_point(&mut self, point: ErrorPoint) {
        self.points.push(point);
    }

    /// Gets all ErrorPoints where this Error was thrown. These are in reverse order, with the
    /// first time it was thrown first and the latest time it was thrown last.
    #[inline]
    pub fn points(&self) -> &[ErrorPoint] {
        &self.points
    }

    /// Gets the original error which this Error was constructed with.
    #[inline]
    pub fn original_error(&self) -> &E {
        &self.original_error
    }

    /// Transforms this Error<OldError> into Error<NewError>. This isn't implemented as an Into or
    /// From implementation because it would conflict with the blanket implementations in stdlib.
    pub fn transform<NE>(self) -> Error<NE> where E: Into<NE> {
        Error {
            points: self.points,
            original_error: self.original_error.into(),
        }
    }
}

impl<E> fmt::Display for Error<E> where E: fmt::Display {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> std::result::Result<(), fmt::Error> {
        try!(write!(fmt, "Error: {}", self.original_error));
        for point in self.points.iter().rev() {
            try!(write!(fmt, "\n\tat {}:{} in {} ({})", point.line(), point.column(),
                point.module_path(), point.file()));
        }

        Ok(())
    }
}

impl<E> fmt::Debug for Error<E> where E: fmt::Debug {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> std::result::Result<(), fmt::Error> {
        try!(write!(fmt, "Error: {:?}", self.original_error));
        for point in self.points.iter().rev() {
            try!(write!(fmt, "\n\tat {}:{} in {} ({})", point.line(), point.column(),
                point.module_path(), point.file()));
        }

        Ok(())
    }
}

#[macro_export]
macro_rules! up {
    ($e:expr) => (
        match $e {
            Ok(v) => v,
            Err(e) => {
                // re-assignment for a better error message if up!() is used incorrectly
                let mut e: $crate::Error<_> = e.transform();
                e.__push_point($crate::ErrorPoint::__construct(
                    line!(),
                    column!(),
                    module_path!(),
                    file!(),
                ));
                return Err(e);
            },
        }
    );
}

#[macro_export]
macro_rules! throw {
    ($e:expr) => (
        match $e {
            Ok(v) => v,
            Err(e) => throw_new!(e),
        }
    );
}

#[macro_export]
macro_rules! throw_new {
    ($e:expr) => ({
        let mut e: $crate::Error<_> = $crate::Error::new($e.into());
        e.__push_point($crate::ErrorPoint::__construct(
            line!(),
            column!(),
            module_path!(),
            file!(),
        ));
        return Err(e);
    })
}
<commit_msg>add move method<commit_after>#![deny(missing_docs)]
#![doc(html_root_url = "https://dabo.guru/rust/throw/throw/")]
//! Throw!
//! ------
//!
//! Throw is a new experimental rust error handling library, meant to assist and build on existing
//! error handling systems.
//!
//! Throw exports two structs, `throw::ErrorPoint` and `throw::Error`. `throw::Error` stores a
//! single `original_error` variable which it is created from, and then a list of `ErrorPoint`s
//! which starts out with the original point of creation with `throw!()`, and is added to every
//! time you propagate the error upwards with `up!()`.
//!
//! *Throw does not replace existing error handling systems*. The `throw::Error` type has a type
//! parameter `E` which represents an internal error type stored. `throw::Error` just wraps your
//! error type and stores ErrorPoints alongside it.
//!
//! Throw helps you better keep track of your errors. Instead of seeing a generic "No such file or
//! directory" message, you get a stack trace of functions which propagated the error as well.
//!
//! Instead of:
//!
//! ```text
//! IO Error: failed to lookup address information: Name or service not known
//! ```
//!
//! Get:
//!
//! ```text
//! Error: IO Error: failed to lookup address information: Name or service not known
//!     at 79:17 in zaldinar::startup (src/startup.rs)
//!     at 104:4 in zaldinar::startup (src/startup.rs)
//!     at 28:17 in zaldinar_irclib (/home/daboross/Projects/Rust/zaldinar/zaldinar-irclib/src/lib.rs)
//! ```
//!
//! ---
//!
//! Using throw!
//! ---
//!
//! The main way you use throw is through two macros, `throw!()` and `up!()`. `throw!()` is used
//! when you have a regular (non-throw) result coming from some library function that you want to
//! propagate upwards in case of an error. `up!()` is used when you have an error which was
//! created using `throw!()` in a sub-function which you want to add an error point to and
//! propagate upwards.
//!
//! Here's an example of throw in action:
//!
//! ```rust
//! #[macro_use]
//! extern crate throw;
//!
//! use std::io::prelude::*;
//! use std::io;
//! use std::fs::File;
//!
//! fn read_log() -> Result<String, throw::Error<io::Error>> {
//!     let mut file = throw!(File::open("some_file.log"));
//!     let mut buf = String::new();
//!     throw!(file.read_to_string(&mut buf));
//!     Ok((buf))
//! }
//!
//! fn do_things() -> Result<(), throw::Error<io::Error>> {
//!     let log_contents = up!(read_log());
//!     println!("Log contents: {}", log_contents);
//!
//!     Ok(())
//! }
//!
//! fn main() {
//!     let result = do_things();
//!     if let Err(e) = result {
//! #       /*
//!         panic!("{}", e);
//! #       */
//! #       assert_eq!(format!("{}", e), "Error: No such file or directory (os error 2)\
//! #       \n\tat 16:23 in rust_out (<anon>)\
//! #       \n\tat 9:19 in rust_out (<anon>)");
//!     }
//! }
//! ```
//!
//! This simple program behaves exactly as if `Result<_, io::Error>` directly when it functions
//! correctly. When the program encounters is when throw really shines.  This will result in an
//! error message:
//!
//! ```text
//! Error: No such file or directory (os error 2)
//!    at 16:23 in main (src/main.rs)
//!    at 9:19 in main (src/main.rs)
//! ```
//!
//! These stack traces are stored inside throw::Error, and are recorded automatically when
//! `throw!()` or `up!()` returns an Err value.
//!
//! In each `at` line, the `16:23` represents `line_num:column_num`, the `main` represents the
//! module path (for example `my_program::sub_module`), and `src/main.rs` represents the path of
//! the file in which `throw!()` was used in.
//!
//! ---
//!
//! Throwing directly from a function is also supported, using `throw_new!()`:
//!
//! ```
//! # #[macro_use]
//! # extern crate throw;
//! fn possibly_fails() -> Result<(), throw::Error<&'static str>> {
//!     if true {
//!         // throw_new!() will always return directly
//!         throw_new!("oops");
//!     }
//!
//!     Ok(())
//! }
//!
//! fn main() {
//! #   /*
//!     possibly_fails().unwrap()
//! #   */
//! #   assert_eq!(format!("{}", possibly_fails().unwrap_err()), "Error: oops\
//! #   \n\tat 6:8 in rust_out (<anon>)")
//! }
//! ```
//!
//! ```text
//! called `Result::unwrap()` on an `Err` value: Error: "oops"
//!    at 6:8 in main (src/main.rs)
//! ```
//!
//! `throw_new!()` differs from `throw!()` in that it takes a parameter directly to pass to a
//! `throw::Error`, rather than a `Result<>` to match on. `throw_new!()` will always return
//! directly from the function.

use std::fmt;

/// Result alias for a result containing a throw::Error.
pub type Result<T, E> = std::result::Result<T, Error<E>>;

/// Represents a location at which an error was thrown via throw!()
pub struct ErrorPoint {
    line: u32,
    column: u32,
    module_path: &'static str,
    file: &'static str,
}

impl ErrorPoint {
    /// The line throw!() occurred at, retrieved by line!()
    #[inline]
    pub fn line(&self) -> u32 {
        self.line
    }

    /// The column throw!() occurred at, retrieved by column!()
    #[inline]
    pub fn column(&self) -> u32 {
        self.column
    }

    /// The module throw!() occurred in, retrieved by module_path!()
    #[inline]
    pub fn module_path(&self) -> &'static str {
        self.module_path
    }

    /// The file throw!() occurred in, retrieved by file!()
    #[inline]
    pub fn file(&self) -> &'static str {
        self.file
    }

    #[doc(hidden)]
    pub fn __construct(line: u32, column: u32, module_path: &'static str, file: &'static str)
            -> ErrorPoint {
        ErrorPoint {
            line: line,
            column: column,
            module_path: module_path,
            file: file,
        }
    }
}

/// Represents an error. Stores an original error of type E, and any number of ErrorPoints at
/// which the error was propagated.
pub struct Error<E> {
    points: Vec<ErrorPoint>,
    original_error: E,
}

impl<E> Error<E> {
    /// Creates a new Error with no ErrorPoints
    pub fn new(error: E) -> Error<E> {
        Error {
            points: Vec::new(),
            original_error: error,
        }
    }

    /// For macro use only
    #[doc(hidden)]
    pub fn __push_point(&mut self, point: ErrorPoint) {
        self.points.push(point);
    }

    /// Gets all ErrorPoints where this Error was thrown. These are in reverse order, with the
    /// first time it was thrown first and the latest time it was thrown last.
    #[inline]
    pub fn points(&self) -> &[ErrorPoint] {
        &self.points
    }

    /// Gets the original error which this Error was constructed with.
    #[inline]
    pub fn original_error(&self) -> &E {
        &self.original_error
    }

    /// Move the original error out.
    #[inline]
    pub fn into_origin(self) -> E {
        self.original_error
    }

    /// Transforms this Error<OldError> into Error<NewError>. This isn't implemented as an Into or
    /// From implementation because it would conflict with the blanket implementations in stdlib.
    pub fn transform<NE>(self) -> Error<NE> where E: Into<NE> {
        Error {
            points: self.points,
            original_error: self.original_error.into(),
        }
    }
}

impl<E> fmt::Display for Error<E> where E: fmt::Display {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> std::result::Result<(), fmt::Error> {
        try!(write!(fmt, "Error: {}", self.original_error));
        for point in self.points.iter().rev() {
            try!(write!(fmt, "\n\tat {}:{} in {} ({})", point.line(), point.column(),
                point.module_path(), point.file()));
        }

        Ok(())
    }
}

impl<E> fmt::Debug for Error<E> where E: fmt::Debug {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> std::result::Result<(), fmt::Error> {
        try!(write!(fmt, "Error: {:?}", self.original_error));
        for point in self.points.iter().rev() {
            try!(write!(fmt, "\n\tat {}:{} in {} ({})", point.line(), point.column(),
                point.module_path(), point.file()));
        }

        Ok(())
    }
}

#[macro_export]
macro_rules! up {
    ($e:expr) => (
        match $e {
            Ok(v) => v,
            Err(e) => {
                // re-assignment for a better error message if up!() is used incorrectly
                let mut e: $crate::Error<_> = e.transform();
                e.__push_point($crate::ErrorPoint::__construct(
                    line!(),
                    column!(),
                    module_path!(),
                    file!(),
                ));
                return Err(e);
            },
        }
    );
}

#[macro_export]
macro_rules! throw {
    ($e:expr) => (
        match $e {
            Ok(v) => v,
            Err(e) => throw_new!(e),
        }
    );
}

#[macro_export]
macro_rules! throw_new {
    ($e:expr) => ({
        let mut e: $crate::Error<_> = $crate::Error::new($e.into());
        e.__push_point($crate::ErrorPoint::__construct(
            line!(),
            column!(),
            module_path!(),
            file!(),
        ));
        return Err(e);
    })
}
<|endoftext|>


<commit_before>#![doc(html_root_url = "https://hyperium.github.io/hyper/")]
#![deny(missing_docs)]
#![cfg_attr(test, deny(warnings))]
#![cfg_attr(all(test, feature = "nightly"), feature(test))]

//! # Hyper
//!
//! Hyper is a fast, modern HTTP implementation written in and for Rust. It
//! is a low-level typesafe abstraction over raw HTTP, providing an elegant
//! layer over "stringly-typed" HTTP.
//!
//! Hyper offers both a [Client](client/index.html) and a
//! [Server](server/index.html) which can be used to drive complex web
//! applications written entirely in Rust.
//!
//! ## Internal Design
//!
//! Hyper is designed as a relatively low-level wrapper over raw HTTP. It should
//! allow the implementation of higher-level abstractions with as little pain as
//! possible, and should not irrevocably hide any information from its users.
//!
//! ### Common Functionality
//!
//! Functionality and code shared between the Server and Client implementations
//! can be found in `src` directly - this includes `NetworkStream`s, `Method`s,
//! `StatusCode`, and so on.
//!
//! #### Methods
//!
//! Methods are represented as a single `enum` to remain as simple as possible.
//! Extension Methods are represented as raw `String`s. A method's safety and
//! idempotence can be accessed using the `safe` and `idempotent` methods.
//!
//! #### StatusCode
//!
//! Status codes are also represented as a single, exhaustive, `enum`. This
//! representation is efficient, typesafe, and ergonomic as it allows the use of
//! `match` to disambiguate known status codes.
//!
//! #### Headers
//!
//! Hyper's [header](header/index.html) representation is likely the most
//! complex API exposed by Hyper.
//!
//! Hyper's headers are an abstraction over an internal `HashMap` and provides a
//! typesafe API for interacting with headers that does not rely on the use of
//! "string-typing."
//!
//! Each HTTP header in Hyper has an associated type and implementation of the
//! `Header` trait, which defines an HTTP headers name as a string, how to parse
//! that header, and how to format that header.
//!
//! Headers are then parsed from the string representation lazily when the typed
//! representation of a header is requested and formatted back into their string
//! representation when headers are written back to the client.
//!
//! #### NetworkStream and NetworkAcceptor
//!
//! These are found in `src/net.rs` and define the interface that acceptors and
//! streams must fulfill for them to be used within Hyper. They are by and large
//! internal tools and you should only need to mess around with them if you want to
//! mock or replace `TcpStream` and `TcpAcceptor`.
//!
//! ### Server
//!
//! Server-specific functionality, such as `Request` and `Response`
//! representations, are found in in `src/server`.
//!
//! #### Handler + Server
//!
//! A `Handler` in Hyper accepts a `Request` and `Response`. This is where
//! user-code can handle each connection. The server accepts connections in a
//! task pool with a customizable number of threads, and passes the Request /
//! Response to the handler.
//!
//! #### Request
//!
//! An incoming HTTP Request is represented as a struct containing
//! a `Reader` over a `NetworkStream`, which represents the body, headers, a remote
//! address, an HTTP version, and a `Method` - relatively standard stuff.
//!
//! `Request` implements `Reader` itself, meaning that you can ergonomically get
//! the body out of a `Request` using standard `Reader` methods and helpers.
//!
//! #### Response
//!
//! An outgoing HTTP Response is also represented as a struct containing a `Writer`
//! over a `NetworkStream` which represents the Response body in addition to
//! standard items such as the `StatusCode` and HTTP version. `Response`'s `Writer`
//! implementation provides a streaming interface for sending data over to the
//! client.
//!
//! One of the traditional problems with representing outgoing HTTP Responses is
//! tracking the write-status of the Response - have we written the status-line,
//! the headers, the body, etc.? Hyper tracks this information statically using the
//! type system and prevents you, using the type system, from writing headers after
//! you have started writing to the body or vice versa.
//!
//! Hyper does this through a phantom type parameter in the definition of Response,
//! which tracks whether you are allowed to write to the headers or the body. This
//! phantom type can have two values `Fresh` or `Streaming`, with `Fresh`
//! indicating that you can write the headers and `Streaming` indicating that you
//! may write to the body, but not the headers.
//!
//! ### Client
//!
//! Client-specific functionality, such as `Request` and `Response`
//! representations, are found in `src/client`.
//!
//! #### Request
//!
//! An outgoing HTTP Request is represented as a struct containing a `Writer` over
//! a `NetworkStream` which represents the Request body in addition to the standard
//! information such as headers and the request method.
//!
//! Outgoing Requests track their write-status in almost exactly the same way as
//! outgoing HTTP Responses do on the Server, so we will defer to the explanation
//! in the documentation for server Response.
//!
//! Requests expose an efficient streaming interface instead of a builder pattern,
//! but they also provide the needed interface for creating a builder pattern over
//! the API exposed by core Hyper.
//!
//! #### Response
//!
//! Incoming HTTP Responses are represented as a struct containing a `Reader` over
//! a `NetworkStream` and contain headers, a status, and an http version. They
//! implement `Reader` and can be read to get the data out of a `Response`.
//!

extern crate rustc_serialize as serialize;
extern crate time;
extern crate url;
#[cfg(feature = "openssl")]
extern crate openssl;
extern crate cookie;
extern crate unicase;
extern crate httparse;
extern crate num_cpus;
extern crate traitobject;
extern crate typeable;
extern crate solicit;

#[macro_use]
extern crate language_tags;

#[macro_use]
extern crate mime as mime_crate;

#[macro_use]
extern crate log;

#[cfg(all(test, feature = "nightly"))]
extern crate test;

pub use url::Url;
pub use client::Client;
pub use error::{Result, Error};
pub use method::Method::{Get, Head, Post, Delete};
pub use status::StatusCode::{Ok, BadRequest, NotFound};
pub use server::Server;
pub use language_tags::LanguageTag;

macro_rules! todo(
    ($($arg:tt)*) => (if cfg!(not(ndebug)) {
        trace!("TODO: {:?}", format_args!($($arg)*))
    })
);

macro_rules! inspect(
    ($name:expr, $value:expr) => ({
        let v = $value;
        trace!("inspect: {:?} = {:?}", $name, v);
        v
    })
);

#[cfg(test)]
#[macro_use]
mod mock;
#[doc(hidden)]
pub mod buffer;
pub mod client;
pub mod error;
pub mod method;
pub mod header;
pub mod http;
pub mod net;
pub mod server;
pub mod status;
pub mod uri;
pub mod version;

/// Re-exporting the mime crate, for convenience.
pub mod mime {
    pub use mime_crate::*;
}

#[allow(unconditional_recursion)]
fn _assert_send<T: Send>() {
    _assert_send::<Client>();
    _assert_send::<client::Request<net::Fresh>>();
    _assert_send::<client::Response>();
}

#[allow(unconditional_recursion)]
fn _assert_sync<T: Sync>() {
    _assert_sync::<Client>();
}
<commit_msg>test(hyper): assert that `error::Error` is Send + Sync<commit_after>#![doc(html_root_url = "https://hyperium.github.io/hyper/")]
#![deny(missing_docs)]
#![cfg_attr(test, deny(warnings))]
#![cfg_attr(all(test, feature = "nightly"), feature(test))]

//! # Hyper
//!
//! Hyper is a fast, modern HTTP implementation written in and for Rust. It
//! is a low-level typesafe abstraction over raw HTTP, providing an elegant
//! layer over "stringly-typed" HTTP.
//!
//! Hyper offers both a [Client](client/index.html) and a
//! [Server](server/index.html) which can be used to drive complex web
//! applications written entirely in Rust.
//!
//! ## Internal Design
//!
//! Hyper is designed as a relatively low-level wrapper over raw HTTP. It should
//! allow the implementation of higher-level abstractions with as little pain as
//! possible, and should not irrevocably hide any information from its users.
//!
//! ### Common Functionality
//!
//! Functionality and code shared between the Server and Client implementations
//! can be found in `src` directly - this includes `NetworkStream`s, `Method`s,
//! `StatusCode`, and so on.
//!
//! #### Methods
//!
//! Methods are represented as a single `enum` to remain as simple as possible.
//! Extension Methods are represented as raw `String`s. A method's safety and
//! idempotence can be accessed using the `safe` and `idempotent` methods.
//!
//! #### StatusCode
//!
//! Status codes are also represented as a single, exhaustive, `enum`. This
//! representation is efficient, typesafe, and ergonomic as it allows the use of
//! `match` to disambiguate known status codes.
//!
//! #### Headers
//!
//! Hyper's [header](header/index.html) representation is likely the most
//! complex API exposed by Hyper.
//!
//! Hyper's headers are an abstraction over an internal `HashMap` and provides a
//! typesafe API for interacting with headers that does not rely on the use of
//! "string-typing."
//!
//! Each HTTP header in Hyper has an associated type and implementation of the
//! `Header` trait, which defines an HTTP headers name as a string, how to parse
//! that header, and how to format that header.
//!
//! Headers are then parsed from the string representation lazily when the typed
//! representation of a header is requested and formatted back into their string
//! representation when headers are written back to the client.
//!
//! #### NetworkStream and NetworkAcceptor
//!
//! These are found in `src/net.rs` and define the interface that acceptors and
//! streams must fulfill for them to be used within Hyper. They are by and large
//! internal tools and you should only need to mess around with them if you want to
//! mock or replace `TcpStream` and `TcpAcceptor`.
//!
//! ### Server
//!
//! Server-specific functionality, such as `Request` and `Response`
//! representations, are found in in `src/server`.
//!
//! #### Handler + Server
//!
//! A `Handler` in Hyper accepts a `Request` and `Response`. This is where
//! user-code can handle each connection. The server accepts connections in a
//! task pool with a customizable number of threads, and passes the Request /
//! Response to the handler.
//!
//! #### Request
//!
//! An incoming HTTP Request is represented as a struct containing
//! a `Reader` over a `NetworkStream`, which represents the body, headers, a remote
//! address, an HTTP version, and a `Method` - relatively standard stuff.
//!
//! `Request` implements `Reader` itself, meaning that you can ergonomically get
//! the body out of a `Request` using standard `Reader` methods and helpers.
//!
//! #### Response
//!
//! An outgoing HTTP Response is also represented as a struct containing a `Writer`
//! over a `NetworkStream` which represents the Response body in addition to
//! standard items such as the `StatusCode` and HTTP version. `Response`'s `Writer`
//! implementation provides a streaming interface for sending data over to the
//! client.
//!
//! One of the traditional problems with representing outgoing HTTP Responses is
//! tracking the write-status of the Response - have we written the status-line,
//! the headers, the body, etc.? Hyper tracks this information statically using the
//! type system and prevents you, using the type system, from writing headers after
//! you have started writing to the body or vice versa.
//!
//! Hyper does this through a phantom type parameter in the definition of Response,
//! which tracks whether you are allowed to write to the headers or the body. This
//! phantom type can have two values `Fresh` or `Streaming`, with `Fresh`
//! indicating that you can write the headers and `Streaming` indicating that you
//! may write to the body, but not the headers.
//!
//! ### Client
//!
//! Client-specific functionality, such as `Request` and `Response`
//! representations, are found in `src/client`.
//!
//! #### Request
//!
//! An outgoing HTTP Request is represented as a struct containing a `Writer` over
//! a `NetworkStream` which represents the Request body in addition to the standard
//! information such as headers and the request method.
//!
//! Outgoing Requests track their write-status in almost exactly the same way as
//! outgoing HTTP Responses do on the Server, so we will defer to the explanation
//! in the documentation for server Response.
//!
//! Requests expose an efficient streaming interface instead of a builder pattern,
//! but they also provide the needed interface for creating a builder pattern over
//! the API exposed by core Hyper.
//!
//! #### Response
//!
//! Incoming HTTP Responses are represented as a struct containing a `Reader` over
//! a `NetworkStream` and contain headers, a status, and an http version. They
//! implement `Reader` and can be read to get the data out of a `Response`.
//!

extern crate rustc_serialize as serialize;
extern crate time;
extern crate url;
#[cfg(feature = "openssl")]
extern crate openssl;
extern crate cookie;
extern crate unicase;
extern crate httparse;
extern crate num_cpus;
extern crate traitobject;
extern crate typeable;
extern crate solicit;

#[macro_use]
extern crate language_tags;

#[macro_use]
extern crate mime as mime_crate;

#[macro_use]
extern crate log;

#[cfg(all(test, feature = "nightly"))]
extern crate test;

pub use url::Url;
pub use client::Client;
pub use error::{Result, Error};
pub use method::Method::{Get, Head, Post, Delete};
pub use status::StatusCode::{Ok, BadRequest, NotFound};
pub use server::Server;
pub use language_tags::LanguageTag;

macro_rules! todo(
    ($($arg:tt)*) => (if cfg!(not(ndebug)) {
        trace!("TODO: {:?}", format_args!($($arg)*))
    })
);

macro_rules! inspect(
    ($name:expr, $value:expr) => ({
        let v = $value;
        trace!("inspect: {:?} = {:?}", $name, v);
        v
    })
);

#[cfg(test)]
#[macro_use]
mod mock;
#[doc(hidden)]
pub mod buffer;
pub mod client;
pub mod error;
pub mod method;
pub mod header;
pub mod http;
pub mod net;
pub mod server;
pub mod status;
pub mod uri;
pub mod version;

/// Re-exporting the mime crate, for convenience.
pub mod mime {
    pub use mime_crate::*;
}

#[allow(unconditional_recursion)]
fn _assert_send<T: Send>() {
    _assert_send::<Client>();
    _assert_send::<client::Request<net::Fresh>>();
    _assert_send::<client::Response>();
    _assert_send::<error::Error>();
}

#[allow(unconditional_recursion)]
fn _assert_sync<T: Sync>() {
    _assert_sync::<Client>();
    _assert_sync::<error::Error>();
}
<|endoftext|>


<commit_before>extern crate git2;

use std::path::Path;
use std::path::PathBuf;
use std::fmt::Write;

pub struct GitPromptRepo {
    lg2_repo: Option<git2::Repository>,
    origin_path: PathBuf,
    root_path: PathBuf,
    is_unborn: bool,
    has_head: bool,
    has_checkout: bool,
}

impl GitPromptRepo {
    pub fn new(path_spec: &Path) -> GitPromptRepo {
        let lg2_repo = git2::Repository::discover(path_spec).ok();
        let mut root_path = PathBuf::new();
        let mut is_unborn = false;
        let mut has_head = false;
        let mut has_checkout = false;

        if let Some(ref repo) = lg2_repo {
            root_path = repo.path().to_path_buf();
            if let Err(e) = repo.head() {
                is_unborn = e.code() == git2::ErrorCode::UnbornBranch;
            } else {
                has_head = true;
            }
            has_checkout = !repo.is_bare();
        }

        GitPromptRepo {
            lg2_repo: lg2_repo,
            origin_path: path_spec.to_path_buf(),
            root_path: root_path,
            is_unborn: is_unborn,
            has_head: has_head,
            has_checkout: has_checkout,
        }
    }

    // Assumes has_head is true
    fn head_name(&self) -> String {
        self.lg2_repo
            .as_ref()
            .unwrap()
            .head()
            .unwrap()
            .name()
            .unwrap_or("")
            .trim_left_matches("refs/heads/")
            .to_string()
    }

    fn head_to_branch(&self) -> Option<git2::Branch> {
        if self.has_head {
            let head_name = self.head_name();
            return self.lg2_repo
                .as_ref()
                .unwrap()
                .find_branch(head_name.as_str(), git2::BranchType::Local)
                .ok();
        }
        None
    }

    fn head_branch_has_upstream(&self) -> bool {
        if let Some(branch) = self.head_to_branch() {
            return branch.upstream().is_ok();
        }
        false
    }

    // fn is_remote(&self) -> bool {
    //     match &self.ref_result {
    //         &Ok(ref r) => r.is_remote(),
    //         &Err(_) => false
    //     }
    // }

    fn build_ref_name_for_commit(&self, commit: &git2::Commit, ref_string: &mut String) {
        let oid = commit.id();
        let mut candidate_branch_names = Vec::new();
        let branches_it = self.lg2_repo
            .as_ref()
            .unwrap()
            .branches(Some(git2::BranchType::Remote))
            .unwrap()
            .filter_map(|branch_result| branch_result.ok());
        for branch in branches_it {
            let ref branch_ref = branch.0.get();
            let peeled_obj_res = branch_ref.peel(git2::ObjectType::Commit);
            if peeled_obj_res.is_ok() && peeled_obj_res.unwrap().id() == oid
                && branch_ref.name().is_some()
            {
                candidate_branch_names.push(branch_ref.name().unwrap().to_string());
            }
        }
        ref_string.clear();
        if candidate_branch_names.is_empty() {
            let mut oid_string = "".to_string();
            write!(oid_string, "{}", oid).unwrap();
            oid_string.truncate(8);
            write!(ref_string, "{}", oid_string).unwrap();
        } else {
            write!(
                ref_string,
                "{}",
                find_best_branch_name(candidate_branch_names)
            ).unwrap();
        }
    }

    pub fn ref_name_head(&self) -> String {
        let mut ref_string = "".to_string();
        if self.is_unborn {
            ref_string = "[Unborn]".to_string();
        } else if self.has_head {
            ref_string = self.head_name();
        }
        if ref_string == "HEAD" {
            let head_object = self.lg2_repo
                .as_ref()
                .unwrap()
                .head()
                .unwrap()
                .resolve()
                .unwrap()
                .peel(git2::ObjectType::Commit)
                .unwrap();
            let head_commit = head_object.as_commit().unwrap();
            self.build_ref_name_for_commit(head_commit, &mut ref_string);
        }
        ref_string.to_string()
    }

    pub fn upstream_name(&self) -> String {
        if self.head_branch_has_upstream() {
            let branch = self.head_to_branch().unwrap();
            let upstream_branch = branch.upstream().unwrap();
            if let Ok(Some(name)) = upstream_branch.name() {
                return name.to_string();
            }
        }
        "".to_string()
    }

    pub fn ahead_behind(&self) -> String {
        let mut result = String::from("");
        if self.head_branch_has_upstream() {
            let head_branch = self.head_to_branch().unwrap();
            let upstream_branch = head_branch.upstream().unwrap();
            let head_branch_oid = head_branch.get().resolve().unwrap().target().unwrap();
            let upstream_branch_oid = upstream_branch.get().resolve().unwrap().target().unwrap();
            let repo = self.lg2_repo.as_ref().unwrap();
            let (ahead, behind) = repo.graph_ahead_behind(head_branch_oid, upstream_branch_oid)
                .unwrap();
            if behind > 0 {
                result += "↓·";
                result += &*behind.to_string();
            }
            if ahead > 0 {
                result += "↑·";
                result += &*ahead.to_string();
            }
        }
        result
    }

    pub fn status(&self) -> String {
        let mut result = String::from("");
        if self.has_checkout {
            let mut opts = git2::StatusOptions::new();
            if let Ok(statuses) = self.lg2_repo.as_ref().unwrap().statuses(Some(
                opts.update_index(true)
                    .include_untracked(true)
                    .recurse_untracked_dirs(true),
            )) {
                result += &status_bit_to_string(&statuses, git2::STATUS_INDEX_MODIFIED, "∂");
                result += &status_bit_to_string(&statuses, git2::STATUS_INDEX_NEW, "…");
                result += &status_bit_to_string(&statuses, git2::STATUS_INDEX_DELETED, "✖");
                result +=
                    &status_bit_to_string(&statuses, git2::STATUS_CONFLICTED, "\x1b[31;1m≠");
                result += &status_bit_to_string(&statuses, git2::STATUS_WT_MODIFIED, "\x1b[34m∂");
                result += &status_bit_to_string(&statuses, git2::STATUS_WT_NEW, "\x1b[34m…");
                result += &status_bit_to_string(&statuses, git2::STATUS_WT_DELETED, "\x1b[34m✖");
            }
            if result.is_empty() {
                result = String::from("\x1b[36m√\x1b[m");
            }
        }
        result
    }
}

fn status_bit_to_string(statuses: &git2::Statuses, flag: git2::Status, prefix: &str) -> String {
    let count = statuses
        .iter()
        .filter(|s| s.status().contains(flag))
        .count();
    let mut result = "".to_string();
    if count > 0 {
        write!(result, "{}{}\x1b[m", prefix, count).unwrap();
    }
    result
}

fn abbreviated_remote_branch_name(full_name: &String) -> Option<String> {
    let mut full_name_it = full_name.split('/').peekable();
    if full_name_it.next() == Some("refs") && full_name_it.next() == Some("remotes")
        && full_name_it.peek().is_some()
    {
        let mut abbreviated_name = full_name_it.next().unwrap().to_string();
        if full_name_it.peek().is_some()
            && full_name_it.peek().unwrap().to_string() == "HEAD".to_string()
        {
            return None;
        }
        for s in full_name_it {
            abbreviated_name.push('/');
            abbreviated_name.push_str(s);
        }
        if !abbreviated_name.is_empty() {
            return Some(abbreviated_name);
        }
    }
    None
}

fn find_best_branch_name(branch_names: Vec<String>) -> String {
    let working_branch_names: Vec<String> = branch_names
        .iter()
        .filter_map(abbreviated_remote_branch_name)
        .filter(|b| b != "HEAD")
        .collect();

    working_branch_names[0].clone()
}
<commit_msg>Minor code simplification.<commit_after>extern crate git2;

use std::path::Path;
use std::path::PathBuf;
use std::fmt::Write;

pub struct GitPromptRepo {
    lg2_repo: Option<git2::Repository>,
    origin_path: PathBuf,
    root_path: PathBuf,
    is_unborn: bool,
    has_head: bool,
    has_checkout: bool,
}

impl GitPromptRepo {
    pub fn new(path_spec: &Path) -> GitPromptRepo {
        let lg2_repo = git2::Repository::discover(path_spec).ok();
        let mut root_path = PathBuf::new();
        let mut is_unborn = false;
        let mut has_head = false;
        let mut has_checkout = false;

        if let Some(ref repo) = lg2_repo {
            root_path = repo.path().to_path_buf();
            if let Err(e) = repo.head() {
                is_unborn = e.code() == git2::ErrorCode::UnbornBranch;
            } else {
                has_head = true;
            }
            has_checkout = !repo.is_bare();
        }

        GitPromptRepo {
            lg2_repo: lg2_repo,
            origin_path: path_spec.to_path_buf(),
            root_path: root_path,
            is_unborn: is_unborn,
            has_head: has_head,
            has_checkout: has_checkout,
        }
    }

    // Assumes has_head is true
    fn head_name(&self) -> String {
        self.lg2_repo
            .as_ref()
            .unwrap()
            .head()
            .unwrap()
            .name()
            .unwrap_or("")
            .trim_left_matches("refs/heads/")
            .to_string()
    }

    fn head_to_branch(&self) -> Option<git2::Branch> {
        if self.has_head {
            let head_name = self.head_name();
            return self.lg2_repo
                .as_ref()
                .unwrap()
                .find_branch(head_name.as_str(), git2::BranchType::Local)
                .ok();
        }
        None
    }

    fn head_branch_has_upstream(&self) -> bool {
        if let Some(branch) = self.head_to_branch() {
            return branch.upstream().is_ok();
        }
        false
    }

    // fn is_remote(&self) -> bool {
    //     match &self.ref_result {
    //         &Ok(ref r) => r.is_remote(),
    //         &Err(_) => false
    //     }
    // }

    fn build_ref_name_for_commit(&self, commit: &git2::Commit, ref_string: &mut String) {
        let oid = commit.id();
        let mut candidate_branch_names = Vec::new();
        let branches_it = self.lg2_repo
            .as_ref()
            .unwrap()
            .branches(Some(git2::BranchType::Remote))
            .unwrap()
            .filter_map(|branch_result| branch_result.ok());
        for branch in branches_it {
            let ref branch_ref = branch.0.get();
            let peeled_obj_res = branch_ref.peel(git2::ObjectType::Commit);
            if peeled_obj_res.is_ok() && peeled_obj_res.unwrap().id() == oid
                && branch_ref.name().is_some()
            {
                candidate_branch_names.push(branch_ref.name().unwrap().to_string());
            }
        }
        ref_string.clear();
        if candidate_branch_names.is_empty() {
            let mut oid_string = "".to_string();
            write!(oid_string, "{}", oid).unwrap();
            oid_string.truncate(8);
            write!(ref_string, "{}", oid_string).unwrap();
        } else {
            write!(
                ref_string,
                "{}",
                find_best_branch_name(candidate_branch_names)
            ).unwrap();
        }
    }

    pub fn ref_name_head(&self) -> String {
        let mut ref_string = "".to_string();
        if self.is_unborn {
            ref_string = "[Unborn]".to_string();
        } else if self.has_head {
            ref_string = self.head_name();
        }
        if ref_string == "HEAD" {
            let head_object = self.lg2_repo
                .as_ref()
                .unwrap()
                .head()
                .unwrap()
                .resolve()
                .unwrap()
                .peel(git2::ObjectType::Commit)
                .unwrap();
            let head_commit = head_object.as_commit().unwrap();
            self.build_ref_name_for_commit(head_commit, &mut ref_string);
        }
        ref_string.to_string()
    }

    pub fn upstream_name(&self) -> String {
        if self.head_branch_has_upstream() {
            let branch = self.head_to_branch().unwrap();
            let upstream_branch = branch.upstream().unwrap();
            if let Ok(Some(name)) = upstream_branch.name() {
                return name.to_string();
            }
        }
        "".to_string()
    }

    pub fn ahead_behind(&self) -> String {
        let mut result = String::from("");
        if self.head_branch_has_upstream() {
            let head_branch = self.head_to_branch().unwrap();
            let upstream_branch = head_branch.upstream().unwrap();
            let head_branch_oid = head_branch.get().resolve().unwrap().target().unwrap();
            let upstream_branch_oid = upstream_branch.get().resolve().unwrap().target().unwrap();
            let repo = self.lg2_repo.as_ref().unwrap();
            let (ahead, behind) = repo.graph_ahead_behind(head_branch_oid, upstream_branch_oid)
                .unwrap();
            if behind > 0 {
                result += "↓·";
                result += &*behind.to_string();
            }
            if ahead > 0 {
                result += "↑·";
                result += &*ahead.to_string();
            }
        }
        result
    }

    pub fn status(&self) -> String {
        let mut result = String::from("");
        if self.has_checkout {
            let mut opts = git2::StatusOptions::new();
            if let Ok(statuses) = self.lg2_repo.as_ref().unwrap().statuses(Some(
                opts.update_index(true)
                    .include_untracked(true)
                    .recurse_untracked_dirs(true),
            )) {
                result += &status_bit_to_string(&statuses, git2::STATUS_INDEX_MODIFIED, "∂");
                result += &status_bit_to_string(&statuses, git2::STATUS_INDEX_NEW, "…");
                result += &status_bit_to_string(&statuses, git2::STATUS_INDEX_DELETED, "✖");
                result +=
                    &status_bit_to_string(&statuses, git2::STATUS_CONFLICTED, "\x1b[31;1m≠");
                result += &status_bit_to_string(&statuses, git2::STATUS_WT_MODIFIED, "\x1b[34m∂");
                result += &status_bit_to_string(&statuses, git2::STATUS_WT_NEW, "\x1b[34m…");
                result += &status_bit_to_string(&statuses, git2::STATUS_WT_DELETED, "\x1b[34m✖");
            }
            if result.is_empty() {
                result = String::from("\x1b[36m√\x1b[m");
            }
        }
        result
    }
}

fn status_bit_to_string(statuses: &git2::Statuses, flag: git2::Status, prefix: &str) -> String {
    let count = statuses
        .iter()
        .filter(|s| s.status().contains(flag))
        .count();
    let mut result = "".to_string();
    if count > 0 {
        write!(result, "{}{}\x1b[m", prefix, count).unwrap();
    }
    result
}

fn abbreviated_remote_branch_name(full_name: &String) -> Option<String> {
    let mut full_name_it = full_name.split('/').peekable();
    if full_name_it.next() == Some("refs") && full_name_it.next() == Some("remotes")
        && full_name_it.peek().is_some()
    {
        let mut abbreviated_name = full_name_it.next().unwrap().to_string();
        if full_name_it.peek().unwrap_or(&"").to_string() == "HEAD".to_string() {
            return None;
        }
        for s in full_name_it {
            abbreviated_name.push('/');
            abbreviated_name.push_str(s);
        }
        if !abbreviated_name.is_empty() {
            return Some(abbreviated_name);
        }
    }
    None
}

fn find_best_branch_name(branch_names: Vec<String>) -> String {
    let working_branch_names: Vec<String> = branch_names
        .iter()
        .filter_map(abbreviated_remote_branch_name)
        .filter(|b| b != "HEAD")
        .collect();

    working_branch_names[0].clone()
}
<|endoftext|>


<commit_before>extern crate crossbeam;

use std::borrow::Cow;
use std::ffi::{OsStr, OsString};
use std::fs::File;
use std::io;
use std::io::prelude::*;
use std::path::Path;
use std::process::{Command, Output, ExitStatus};
use std::thread::JoinHandle;

mod pipe;

pub fn cmd<T: AsRef<OsStr>>(argv: &[T]) -> Expression<'static> {
    let argv_vec = argv.iter().map(|arg| arg.as_ref().to_owned()).collect();
    Expression {
        inner: ExpressionInner::ArgvCommand(argv_vec),
        ioargs: IoArgs::new(),
    }
}

pub fn sh<T: AsRef<OsStr>>(command: T) -> Expression<'static> {
    Expression {
        inner: ExpressionInner::ShCommand(command.as_ref().to_owned()),
        ioargs: IoArgs::new(),
    }
}

pub fn pipe<'a>(left: Expression<'a>, right: Expression<'a>) -> Expression<'a> {
    Expression {
        inner: ExpressionInner::Pipe(Box::new(left), Box::new(right)),
        ioargs: IoArgs::new(),
    }
}

pub fn then<'a>(left: Expression<'a>, right: Expression<'a>) -> Expression<'a> {
    Expression {
        inner: ExpressionInner::Then(Box::new(left), Box::new(right)),
        ioargs: IoArgs::new(),
    }
}

#[derive(Debug)]
pub struct Expression<'a> {
    inner: ExpressionInner<'a>,
    ioargs: IoArgs<'a>,
}

#[derive(Debug)]
enum ExpressionInner<'a> {
    ArgvCommand(Vec<OsString>),
    ShCommand(OsString),
    Pipe(Box<Expression<'a>>, Box<Expression<'a>>),
    Then(Box<Expression<'a>>, Box<Expression<'a>>),
}

impl<'a> Expression<'a> {
    pub fn run(&self) -> Result<Output, Error> {
        unreachable!();
    }

    pub fn read(&self) -> Result<String, Error> {
        let (handle, reader) = pipe_with_reader_thread();
        let mut context = IoContext::new();
        context.stdout = handle;
        let status = try!(self.exec(context));
        let stdout_vec = try!(reader.join().unwrap());
        if !status.success() {
            return Err(Error::Status(Output {
                status: status,
                stdout: stdout_vec,
                stderr: Vec::new(),
            }));
        }
        let stdout_string = try!(std::str::from_utf8(&stdout_vec))
                                .trim_right_matches('\n')
                                .to_owned();
        Ok(stdout_string)
    }

    fn exec(&self, parent_context: IoContext) -> io::Result<ExitStatus> {
        self.ioargs.with_child_context(parent_context, |context| {
            match self.inner {
                ExpressionInner::ArgvCommand(ref argv) => exec_argv(argv, context),
                ExpressionInner::ShCommand(ref command) => exec_sh(command, context),
                ExpressionInner::Pipe(ref left, ref right) => exec_pipe(left, right, context),
                ExpressionInner::Then(ref left, ref right) => exec_then(left, right, context),
            }
        })
    }

    pub fn stdin(&mut self, arg: InputArg<'a>) -> &mut Self {
        self.ioargs.stdin = arg;
        self
    }

    pub fn stdout(&mut self, arg: OutputArg<'a>) -> &mut Self {
        self.ioargs.stdout = arg;
        self
    }

    pub fn stderr(&mut self, arg: OutputArg<'a>) -> &mut Self {
        self.ioargs.stderr = arg;
        self
    }
}

fn exec_argv(argv: &Vec<OsString>, context: IoContext) -> io::Result<ExitStatus> {
    let mut command = Command::new(&argv[0]);
    command.args(&argv[1..]);
    command.stdin(context.stdin.to_stdio());
    command.stdout(context.stdout.to_stdio());
    command.stderr(context.stderr.to_stdio());
    command.status()
}

fn exec_sh(command: &OsStr, context: IoContext) -> io::Result<ExitStatus> {
    // TODO: What shell should we be using here, really?
    // TODO: Figure out how cmd.exe works on Windows.
    let mut argv = Vec::new();
    argv.push("bash".into());
    argv.push("-c".into());
    argv.push(command.to_owned());
    exec_argv(&argv, context)
}

fn exec_pipe(left: &Expression, right: &Expression, context: IoContext) -> io::Result<ExitStatus> {
    let (read_pipe, write_pipe) = pipe::open_pipe();
    let left_context = IoContext {
        stdin: context.stdin,
        stdout: write_pipe,
        stderr: context.stderr.clone(),
    };
    let right_context = IoContext {
        stdin: read_pipe,
        stdout: context.stdout,
        stderr: context.stderr,
    };

    let (left_result, right_result) = crossbeam::scope(|scope| {
        let left_joiner = scope.spawn(|| left.exec(left_context));
        let right_result = right.exec(right_context);
        let left_result = left_joiner.join();
        (left_result, right_result)
    });

    let right_status = try!(right_result);
    let left_status = try!(left_result);
    if !right_status.success() {
        Ok(right_status)
    } else {
        Ok(left_status)
    }
}

fn exec_then(left: &Expression, right: &Expression, context: IoContext) -> io::Result<ExitStatus> {
    let status = try!(left.exec(context.clone()));
    if !status.success() {
        Ok(status)
    } else {
        right.exec(context)
    }
}

#[derive(Debug)]
pub enum Error {
    Io(io::Error),
    Utf8(std::str::Utf8Error),
    Status(Output),
}

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

impl From<std::str::Utf8Error> for Error {
    fn from(err: std::str::Utf8Error) -> Error {
        Error::Utf8(err)
    }
}

// IoArgs store the redirections and other settings associated with an expression. At execution
// time, IoArgs are used to modify an IoContext, which contains the actual pipes that child process
#[derive(Debug)]
struct IoArgs<'a> {
    stdin: InputArg<'a>,
    stdout: OutputArg<'a>,
    stderr: OutputArg<'a>,
}

impl<'a> IoArgs<'a> {
    fn new() -> IoArgs<'static> {
        IoArgs {
            stdin: InputArg::Inherit,
            stdout: OutputArg::Inherit,
            stderr: OutputArg::Inherit,
        }
    }

    fn with_child_context<F, T>(&self, parent_context: IoContext, inner: F) -> io::Result<T>
        where F: FnOnce(IoContext) -> io::Result<T>
    {
        crossbeam::scope(|scope| {
            let parent_context = parent_context;  // move it into the closure
            let (stdin, maybe_stdin_thread) = try!(self.stdin
                                                       .update_handle(parent_context.stdin, scope));
            let stdout = try!(self.stdout.update_handle(parent_context.stdout));
            let stderr = try!(self.stderr.update_handle(parent_context.stderr));
            let (stdout, stderr) = apply_swaps(stdout, stderr, &self.stdout, &self.stderr);

            let child_context = IoContext {
                stdin: stdin,
                stdout: stdout,
                stderr: stderr,
            };

            let ret = try!(inner(child_context));

            if let Some(thread) = maybe_stdin_thread {
                try!(thread.join());
            }

            Ok(ret)
        })
    }
}

// returns (new_stdout, new_stderr)
fn apply_swaps(stdout_handle: pipe::Handle,
               stderr_handle: pipe::Handle,
               stdout_arg: &OutputArg,
               stderr_arg: &OutputArg)
               -> (pipe::Handle, pipe::Handle) {
    // TODO: These clones are a little excessive.
    let new_stdout = if let &OutputArg::Stderr = stdout_arg {
        stderr_handle.clone()
    } else {
        stdout_handle.clone()
    };
    let new_stderr = if let &OutputArg::Stdout = stderr_arg {
        stdout_handle.clone()
    } else {
        stderr_handle.clone()
    };
    (new_stdout, new_stderr)
}

#[derive(Debug)]
pub enum InputArg<'a> {
    Inherit,
    Null,
    Path(Cow<'a, Path>),
    // TODO: Figure out what the hell to do with these File variants. They don't work with Cow,
    // because they're not Clone/ToOwned.
    FileRef(&'a File),
    FileOwned(File),
    Bytes(Cow<'a, [u8]>),
}

impl<'a> InputArg<'a> {
    fn update_handle(&'a self,
                     parent_handle: pipe::Handle,
                     scope: &crossbeam::Scope<'a>)
                     -> io::Result<(pipe::Handle, Option<WriterThreadJoiner>)> {
        let mut maybe_thread = None;
        let handle = match self {
            &InputArg::Inherit => parent_handle,
            &InputArg::Null => pipe::Handle::from_file(try!(File::open("/dev/null"))),  // TODO: Windows
            &InputArg::Path(ref p) => pipe::Handle::from_file(try!(File::open(&p))),
            &InputArg::FileRef(ref f) => pipe::Handle::dup_file(f),
            &InputArg::FileOwned(ref f) => pipe::Handle::dup_file(f),
            &InputArg::Bytes(ref v) => {
                let (handle, thread) = pipe_with_writer_thread(v, scope);
                maybe_thread = Some(thread);
                handle
            }
        };
        Ok((handle, maybe_thread))
    }
}

// TODO: stdout/stderr swaps
#[derive(Debug)]
pub enum OutputArg<'a> {
    Inherit,
    Null,
    Stdout,
    Stderr,
    Path(Cow<'a, Path>),
    // TODO: Figure out what the hell to do with these File variants. They don't work with Cow,
    // because they're not Clone/ToOwned.
    FileRef(&'a File),
    FileOwned(File),
}

impl<'a> OutputArg<'a> {
    fn update_handle(&self, parent_handle: pipe::Handle) -> io::Result<pipe::Handle> {
        let handle = match self {
            // Stdout and Stderr are no-ops here, but with_child_context interprets them. This is
            // because they refer to the *child's* stdout/stderr, with other redirections already
            // applied, rather than to the parent's.
            &OutputArg::Inherit | &OutputArg::Stdout | &OutputArg::Stderr => parent_handle,
            &OutputArg::Null => pipe::Handle::from_file(try!(File::create("/dev/null"))),  // TODO: Windows
            &OutputArg::Path(ref p) => pipe::Handle::from_file(try!(File::create(&p))),
            &OutputArg::FileRef(ref f) => pipe::Handle::dup_file(f),
            &OutputArg::FileOwned(ref f) => pipe::Handle::dup_file(f),
        };
        Ok(handle)
    }
}

// An IoContext represents the file descriptors child processes are talking to at execution time.
// It's initialized in run(), with dups of the stdin/stdout/stderr pipes, and then passed down to
// sub-expressions. Compound expressions will clone() it, and pipes/redirections will modify it
// according to their IoArgs.
#[derive(Clone, Debug)]
pub struct IoContext {
    stdin: pipe::Handle,
    stdout: pipe::Handle,
    stderr: pipe::Handle,
}

impl IoContext {
    fn new() -> IoContext {
        IoContext {
            stdin: pipe::Handle::stdin(),
            stdout: pipe::Handle::stdout(),
            stderr: pipe::Handle::stderr(),
        }
    }
}

fn pipe_with_reader_thread() -> (pipe::Handle, JoinHandle<io::Result<Vec<u8>>>) {
    let (read_pipe, write_pipe) = pipe::open_pipe();
    let thread = std::thread::spawn(move || {
        let mut read_file = read_pipe.to_file();
        let mut output = Vec::new();
        try!(read_file.read_to_end(&mut output));
        Ok(output)
    });
    (write_pipe, thread)
}

type WriterThreadJoiner = crossbeam::ScopedJoinHandle<io::Result<()>>;

fn pipe_with_writer_thread<'a>(input: &'a [u8],
                               scope: &crossbeam::Scope<'a>)
                               -> (pipe::Handle, WriterThreadJoiner) {
    let (read_pipe, write_pipe) = pipe::open_pipe();
    let thread = scope.spawn(move || {
        let mut write_file = write_pipe.to_file();
        try!(write_file.write_all(&input));
        Ok(())
    });
    (read_pipe, thread)
}

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

    use super::*;
    use std::borrow::Cow;
    use std::io::prelude::*;
    use std::io::SeekFrom;

    #[test]
    fn test_cmd() {
        let output = cmd(&["echo", "hi"]).read().unwrap();
        assert_eq!("hi", output);
    }

    #[test]
    fn test_sh() {
        let output = sh("echo hi").read().unwrap();
        assert_eq!("hi", output);
    }

    #[test]
    fn test_pipe() {
        let output = pipe(sh("echo hi"), sh("sed s/i/o/")).read().unwrap();
        assert_eq!("ho", output);
    }

    #[test]
    fn test_then() {
        let output = then(sh("echo -n hi"), sh("echo lo")).read().unwrap();
        assert_eq!("hilo", output);
    }

    #[test]
    fn test_input() {
        let mut expr = sh("sed s/f/g/");
        expr.stdin(InputArg::Bytes(Cow::Borrowed(b"foo")));
        let output = expr.read().unwrap();
        assert_eq!("goo", output);
    }

    #[test]
    fn test_null() {
        let mut expr = cmd(&["cat"]);
        expr.stdin(InputArg::Null);
        expr.stdout(OutputArg::Null);
        let output = expr.read().unwrap();
        assert_eq!("", output);
    }

    #[test]
    fn test_path() {
        let mut input_file = tempfile::NamedTempFile::new().unwrap();
        let mut output_file = tempfile::NamedTempFile::new().unwrap();
        println!("Here are the paths: {:?} {:?}",
                 input_file.path(),
                 output_file.path());
        input_file.write_all(b"foo").unwrap();
        let mut expr = sh("sed s/o/a/g");
        expr.stdin(InputArg::Path(Cow::Owned(input_file.path().to_owned())));
        expr.stdout(OutputArg::Path(Cow::Owned(output_file.path().to_owned())));
        let output = expr.read().unwrap();
        assert_eq!("", output);
        let mut file_output = String::new();
        output_file.read_to_string(&mut file_output).unwrap();
        assert_eq!("faa", file_output);
    }

    #[test]
    fn test_owned_input() {
        fn set_input(expr: &mut Expression) {
            let mystr = format!("I own this: {}", "foo");
            // This would be a lifetime error if we tried to use &mystr.
            expr.stdin(InputArg::Bytes(Cow::Owned(mystr.into_bytes())));
        }

        let mut c = cmd(&["cat"]);
        set_input(&mut c);
        let output = c.read().unwrap();
        assert_eq!("I own this: foo", output);
    }

    #[test]
    fn test_stderr_to_stdout() {
        let mut command = sh("echo hi >&2");
        command.stderr(OutputArg::Stdout);
        let output = command.read().unwrap();
        assert_eq!("hi", output);
    }

    #[test]
    fn test_file() {
        let mut temp = tempfile::NamedTempFile::new().unwrap();
        temp.write_all(b"example").unwrap();
        temp.seek(SeekFrom::Start(0)).unwrap();
        let mut expr = cmd(&["cat"]);
        expr.stdin(InputArg::FileRef(&temp));
        let output = expr.read().unwrap();
        assert_eq!(output, "example");
    }
}
<commit_msg>try switching from Cow to Box<Borrow<...>><commit_after>extern crate crossbeam;

use std::borrow::Borrow;
use std::ffi::{OsStr, OsString};
use std::fs::File;
use std::io;
use std::io::prelude::*;
use std::path::Path;
use std::process::{Command, Output, ExitStatus};
use std::thread::JoinHandle;

mod pipe;

pub fn cmd<T: AsRef<OsStr>>(argv: &[T]) -> Expression<'static> {
    let argv_vec = argv.iter().map(|arg| arg.as_ref().to_owned()).collect();
    Expression {
        inner: ExpressionInner::ArgvCommand(argv_vec),
        ioargs: IoArgs::new(),
    }
}

pub fn sh<T: AsRef<OsStr>>(command: T) -> Expression<'static> {
    Expression {
        inner: ExpressionInner::ShCommand(command.as_ref().to_owned()),
        ioargs: IoArgs::new(),
    }
}

pub fn pipe<'a>(left: Expression<'a>, right: Expression<'a>) -> Expression<'a> {
    Expression {
        inner: ExpressionInner::Pipe(Box::new(left), Box::new(right)),
        ioargs: IoArgs::new(),
    }
}

pub fn then<'a>(left: Expression<'a>, right: Expression<'a>) -> Expression<'a> {
    Expression {
        inner: ExpressionInner::Then(Box::new(left), Box::new(right)),
        ioargs: IoArgs::new(),
    }
}

pub struct Expression<'a> {
    inner: ExpressionInner<'a>,
    ioargs: IoArgs<'a>,
}

enum ExpressionInner<'a> {
    ArgvCommand(Vec<OsString>),
    ShCommand(OsString),
    Pipe(Box<Expression<'a>>, Box<Expression<'a>>),
    Then(Box<Expression<'a>>, Box<Expression<'a>>),
}

impl<'a> Expression<'a> {
    pub fn run(&self) -> Result<Output, Error> {
        unreachable!();
    }

    pub fn read(&self) -> Result<String, Error> {
        let (handle, reader) = pipe_with_reader_thread();
        let mut context = IoContext::new();
        context.stdout = handle;
        let status = try!(self.exec(context));
        let stdout_vec = try!(reader.join().unwrap());
        if !status.success() {
            return Err(Error::Status(Output {
                status: status,
                stdout: stdout_vec,
                stderr: Vec::new(),
            }));
        }
        let stdout_string = try!(std::str::from_utf8(&stdout_vec))
                                .trim_right_matches('\n')
                                .to_owned();
        Ok(stdout_string)
    }

    fn exec(&self, parent_context: IoContext) -> io::Result<ExitStatus> {
        self.ioargs.with_child_context(parent_context, |context| {
            match self.inner {
                ExpressionInner::ArgvCommand(ref argv) => exec_argv(argv, context),
                ExpressionInner::ShCommand(ref command) => exec_sh(command, context),
                ExpressionInner::Pipe(ref left, ref right) => exec_pipe(left, right, context),
                ExpressionInner::Then(ref left, ref right) => exec_then(left, right, context),
            }
        })
    }

    pub fn stdin(&mut self, arg: InputArg<'a>) -> &mut Self {
        self.ioargs.stdin = arg;
        self
    }

    pub fn stdout(&mut self, arg: OutputArg<'a>) -> &mut Self {
        self.ioargs.stdout = arg;
        self
    }

    pub fn stderr(&mut self, arg: OutputArg<'a>) -> &mut Self {
        self.ioargs.stderr = arg;
        self
    }
}

fn exec_argv(argv: &Vec<OsString>, context: IoContext) -> io::Result<ExitStatus> {
    let mut command = Command::new(&argv[0]);
    command.args(&argv[1..]);
    command.stdin(context.stdin.to_stdio());
    command.stdout(context.stdout.to_stdio());
    command.stderr(context.stderr.to_stdio());
    command.status()
}

fn exec_sh(command: &OsStr, context: IoContext) -> io::Result<ExitStatus> {
    // TODO: What shell should we be using here, really?
    // TODO: Figure out how cmd.exe works on Windows.
    let mut argv = Vec::new();
    argv.push("bash".into());
    argv.push("-c".into());
    argv.push(command.to_owned());
    exec_argv(&argv, context)
}

fn exec_pipe(left: &Expression, right: &Expression, context: IoContext) -> io::Result<ExitStatus> {
    let (read_pipe, write_pipe) = pipe::open_pipe();
    let left_context = IoContext {
        stdin: context.stdin,
        stdout: write_pipe,
        stderr: context.stderr.clone(),
    };
    let right_context = IoContext {
        stdin: read_pipe,
        stdout: context.stdout,
        stderr: context.stderr,
    };

    let (left_result, right_result) = crossbeam::scope(|scope| {
        let left_joiner = scope.spawn(|| left.exec(left_context));
        let right_result = right.exec(right_context);
        let left_result = left_joiner.join();
        (left_result, right_result)
    });

    let right_status = try!(right_result);
    let left_status = try!(left_result);
    if !right_status.success() {
        Ok(right_status)
    } else {
        Ok(left_status)
    }
}

fn exec_then(left: &Expression, right: &Expression, context: IoContext) -> io::Result<ExitStatus> {
    let status = try!(left.exec(context.clone()));
    if !status.success() {
        Ok(status)
    } else {
        right.exec(context)
    }
}

#[derive(Debug)]
pub enum Error {
    Io(io::Error),
    Utf8(std::str::Utf8Error),
    Status(Output),
}

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

impl From<std::str::Utf8Error> for Error {
    fn from(err: std::str::Utf8Error) -> Error {
        Error::Utf8(err)
    }
}

// IoArgs store the redirections and other settings associated with an expression. At execution
// time, IoArgs are used to modify an IoContext, which contains the actual pipes that child process
struct IoArgs<'a> {
    stdin: InputArg<'a>,
    stdout: OutputArg<'a>,
    stderr: OutputArg<'a>,
}

impl<'a> IoArgs<'a> {
    fn new() -> IoArgs<'static> {
        IoArgs {
            stdin: InputArg::Inherit,
            stdout: OutputArg::Inherit,
            stderr: OutputArg::Inherit,
        }
    }

    fn with_child_context<F, T>(&self, parent_context: IoContext, inner: F) -> io::Result<T>
        where F: FnOnce(IoContext) -> io::Result<T>
    {
        crossbeam::scope(|scope| {
            let parent_context = parent_context;  // move it into the closure
            let (stdin, maybe_stdin_thread) = try!(self.stdin
                                                       .update_handle(parent_context.stdin, scope));
            let stdout = try!(self.stdout.update_handle(parent_context.stdout));
            let stderr = try!(self.stderr.update_handle(parent_context.stderr));
            let (stdout, stderr) = apply_swaps(stdout, stderr, &self.stdout, &self.stderr);

            let child_context = IoContext {
                stdin: stdin,
                stdout: stdout,
                stderr: stderr,
            };

            let ret = try!(inner(child_context));

            if let Some(thread) = maybe_stdin_thread {
                try!(thread.join());
            }

            Ok(ret)
        })
    }
}

// returns (new_stdout, new_stderr)
fn apply_swaps(stdout_handle: pipe::Handle,
               stderr_handle: pipe::Handle,
               stdout_arg: &OutputArg,
               stderr_arg: &OutputArg)
               -> (pipe::Handle, pipe::Handle) {
    // TODO: These clones are a little excessive.
    let new_stdout = if let &OutputArg::Stderr = stdout_arg {
        stderr_handle.clone()
    } else {
        stdout_handle.clone()
    };
    let new_stderr = if let &OutputArg::Stdout = stderr_arg {
        stdout_handle.clone()
    } else {
        stderr_handle.clone()
    };
    (new_stdout, new_stderr)
}

pub enum InputArg<'a> {
    Inherit,
    Null,
    Path(Box<Borrow<Path> + Sync + 'a>),
    File(Box<Borrow<File> + Sync + 'a>),
    Bytes(Box<Borrow<[u8]> + Sync + 'a>),
}

impl<'a> InputArg<'a> {
    fn update_handle(&'a self,
                     parent_handle: pipe::Handle,
                     scope: &crossbeam::Scope<'a>)
                     -> io::Result<(pipe::Handle, Option<WriterThreadJoiner>)> {
        let mut maybe_thread = None;
        let handle = match self {
            &InputArg::Inherit => parent_handle,
            &InputArg::Null => pipe::Handle::from_file(try!(File::open("/dev/null"))),  // TODO: Windows
            &InputArg::Path(ref p) => pipe::Handle::from_file(try!(File::open((&**p).borrow()))),
            &InputArg::File(ref f) => pipe::Handle::dup_file((&**f).borrow()),
            &InputArg::Bytes(ref v) => {
                let (handle, thread) = pipe_with_writer_thread((&**v).borrow(), scope);
                maybe_thread = Some(thread);
                handle
            }
        };
        Ok((handle, maybe_thread))
    }
}

pub enum OutputArg<'a> {
    Inherit,
    Null,
    Stdout,
    Stderr,
    Path(Box<Borrow<Path> + Sync + 'a>),
    File(Box<Borrow<File> + Sync + 'a>),
}

impl<'a> OutputArg<'a> {
    fn update_handle(&self, parent_handle: pipe::Handle) -> io::Result<pipe::Handle> {
        let handle = match self {
            // Stdout and Stderr are no-ops here, but with_child_context interprets them. This is
            // because they refer to the *child's* stdout/stderr, with other redirections already
            // applied, rather than to the parent's.
            &OutputArg::Inherit | &OutputArg::Stdout | &OutputArg::Stderr => parent_handle,
            &OutputArg::Null => pipe::Handle::from_file(try!(File::create("/dev/null"))),  // TODO: Windows
            &OutputArg::Path(ref p) => pipe::Handle::from_file(try!(File::create((&**p).borrow()))),
            &OutputArg::File(ref f) => pipe::Handle::dup_file((&**f).borrow()),
        };
        Ok(handle)
    }
}

// An IoContext represents the file descriptors child processes are talking to at execution time.
// It's initialized in run(), with dups of the stdin/stdout/stderr pipes, and then passed down to
// sub-expressions. Compound expressions will clone() it, and pipes/redirections will modify it
// according to their IoArgs.
#[derive(Clone, Debug)]
pub struct IoContext {
    stdin: pipe::Handle,
    stdout: pipe::Handle,
    stderr: pipe::Handle,
}

impl IoContext {
    fn new() -> IoContext {
        IoContext {
            stdin: pipe::Handle::stdin(),
            stdout: pipe::Handle::stdout(),
            stderr: pipe::Handle::stderr(),
        }
    }
}

fn pipe_with_reader_thread() -> (pipe::Handle, JoinHandle<io::Result<Vec<u8>>>) {
    let (read_pipe, write_pipe) = pipe::open_pipe();
    let thread = std::thread::spawn(move || {
        let mut read_file = read_pipe.to_file();
        let mut output = Vec::new();
        try!(read_file.read_to_end(&mut output));
        Ok(output)
    });
    (write_pipe, thread)
}

type WriterThreadJoiner = crossbeam::ScopedJoinHandle<io::Result<()>>;

fn pipe_with_writer_thread<'a>(input: &'a [u8],
                               scope: &crossbeam::Scope<'a>)
                               -> (pipe::Handle, WriterThreadJoiner) {
    let (read_pipe, write_pipe) = pipe::open_pipe();
    let thread = scope.spawn(move || {
        let mut write_file = write_pipe.to_file();
        try!(write_file.write_all(&input));
        Ok(())
    });
    (read_pipe, thread)
}

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

    use super::*;
    use std::io::prelude::*;
    use std::io::SeekFrom;

    #[test]
    fn test_cmd() {
        let output = cmd(&["echo", "hi"]).read().unwrap();
        assert_eq!("hi", output);
    }

    #[test]
    fn test_sh() {
        let output = sh("echo hi").read().unwrap();
        assert_eq!("hi", output);
    }

    #[test]
    fn test_pipe() {
        let output = pipe(sh("echo hi"), sh("sed s/i/o/")).read().unwrap();
        assert_eq!("ho", output);
    }

    #[test]
    fn test_then() {
        let output = then(sh("echo -n hi"), sh("echo lo")).read().unwrap();
        assert_eq!("hilo", output);
    }

    #[test]
    fn test_input() {
        let mut expr = sh("sed s/f/g/");
        expr.stdin(InputArg::Bytes(Box::new(b"foo".as_ref())));
        let output = expr.read().unwrap();
        assert_eq!("goo", output);
    }

    #[test]
    fn test_null() {
        let mut expr = cmd(&["cat"]);
        expr.stdin(InputArg::Null);
        expr.stdout(OutputArg::Null);
        let output = expr.read().unwrap();
        assert_eq!("", output);
    }

    #[test]
    fn test_path() {
        let mut input_file = tempfile::NamedTempFile::new().unwrap();
        let mut output_file = tempfile::NamedTempFile::new().unwrap();
        println!("Here are the paths: {:?} {:?}",
                 input_file.path(),
                 output_file.path());
        input_file.write_all(b"foo").unwrap();
        let mut expr = sh("sed s/o/a/g");
        expr.stdin(InputArg::Path(Box::new(input_file.path().to_owned())));
        expr.stdout(OutputArg::Path(Box::new(output_file.path().to_owned())));
        let output = expr.read().unwrap();
        assert_eq!("", output);
        let mut file_output = String::new();
        output_file.read_to_string(&mut file_output).unwrap();
        assert_eq!("faa", file_output);
    }

    #[test]
    fn test_owned_input() {
        fn set_input(expr: &mut Expression) {
            let mystr = format!("I own this: {}", "foo");
            // This would be a lifetime error if we tried to use &mystr.
            expr.stdin(InputArg::Bytes(Box::new(mystr.into_bytes())));
        }

        let mut c = cmd(&["cat"]);
        set_input(&mut c);
        let output = c.read().unwrap();
        assert_eq!("I own this: foo", output);
    }

    #[test]
    fn test_stderr_to_stdout() {
        let mut command = sh("echo hi >&2");
        command.stderr(OutputArg::Stdout);
        let output = command.read().unwrap();
        assert_eq!("hi", output);
    }

    #[test]
    fn test_file() {
        let mut temp = tempfile::NamedTempFile::new().unwrap();
        temp.write_all(b"example").unwrap();
        temp.seek(SeekFrom::Start(0)).unwrap();
        let mut expr = cmd(&["cat"]);
        expr.stdin(InputArg::File(Box::new(&*temp)));
        let output = expr.read().unwrap();
        assert_eq!(output, "example");
    }
}
<|endoftext|>