<commit_before>// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! Standard library macros
//!
//! This modules contains a set of macros which are exported from the standard
//! library. Each macro is available for use when linking against the standard
//! library.

#[macro_escape];

/// The standard logging macro
///
/// This macro will generically log over a provided level (of type u32) with a
/// format!-based argument list. See documentation in `std::fmt` for details on
/// how to use the syntax, and documentation in `std::logging` for info about
/// logging macros.
///
/// # Example
///
/// ```
/// log!(::std::logging::DEBUG, "this is a debug message");
/// log!(::std::logging::WARN, "this is a warning {}", "message");
/// log!(6, "this is a custom logging level: {level}", level=6);
/// ```
#[macro_export]
macro_rules! log(
    ($lvl:expr, $($arg:tt)+) => ({
        let lvl = $lvl;
        if lvl <= __log_level() {
            format_args!(|args| {
                ::std::logging::log(lvl, args)
            }, $($arg)+)
        }
    })
)

/// A convenience macro for logging at the error log level. See `std::logging`
/// for more information. about logging.
///
/// # Example
///
/// ```
/// # let error = 3;
/// error!("the build has failed with error code: {}", error);
/// ```
#[macro_export]
macro_rules! error(
    ($($arg:tt)*) => (log!(1u32, $($arg)*))
)

/// A convenience macro for logging at the warning log level. See `std::logging`
/// for more information. about logging.
///
/// # Example
///
/// ```
/// # let code = 3;
/// warn!("you may like to know that a process exited with: {}", code);
/// ```
#[macro_export]
macro_rules! warn(
    ($($arg:tt)*) => (log!(2u32, $($arg)*))
)

/// A convenience macro for logging at the info log level. See `std::logging`
/// for more information. about logging.
///
/// # Example
///
/// ```
/// # let ret = 3;
/// info!("this function is about to return: {}", ret);
/// ```
#[macro_export]
macro_rules! info(
    ($($arg:tt)*) => (log!(3u32, $($arg)*))
)

/// A convenience macro for logging at the debug log level. See `std::logging`
/// for more information. about logging.
///
/// # Example
///
/// ```
/// debug!("x = {x}, y = {y}", x=10, y=20);
/// ```
#[macro_export]
macro_rules! debug(
    ($($arg:tt)*) => (if cfg!(not(ndebug)) { log!(4u32, $($arg)*) })
)

/// A macro to test whether a log level is enabled for the current module.
///
/// # Example
///
/// ```
/// # struct Point { x: int, y: int }
/// # fn some_expensive_computation() -> Point { Point { x: 1, y: 2 } }
/// if log_enabled!(std::logging::DEBUG) {
///     let x = some_expensive_computation();
///     debug!("x.x = {}, x.y = {}", x.x, x.y);
/// }
/// ```
#[macro_export]
macro_rules! log_enabled(
    ($lvl:expr) => ({
        let lvl = $lvl;
        lvl <= __log_level() && (lvl != 4 || cfg!(not(ndebug)))
    })
)

/// The entry point for failure of rust tasks.
///
/// This macro is used to inject failure into a rust task, causing the task to
/// unwind and fail entirely. Each task's failure can be reaped as the `~Any`
/// type, and the single-argument form of the `fail!` macro will be the value
/// which is transmitted.
///
/// The multi-argument form of this macro fails with a string and has the
/// `format!` sytnax for building a string.
///
/// # Example
///
/// ```should_fail
/// # #[allow(unreachable_code)];
/// fail!();
/// fail!("this is a terrible mistake!");
/// fail!(4); // fail with the value of 4 to be collected elsewhere
/// fail!("this is a {} {message}", "fancy", message = "message");
/// ```
#[macro_export]
macro_rules! fail(
    () => (
        fail!("explicit failure")
    );
    ($msg:expr) => (
        ::std::rt::begin_unwind($msg, file!(), line!())
    );
    ($fmt:expr, $($arg:tt)*) => ({
        // a closure can't have return type !, so we need a full
        // function to pass to format_args!, *and* we need the
        // file and line numbers right here; so an inner bare fn
        // is our only choice.
        //
        // LLVM doesn't tend to inline this, presumably because begin_unwind_fmt
        // is #[cold] and #[inline(never)] and because this is flagged as cold
        // as returning !. We really do want this to be inlined, however,
        // because it's just a tiny wrapper. Small wins (156K to 149K in size)
        // were seen when forcing this to be inlined, and that number just goes
        // up with the number of calls to fail!()
        #[inline(always)]
        fn run_fmt(fmt: &::std::fmt::Arguments) -> ! {
            ::std::rt::begin_unwind_fmt(fmt, file!(), line!())
        }
        format_args!(run_fmt, $fmt, $($arg)*)
    });
)

/// Ensure that a boolean expression is `true` at runtime.
///
/// This will invoke the `fail!` macro if the provided expression cannot be
/// evaluated to `true` at runtime.
///
/// # Example
///
/// ```
/// // the failure message for these assertions is the stringified value of the
/// // expression given.
/// assert!(true);
/// # fn some_computation() -> bool { true }
/// assert!(some_computation());
///
/// // assert with a custom message
/// # let x = true;
/// assert!(x, "x wasn't true!");
/// # let a = 3; let b = 27;
/// assert!(a + b == 30, "a = {}, b = {}", a, b);
/// ```
#[macro_export]
macro_rules! assert(
    ($cond:expr) => (
        if !$cond {
            fail!("assertion failed: {:s}", stringify!($cond))
        }
    );
    ($cond:expr, $msg:expr) => (
        if !$cond {
            fail!($msg)
        }
    );
    ($cond:expr, $($arg:expr),+) => (
        if !$cond {
            fail!($($arg),+)
        }
    );
)

/// Asserts that two expressions are equal to each other, testing equality in
/// both directions.
///
/// On failure, this macro will print the values of the expressions.
///
/// # Example
///
/// ```
/// let a = 3;
/// let b = 1 + 2;
/// assert_eq!(a, b);
/// ```
#[macro_export]
macro_rules! assert_eq(
    ($given:expr , $expected:expr) => ({
        let given_val = &($given);
        let expected_val = &($expected);
        // check both directions of equality....
        if !((*given_val == *expected_val) &&
             (*expected_val == *given_val)) {
            fail!("assertion failed: `(left == right) && (right == left)` \
                   (left: `{}`, right: `{}`)", *given_val, *expected_val)
        }
    })
)

/// A utility macro for indicating unreachable code. It will fail if
/// executed. This is occasionally useful to put after loops that never
/// terminate normally, but instead directly return from a function.
///
/// # Example
///
/// ~~~rust
/// struct Item { weight: uint }
///
/// fn choose_weighted_item(v: &[Item]) -> Item {
///     assert!(!v.is_empty());
///     let mut so_far = 0u;
///     for item in v.iter() {
///         so_far += item.weight;
///         if so_far > 100 {
///             return *item;
///         }
///     }
///     // The above loop always returns, so we must hint to the
///     // type checker that it isn't possible to get down here
///     unreachable!();
/// }
/// ~~~
#[macro_export]
macro_rules! unreachable(
    () => (fail!("internal error: entered unreachable code"))
)

/// A standardised placeholder for marking unfinished code. It fails with the
/// message `"not yet implemented"` when executed.
#[macro_export]
macro_rules! unimplemented(
    () => (fail!("not yet implemented"))
)

/// Use the syntax described in `std::fmt` to create a value of type `~str`.
/// See `std::fmt` for more information.
///
/// # Example
///
/// ```
/// format!("test");
/// format!("hello {}", "world!");
/// format!("x = {}, y = {y}", 10, y = 30);
/// ```
#[macro_export]
macro_rules! format(
    ($($arg:tt)*) => (
        format_args!(::std::fmt::format, $($arg)*)
    )
)

/// Use the `format!` syntax to write data into a buffer of type `&mut Writer`.
/// See `std::fmt` for more information.
///
/// # Example
///
/// ```
/// # #[allow(unused_must_use)];
/// use std::io::MemWriter;
///
/// let mut w = MemWriter::new();
/// write!(&mut w, "test");
/// write!(&mut w, "formatted {}", "arguments");
/// ```
#[macro_export]
macro_rules! write(
    ($dst:expr, $($arg:tt)*) => ({
        let dst: &mut ::std::io::Writer = $dst;
        format_args!(|args| { ::std::fmt::write(dst, args) }, $($arg)*)
    })
)

/// Equivalent to the `write!` macro, except that a newline is appended after
/// the message is written.
#[macro_export]
macro_rules! writeln(
    ($dst:expr, $($arg:tt)*) => ({
        let dst: &mut ::std::io::Writer = $dst;
        format_args!(|args| { ::std::fmt::writeln(dst, args) }, $($arg)*)
    })
)

/// Equivalent to the `println!` macro except that a newline is not printed at
/// the end of the message.
#[macro_export]
macro_rules! print(
    ($($arg:tt)*) => (format_args!(::std::io::stdio::print_args, $($arg)*))
)

/// Macro for printing to a task's stdout handle.
///
/// Each task can override its stdout handle via `std::io::stdio::set_stdout`.
/// The syntax of this macro is the same as that used for `format!`. For more
/// information, see `std::fmt` and `std::io::stdio`.
///
/// # Example
///
/// ```
/// println!("hello there!");
/// println!("format {} arguments", "some");
/// ```
#[macro_export]
macro_rules! println(
    ($($arg:tt)*) => (format_args!(::std::io::stdio::println_args, $($arg)*))
)

/// Declare a task-local key with a specific type.
///
/// # Example
///
/// ```
/// use std::local_data;
///
/// local_data_key!(my_integer: int)
///
/// local_data::set(my_integer, 2);
/// local_data::get(my_integer, |val| println!("{}", val.map(|i| *i)));
/// ```
#[macro_export]
macro_rules! local_data_key(
    ($name:ident: $ty:ty) => (
        static $name: ::std::local_data::Key<$ty> = &::std::local_data::Key;
    );
    (pub $name:ident: $ty:ty) => (
        pub static $name: ::std::local_data::Key<$ty> = &::std::local_data::Key;
    );
)

/// Helper macro for unwrapping `Result` values while returning early with an
/// error if the value of the expression is `Err`. For more information, see
/// `std::io`.
#[macro_export]
macro_rules! try(
    ($e:expr) => (match $e { Ok(e) => e, Err(e) => return Err(e) })
)

#[macro_export]
macro_rules! vec(
    ($($e:expr),*) => ({
        let mut temp = ::std::vec_ng::Vec::new();
        $(temp.push($e);)*
        temp
    })
)

/// A macro to select an event from a number of ports.
///
/// This macro is used to wait for the first event to occur on a number of
/// ports. It places no restrictions on the types of ports given to this macro,
/// this can be viewed as a heterogeneous select.
///
/// # Example
///
/// ```
/// let (p1, c1) = Chan::new();
/// let (p2, c2) = Chan::new();
/// # fn long_running_task() {}
/// # fn calculate_the_answer() -> int { 42 }
///
/// spawn(proc() { long_running_task(); c1.send(()) });
/// spawn(proc() { c2.send(calculate_the_answer()) });
///
/// select! (
///     () = p1.recv() => println!("the long running task finished first"),
///     answer = p2.recv() => {
///         println!("the answer was: {}", answer);
///     }
/// )
/// ```
///
/// For more information about select, see the `std::comm::Select` structure.
#[macro_export]
#[experimental]
macro_rules! select {
    (
        $($name:pat = $port:ident.$meth:ident() => $code:expr),+
    ) => ({
        use std::comm::Select;
        let sel = Select::new();
        $( let mut $port = sel.handle(&$port); )+
        unsafe {
            $( $port.add(); )+
        }
        let ret = sel.wait();
        $( if ret == $port.id() { let $name = $port.$meth(); $code } else )+
        { unreachable!() }
    })
}
<commit_msg>std: stop `vec!()` warning about unused mutability.<commit_after>// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! Standard library macros
//!
//! This modules contains a set of macros which are exported from the standard
//! library. Each macro is available for use when linking against the standard
//! library.

#[macro_escape];

/// The standard logging macro
///
/// This macro will generically log over a provided level (of type u32) with a
/// format!-based argument list. See documentation in `std::fmt` for details on
/// how to use the syntax, and documentation in `std::logging` for info about
/// logging macros.
///
/// # Example
///
/// ```
/// log!(::std::logging::DEBUG, "this is a debug message");
/// log!(::std::logging::WARN, "this is a warning {}", "message");
/// log!(6, "this is a custom logging level: {level}", level=6);
/// ```
#[macro_export]
macro_rules! log(
    ($lvl:expr, $($arg:tt)+) => ({
        let lvl = $lvl;
        if lvl <= __log_level() {
            format_args!(|args| {
                ::std::logging::log(lvl, args)
            }, $($arg)+)
        }
    })
)

/// A convenience macro for logging at the error log level. See `std::logging`
/// for more information. about logging.
///
/// # Example
///
/// ```
/// # let error = 3;
/// error!("the build has failed with error code: {}", error);
/// ```
#[macro_export]
macro_rules! error(
    ($($arg:tt)*) => (log!(1u32, $($arg)*))
)

/// A convenience macro for logging at the warning log level. See `std::logging`
/// for more information. about logging.
///
/// # Example
///
/// ```
/// # let code = 3;
/// warn!("you may like to know that a process exited with: {}", code);
/// ```
#[macro_export]
macro_rules! warn(
    ($($arg:tt)*) => (log!(2u32, $($arg)*))
)

/// A convenience macro for logging at the info log level. See `std::logging`
/// for more information. about logging.
///
/// # Example
///
/// ```
/// # let ret = 3;
/// info!("this function is about to return: {}", ret);
/// ```
#[macro_export]
macro_rules! info(
    ($($arg:tt)*) => (log!(3u32, $($arg)*))
)

/// A convenience macro for logging at the debug log level. See `std::logging`
/// for more information. about logging.
///
/// # Example
///
/// ```
/// debug!("x = {x}, y = {y}", x=10, y=20);
/// ```
#[macro_export]
macro_rules! debug(
    ($($arg:tt)*) => (if cfg!(not(ndebug)) { log!(4u32, $($arg)*) })
)

/// A macro to test whether a log level is enabled for the current module.
///
/// # Example
///
/// ```
/// # struct Point { x: int, y: int }
/// # fn some_expensive_computation() -> Point { Point { x: 1, y: 2 } }
/// if log_enabled!(std::logging::DEBUG) {
///     let x = some_expensive_computation();
///     debug!("x.x = {}, x.y = {}", x.x, x.y);
/// }
/// ```
#[macro_export]
macro_rules! log_enabled(
    ($lvl:expr) => ({
        let lvl = $lvl;
        lvl <= __log_level() && (lvl != 4 || cfg!(not(ndebug)))
    })
)

/// The entry point for failure of rust tasks.
///
/// This macro is used to inject failure into a rust task, causing the task to
/// unwind and fail entirely. Each task's failure can be reaped as the `~Any`
/// type, and the single-argument form of the `fail!` macro will be the value
/// which is transmitted.
///
/// The multi-argument form of this macro fails with a string and has the
/// `format!` sytnax for building a string.
///
/// # Example
///
/// ```should_fail
/// # #[allow(unreachable_code)];
/// fail!();
/// fail!("this is a terrible mistake!");
/// fail!(4); // fail with the value of 4 to be collected elsewhere
/// fail!("this is a {} {message}", "fancy", message = "message");
/// ```
#[macro_export]
macro_rules! fail(
    () => (
        fail!("explicit failure")
    );
    ($msg:expr) => (
        ::std::rt::begin_unwind($msg, file!(), line!())
    );
    ($fmt:expr, $($arg:tt)*) => ({
        // a closure can't have return type !, so we need a full
        // function to pass to format_args!, *and* we need the
        // file and line numbers right here; so an inner bare fn
        // is our only choice.
        //
        // LLVM doesn't tend to inline this, presumably because begin_unwind_fmt
        // is #[cold] and #[inline(never)] and because this is flagged as cold
        // as returning !. We really do want this to be inlined, however,
        // because it's just a tiny wrapper. Small wins (156K to 149K in size)
        // were seen when forcing this to be inlined, and that number just goes
        // up with the number of calls to fail!()
        #[inline(always)]
        fn run_fmt(fmt: &::std::fmt::Arguments) -> ! {
            ::std::rt::begin_unwind_fmt(fmt, file!(), line!())
        }
        format_args!(run_fmt, $fmt, $($arg)*)
    });
)

/// Ensure that a boolean expression is `true` at runtime.
///
/// This will invoke the `fail!` macro if the provided expression cannot be
/// evaluated to `true` at runtime.
///
/// # Example
///
/// ```
/// // the failure message for these assertions is the stringified value of the
/// // expression given.
/// assert!(true);
/// # fn some_computation() -> bool { true }
/// assert!(some_computation());
///
/// // assert with a custom message
/// # let x = true;
/// assert!(x, "x wasn't true!");
/// # let a = 3; let b = 27;
/// assert!(a + b == 30, "a = {}, b = {}", a, b);
/// ```
#[macro_export]
macro_rules! assert(
    ($cond:expr) => (
        if !$cond {
            fail!("assertion failed: {:s}", stringify!($cond))
        }
    );
    ($cond:expr, $msg:expr) => (
        if !$cond {
            fail!($msg)
        }
    );
    ($cond:expr, $($arg:expr),+) => (
        if !$cond {
            fail!($($arg),+)
        }
    );
)

/// Asserts that two expressions are equal to each other, testing equality in
/// both directions.
///
/// On failure, this macro will print the values of the expressions.
///
/// # Example
///
/// ```
/// let a = 3;
/// let b = 1 + 2;
/// assert_eq!(a, b);
/// ```
#[macro_export]
macro_rules! assert_eq(
    ($given:expr , $expected:expr) => ({
        let given_val = &($given);
        let expected_val = &($expected);
        // check both directions of equality....
        if !((*given_val == *expected_val) &&
             (*expected_val == *given_val)) {
            fail!("assertion failed: `(left == right) && (right == left)` \
                   (left: `{}`, right: `{}`)", *given_val, *expected_val)
        }
    })
)

/// A utility macro for indicating unreachable code. It will fail if
/// executed. This is occasionally useful to put after loops that never
/// terminate normally, but instead directly return from a function.
///
/// # Example
///
/// ~~~rust
/// struct Item { weight: uint }
///
/// fn choose_weighted_item(v: &[Item]) -> Item {
///     assert!(!v.is_empty());
///     let mut so_far = 0u;
///     for item in v.iter() {
///         so_far += item.weight;
///         if so_far > 100 {
///             return *item;
///         }
///     }
///     // The above loop always returns, so we must hint to the
///     // type checker that it isn't possible to get down here
///     unreachable!();
/// }
/// ~~~
#[macro_export]
macro_rules! unreachable(
    () => (fail!("internal error: entered unreachable code"))
)

/// A standardised placeholder for marking unfinished code. It fails with the
/// message `"not yet implemented"` when executed.
#[macro_export]
macro_rules! unimplemented(
    () => (fail!("not yet implemented"))
)

/// Use the syntax described in `std::fmt` to create a value of type `~str`.
/// See `std::fmt` for more information.
///
/// # Example
///
/// ```
/// format!("test");
/// format!("hello {}", "world!");
/// format!("x = {}, y = {y}", 10, y = 30);
/// ```
#[macro_export]
macro_rules! format(
    ($($arg:tt)*) => (
        format_args!(::std::fmt::format, $($arg)*)
    )
)

/// Use the `format!` syntax to write data into a buffer of type `&mut Writer`.
/// See `std::fmt` for more information.
///
/// # Example
///
/// ```
/// # #[allow(unused_must_use)];
/// use std::io::MemWriter;
///
/// let mut w = MemWriter::new();
/// write!(&mut w, "test");
/// write!(&mut w, "formatted {}", "arguments");
/// ```
#[macro_export]
macro_rules! write(
    ($dst:expr, $($arg:tt)*) => ({
        let dst: &mut ::std::io::Writer = $dst;
        format_args!(|args| { ::std::fmt::write(dst, args) }, $($arg)*)
    })
)

/// Equivalent to the `write!` macro, except that a newline is appended after
/// the message is written.
#[macro_export]
macro_rules! writeln(
    ($dst:expr, $($arg:tt)*) => ({
        let dst: &mut ::std::io::Writer = $dst;
        format_args!(|args| { ::std::fmt::writeln(dst, args) }, $($arg)*)
    })
)

/// Equivalent to the `println!` macro except that a newline is not printed at
/// the end of the message.
#[macro_export]
macro_rules! print(
    ($($arg:tt)*) => (format_args!(::std::io::stdio::print_args, $($arg)*))
)

/// Macro for printing to a task's stdout handle.
///
/// Each task can override its stdout handle via `std::io::stdio::set_stdout`.
/// The syntax of this macro is the same as that used for `format!`. For more
/// information, see `std::fmt` and `std::io::stdio`.
///
/// # Example
///
/// ```
/// println!("hello there!");
/// println!("format {} arguments", "some");
/// ```
#[macro_export]
macro_rules! println(
    ($($arg:tt)*) => (format_args!(::std::io::stdio::println_args, $($arg)*))
)

/// Declare a task-local key with a specific type.
///
/// # Example
///
/// ```
/// use std::local_data;
///
/// local_data_key!(my_integer: int)
///
/// local_data::set(my_integer, 2);
/// local_data::get(my_integer, |val| println!("{}", val.map(|i| *i)));
/// ```
#[macro_export]
macro_rules! local_data_key(
    ($name:ident: $ty:ty) => (
        static $name: ::std::local_data::Key<$ty> = &::std::local_data::Key;
    );
    (pub $name:ident: $ty:ty) => (
        pub static $name: ::std::local_data::Key<$ty> = &::std::local_data::Key;
    );
)

/// Helper macro for unwrapping `Result` values while returning early with an
/// error if the value of the expression is `Err`. For more information, see
/// `std::io`.
#[macro_export]
macro_rules! try(
    ($e:expr) => (match $e { Ok(e) => e, Err(e) => return Err(e) })
)

/// Create a `std::vec_ng::Vec` containing the arguments.
#[macro_export]
macro_rules! vec(
    ($($e:expr),*) => ({
        // leading _ to allow empty construction without a warning.
        let mut _temp = ::std::vec_ng::Vec::new();
        $(_temp.push($e);)*
        _temp
    })
)

/// A macro to select an event from a number of ports.
///
/// This macro is used to wait for the first event to occur on a number of
/// ports. It places no restrictions on the types of ports given to this macro,
/// this can be viewed as a heterogeneous select.
///
/// # Example
///
/// ```
/// let (p1, c1) = Chan::new();
/// let (p2, c2) = Chan::new();
/// # fn long_running_task() {}
/// # fn calculate_the_answer() -> int { 42 }
///
/// spawn(proc() { long_running_task(); c1.send(()) });
/// spawn(proc() { c2.send(calculate_the_answer()) });
///
/// select! (
///     () = p1.recv() => println!("the long running task finished first"),
///     answer = p2.recv() => {
///         println!("the answer was: {}", answer);
///     }
/// )
/// ```
///
/// For more information about select, see the `std::comm::Select` structure.
#[macro_export]
#[experimental]
macro_rules! select {
    (
        $($name:pat = $port:ident.$meth:ident() => $code:expr),+
    ) => ({
        use std::comm::Select;
        let sel = Select::new();
        $( let mut $port = sel.handle(&$port); )+
        unsafe {
            $( $port.add(); )+
        }
        let ret = sel.wait();
        $( if ret == $port.id() { let $name = $port.$meth(); $code } else )+
        { unreachable!() }
    })
}
<|endoftext|>


<commit_before>use protocol::*;
use protocol::basic::gen_properties;
use types::*;
use types::generation::*;

use cookie_factory::GenError;

pub fn gen_protocol_header(x: (&mut [u8], usize)) -> Result<(&mut [u8], usize), GenError> {
    do_gen!(x,
        gen_slice!(metadata::NAME.as_bytes()) >>
        gen_slice!(&[0, metadata::MAJOR_VERSION, metadata::MINOR_VERSION, metadata::REVISION])
    )
}

pub fn gen_heartbeat_frame(x: (&mut [u8], usize)) -> Result<(&mut [u8], usize), GenError> {
    do_gen!(x, gen_slice!(&[constants::FRAME_HEARTBEAT, 0, 0, 0, 0, 0, 0, constants::FRAME_END]))
}

pub fn gen_method_frame<'a>(x:(&'a mut [u8], usize), channel_id: ShortUInt, class: &AMQPClass) -> Result<(&'a mut [u8], usize), GenError> {
    do_gen!(x,
        gen_short_short_uint(&constants::FRAME_METHOD)                          >>
        gen_id(&channel_id)                                                     >>
        len:   gen_skip!(4)                                                     >>
        start: gen_class(class)                                                 >>
        end:   gen_at_offset!(len, gen_long_uint(&((end - start) as LongUInt))) >>
        gen_short_short_uint(&constants::FRAME_END)
    )
}

pub fn gen_content_header_frame<'a>(x: (&'a mut [u8], usize), channel_id: ShortUInt, class_id: ShortUInt, length: LongLongUInt, properties: &basic::AMQPProperties) -> Result<(&'a mut [u8], usize), GenError> {
    do_gen!(x,
        gen_short_short_uint(&constants::FRAME_HEADER)                          >>
        gen_id(&channel_id)                                                     >>
        len:   gen_skip!(4)                                                     >>
        start: do_gen!(
            gen_id(&class_id)           >>
            gen_short_uint(&0)          >> // weight
            gen_long_long_uint(&length) >>
            gen_properties(&properties)
        ) >>
        end:   gen_at_offset!(len, gen_long_uint(&((end - start) as LongUInt))) >>
        gen_short_short_uint(&constants::FRAME_END)
   )
}

pub fn gen_content_body_frame<'a>(x: (&'a mut [u8], usize), channel_id: ShortUInt, content: &[u8]) -> Result<(&'a mut [u8], usize), GenError> {
    do_gen!(x,
        gen_short_short_uint(&constants::FRAME_BODY) >>
        gen_id(&channel_id)                          >>
        gen_long_uint(&(content.len() as LongUInt))  >>
        gen_slice!(content)                          >>
        gen_short_short_uint(&constants::FRAME_END)
    )
}
<commit_msg>protocol: add gen_frame<commit_after>use frame::AMQPFrame;
use protocol::*;
use protocol::basic::gen_properties;
use types::*;
use types::generation::*;

use cookie_factory::GenError;

pub fn gen_frame<'a, 'b>(x: (&'a mut [u8], usize), frame: &'b AMQPFrame) -> Result<(&'a mut [u8], usize), GenError> {
    match frame {
        AMQPFrame::ProtocolHeader => {
            gen_protocol_header(x)
        },
        AMQPFrame::Heartbeat(_) => {
            gen_heartbeat_frame(x)
        },
        AMQPFrame::Method(channel_id, method) => {
            gen_method_frame(x, *channel_id, method)
        },
        AMQPFrame::Header(channel_id, class_id, header) => {
            gen_content_header_frame(x, *channel_id, *class_id, header.body_size, &header.properties)
        },
        AMQPFrame::Body(channel_id, data) => {
            gen_content_body_frame(x, *channel_id, data)
        }
    }
}

pub fn gen_protocol_header(x: (&mut [u8], usize)) -> Result<(&mut [u8], usize), GenError> {
    do_gen!(x,
        gen_slice!(metadata::NAME.as_bytes()) >>
        gen_slice!(&[0, metadata::MAJOR_VERSION, metadata::MINOR_VERSION, metadata::REVISION])
    )
}

pub fn gen_heartbeat_frame(x: (&mut [u8], usize)) -> Result<(&mut [u8], usize), GenError> {
    do_gen!(x, gen_slice!(&[constants::FRAME_HEARTBEAT, 0, 0, 0, 0, 0, 0, constants::FRAME_END]))
}

pub fn gen_method_frame<'a>(x:(&'a mut [u8], usize), channel_id: ShortUInt, class: &AMQPClass) -> Result<(&'a mut [u8], usize), GenError> {
    do_gen!(x,
        gen_short_short_uint(&constants::FRAME_METHOD)                          >>
        gen_id(&channel_id)                                                     >>
        len:   gen_skip!(4)                                                     >>
        start: gen_class(class)                                                 >>
        end:   gen_at_offset!(len, gen_long_uint(&((end - start) as LongUInt))) >>
        gen_short_short_uint(&constants::FRAME_END)
    )
}

pub fn gen_content_header_frame<'a>(x: (&'a mut [u8], usize), channel_id: ShortUInt, class_id: ShortUInt, length: LongLongUInt, properties: &basic::AMQPProperties) -> Result<(&'a mut [u8], usize), GenError> {
    do_gen!(x,
        gen_short_short_uint(&constants::FRAME_HEADER)                          >>
        gen_id(&channel_id)                                                     >>
        len:   gen_skip!(4)                                                     >>
        start: do_gen!(
            gen_id(&class_id)           >>
            gen_short_uint(&0)          >> // weight
            gen_long_long_uint(&length) >>
            gen_properties(&properties)
        ) >>
        end:   gen_at_offset!(len, gen_long_uint(&((end - start) as LongUInt))) >>
        gen_short_short_uint(&constants::FRAME_END)
   )
}

pub fn gen_content_body_frame<'a>(x: (&'a mut [u8], usize), channel_id: ShortUInt, content: &[u8]) -> Result<(&'a mut [u8], usize), GenError> {
    do_gen!(x,
        gen_short_short_uint(&constants::FRAME_BODY) >>
        gen_id(&channel_id)                          >>
        gen_long_uint(&(content.len() as LongUInt))  >>
        gen_slice!(content)                          >>
        gen_short_short_uint(&constants::FRAME_END)
    )
}
<|endoftext|>


<commit_before>use super::{infer, type_at, type_at_pos};
use crate::test_db::TestDB;
use insta::assert_snapshot;
use ra_db::fixture::WithFixture;

#[test]
fn cfg_impl_def() {
    let (db, pos) = TestDB::with_position(
        r#"
//- /main.rs crate:main deps:foo cfg:test
use foo::S as T;
struct S;

#[cfg(test)]
impl S {
    fn foo1(&self) -> i32 { 0 }
}

#[cfg(not(test))]
impl S {
    fn foo2(&self) -> i32 { 0 }
}

fn test() {
    let t = (S.foo1(), S.foo2(), T.foo3(), T.foo4());
    t<|>;
}

//- /foo.rs crate:foo
struct S;

#[cfg(not(test))]
impl S {
    fn foo3(&self) -> i32 { 0 }
}

#[cfg(test)]
impl S {
    fn foo4(&self) -> i32 { 0 }
}
"#,
    );
    assert_eq!("(i32, {unknown}, i32, {unknown})", type_at_pos(&db, pos));
}

#[test]
fn infer_macros_expanded() {
    assert_snapshot!(
        infer(r#"
struct Foo(Vec<i32>);

macro_rules! foo {
    ($($item:expr),*) => {
            {
                Foo(vec![$($item,)*])
            }
    };
}

fn main() {
    let x = foo!(1,2);
}
"#),
        @r###"
    ![0; 17) '{Foo(v...,2,])}': Foo
    ![1; 4) 'Foo': Foo({unknown}) -> Foo
    ![1; 16) 'Foo(vec![1,2,])': Foo
    ![5; 15) 'vec![1,2,]': {unknown}
    [156; 182) '{     ...,2); }': ()
    [166; 167) 'x': Foo
    "###
    );
}

#[test]
fn infer_legacy_textual_scoped_macros_expanded() {
    assert_snapshot!(
        infer(r#"
struct Foo(Vec<i32>);

#[macro_use]
mod m {
    macro_rules! foo {
        ($($item:expr),*) => {
            {
                Foo(vec![$($item,)*])
            }
        };
    }
}

fn main() {
    let x = foo!(1,2);
    let y = crate::foo!(1,2);
}
"#),
        @r###"
    ![0; 17) '{Foo(v...,2,])}': Foo
    ![1; 4) 'Foo': Foo({unknown}) -> Foo
    ![1; 16) 'Foo(vec![1,2,])': Foo
    ![5; 15) 'vec![1,2,]': {unknown}
    [195; 251) '{     ...,2); }': ()
    [205; 206) 'x': Foo
    [228; 229) 'y': {unknown}
    [232; 248) 'crate:...!(1,2)': {unknown}
    "###
    );
}

#[test]
fn infer_path_qualified_macros_expanded() {
    assert_snapshot!(
        infer(r#"
#[macro_export]
macro_rules! foo {
    () => { 42i32 }
}

mod m {
    pub use super::foo as bar;
}

fn main() {
    let x = crate::foo!();
    let y = m::bar!();
}
"#),
        @r###"
    ![0; 5) '42i32': i32
    ![0; 5) '42i32': i32
    [111; 164) '{     ...!(); }': ()
    [121; 122) 'x': i32
    [148; 149) 'y': i32
    "###
    );
}

#[test]
fn expr_macro_expanded_in_various_places() {
    assert_snapshot!(
        infer(r#"
macro_rules! spam {
    () => (1isize);
}

fn spam() {
    spam!();
    (spam!());
    spam!().spam(spam!());
    for _ in spam!() {}
    || spam!();
    while spam!() {}
    break spam!();
    return spam!();
    match spam!() {
        _ if spam!() => spam!(),
    }
    spam!()(spam!());
    Spam { spam: spam!() };
    spam!()[spam!()];
    await spam!();
    spam!() as usize;
    &spam!();
    -spam!();
    spam!()..spam!();
    spam!() + spam!();
}
"#),
        @r###"
    ![0; 6) '1isize': isize
    ![0; 6) '1isize': isize
    ![0; 6) '1isize': isize
    ![0; 6) '1isize': isize
    ![0; 6) '1isize': isize
    ![0; 6) '1isize': isize
    ![0; 6) '1isize': isize
    ![0; 6) '1isize': isize
    ![0; 6) '1isize': isize
    ![0; 6) '1isize': isize
    ![0; 6) '1isize': isize
    ![0; 6) '1isize': isize
    ![0; 6) '1isize': isize
    ![0; 6) '1isize': isize
    ![0; 6) '1isize': isize
    ![0; 6) '1isize': isize
    ![0; 6) '1isize': isize
    ![0; 6) '1isize': isize
    ![0; 6) '1isize': isize
    ![0; 6) '1isize': isize
    ![0; 6) '1isize': isize
    ![0; 6) '1isize': isize
    ![0; 6) '1isize': isize
    ![0; 6) '1isize': isize
    ![0; 6) '1isize': isize
    [54; 457) '{     ...!(); }': !
    [88; 109) 'spam!(...am!())': {unknown}
    [115; 134) 'for _ ...!() {}': ()
    [119; 120) '_': {unknown}
    [132; 134) '{}': ()
    [139; 149) '|| spam!()': || -> isize
    [155; 171) 'while ...!() {}': ()
    [169; 171) '{}': ()
    [176; 189) 'break spam!()': !
    [195; 209) 'return spam!()': !
    [215; 269) 'match ...     }': isize
    [239; 240) '_': isize
    [274; 290) 'spam!(...am!())': {unknown}
    [296; 318) 'Spam {...m!() }': {unknown}
    [324; 340) 'spam!(...am!()]': {unknown}
    [365; 381) 'spam!(... usize': usize
    [387; 395) '&spam!()': &isize
    [401; 409) '-spam!()': isize
    [415; 431) 'spam!(...pam!()': {unknown}
    [437; 454) 'spam!(...pam!()': isize
    "###
    );
}

#[test]
fn infer_type_value_macro_having_same_name() {
    assert_snapshot!(
        infer(r#"
#[macro_export]
macro_rules! foo {
    () => {
        mod foo {
            pub use super::foo;
        }
    };
    ($x:tt) => {
        $x
    };
}

foo!();

fn foo() {
    let foo = foo::foo!(42i32);
}
"#),
        @r###"
    ![0; 5) '42i32': i32
    [171; 206) '{     ...32); }': ()
    [181; 184) 'foo': i32
    "###
    );
}

#[test]
fn processes_impls_generated_by_macros() {
    let t = type_at(
        r#"
//- /main.rs
macro_rules! m {
    ($ident:ident) => (impl Trait for $ident {})
}
trait Trait { fn foo(self) -> u128 {} }
struct S;
m!(S);
fn test() { S.foo()<|>; }
"#,
    );
    assert_eq!(t, "u128");
}

#[test]
fn infer_impl_items_generated_by_macros() {
    let t = type_at(
        r#"
//- /main.rs
macro_rules! m {
    () => (fn foo(&self) -> u128 {0})
}
struct S;
impl S {
    m!();
}

fn test() { S.foo()<|>; }
"#,
    );
    assert_eq!(t, "u128");
}

#[test]
fn infer_impl_items_generated_by_macros_chain() {
    let t = type_at(
        r#"
//- /main.rs
macro_rules! m_inner {
    () => {fn foo(&self) -> u128 {0}}
}
macro_rules! m {
    () => {m_inner!();}
}

struct S;
impl S {
    m!();
}

fn test() { S.foo()<|>; }
"#,
    );
    assert_eq!(t, "u128");
}

#[test]
fn infer_macro_with_dollar_crate_is_correct_in_expr() {
    let (db, pos) = TestDB::with_position(
        r#"
//- /main.rs crate:main deps:foo
fn test() {
    let x = (foo::foo!(1), foo::foo!(2));
    x<|>;
}

//- /lib.rs crate:foo
#[macro_export]
macro_rules! foo {
    (1) => { $crate::bar!() };
    (2) => { 1 + $crate::baz() };
}

#[macro_export]
macro_rules! bar {
    () => { 42 }
}

pub fn baz() -> usize { 31usize }
"#,
    );
    assert_eq!("(i32, usize)", type_at_pos(&db, pos));
}

#[test]
fn infer_type_value_non_legacy_macro_use_as() {
    assert_snapshot!(
        infer(r#"
mod m {
    macro_rules! _foo {
        ($x:ident) => { type $x = u64; }
    }
    pub(crate) use _foo as foo;
}

m::foo!(foo);
use foo as bar;
fn f() -> bar { 0 }
fn main() {
    let _a  = f();
}
"#),
        @r###"
        [159; 164) '{ 0 }': u64
        [161; 162) '0': u64
        [175; 197) '{     ...f(); }': ()
        [185; 187) '_a': u64
        [191; 192) 'f': fn f() -> u64
        [191; 194) 'f()': u64
    "###
    );
}

#[test]
fn infer_builtin_macros_line() {
    assert_snapshot!(
        infer(r#"
#[rustc_builtin_macro]
macro_rules! line {() => {}}

fn main() {
    let x = line!();
}
"#),
        @r###"
    ![0; 1) '0': i32
    [64; 88) '{     ...!(); }': ()
    [74; 75) 'x': i32
    "###
    );
}

#[test]
fn infer_builtin_macros_file() {
    assert_snapshot!(
        infer(r#"
#[rustc_builtin_macro]
macro_rules! file {() => {}}

fn main() {
    let x = file!();
}
"#),
        @r###"
    ![0; 2) '""': &str
    [64; 88) '{     ...!(); }': ()
    [74; 75) 'x': &str
    "###
    );
}

#[test]
fn infer_builtin_macros_column() {
    assert_snapshot!(
        infer(r#"
#[rustc_builtin_macro]
macro_rules! column {() => {}}

fn main() {
    let x = column!();
}
"#),
        @r###"
    ![0; 1) '0': i32
    [66; 92) '{     ...!(); }': ()
    [76; 77) 'x': i32
    "###
    );
}

#[test]
fn infer_derive_clone_simple() {
    let (db, pos) = TestDB::with_position(
        r#"
//- /main.rs crate:main deps:std
#[derive(Clone)]
struct S;
fn test() {
    S.clone()<|>;
}

//- /lib.rs crate:std
#[prelude_import]
use clone::*;
mod clone {
    trait Clone {
        fn clone(&self) -> Self;
    }
}
"#,
    );
    assert_eq!("S", type_at_pos(&db, pos));
}

#[test]
fn infer_derive_clone_with_params() {
    let (db, pos) = TestDB::with_position(
        r#"
//- /main.rs crate:main deps:std
#[derive(Clone)]
struct S;
#[derive(Clone)]
struct Wrapper<T>(T);
struct NonClone;
fn test() {
    (Wrapper(S).clone(), Wrapper(NonClone).clone())<|>;
}

//- /lib.rs crate:std
#[prelude_import]
use clone::*;
mod clone {
    trait Clone {
        fn clone(&self) -> Self;
    }
}
"#,
    );
    assert_eq!("(Wrapper<S>, {unknown})", type_at_pos(&db, pos));
}
<commit_msg>Add test<commit_after>use super::{infer, type_at, type_at_pos};
use crate::test_db::TestDB;
use insta::assert_snapshot;
use ra_db::fixture::WithFixture;

#[test]
fn cfg_impl_def() {
    let (db, pos) = TestDB::with_position(
        r#"
//- /main.rs crate:main deps:foo cfg:test
use foo::S as T;
struct S;

#[cfg(test)]
impl S {
    fn foo1(&self) -> i32 { 0 }
}

#[cfg(not(test))]
impl S {
    fn foo2(&self) -> i32 { 0 }
}

fn test() {
    let t = (S.foo1(), S.foo2(), T.foo3(), T.foo4());
    t<|>;
}

//- /foo.rs crate:foo
struct S;

#[cfg(not(test))]
impl S {
    fn foo3(&self) -> i32 { 0 }
}

#[cfg(test)]
impl S {
    fn foo4(&self) -> i32 { 0 }
}
"#,
    );
    assert_eq!("(i32, {unknown}, i32, {unknown})", type_at_pos(&db, pos));
}

#[test]
fn infer_macros_expanded() {
    assert_snapshot!(
        infer(r#"
struct Foo(Vec<i32>);

macro_rules! foo {
    ($($item:expr),*) => {
            {
                Foo(vec![$($item,)*])
            }
    };
}

fn main() {
    let x = foo!(1,2);
}
"#),
        @r###"
    ![0; 17) '{Foo(v...,2,])}': Foo
    ![1; 4) 'Foo': Foo({unknown}) -> Foo
    ![1; 16) 'Foo(vec![1,2,])': Foo
    ![5; 15) 'vec![1,2,]': {unknown}
    [156; 182) '{     ...,2); }': ()
    [166; 167) 'x': Foo
    "###
    );
}

#[test]
fn infer_legacy_textual_scoped_macros_expanded() {
    assert_snapshot!(
        infer(r#"
struct Foo(Vec<i32>);

#[macro_use]
mod m {
    macro_rules! foo {
        ($($item:expr),*) => {
            {
                Foo(vec![$($item,)*])
            }
        };
    }
}

fn main() {
    let x = foo!(1,2);
    let y = crate::foo!(1,2);
}
"#),
        @r###"
    ![0; 17) '{Foo(v...,2,])}': Foo
    ![1; 4) 'Foo': Foo({unknown}) -> Foo
    ![1; 16) 'Foo(vec![1,2,])': Foo
    ![5; 15) 'vec![1,2,]': {unknown}
    [195; 251) '{     ...,2); }': ()
    [205; 206) 'x': Foo
    [228; 229) 'y': {unknown}
    [232; 248) 'crate:...!(1,2)': {unknown}
    "###
    );
}

#[test]
fn infer_path_qualified_macros_expanded() {
    assert_snapshot!(
        infer(r#"
#[macro_export]
macro_rules! foo {
    () => { 42i32 }
}

mod m {
    pub use super::foo as bar;
}

fn main() {
    let x = crate::foo!();
    let y = m::bar!();
}
"#),
        @r###"
    ![0; 5) '42i32': i32
    ![0; 5) '42i32': i32
    [111; 164) '{     ...!(); }': ()
    [121; 122) 'x': i32
    [148; 149) 'y': i32
    "###
    );
}

#[test]
fn expr_macro_expanded_in_various_places() {
    assert_snapshot!(
        infer(r#"
macro_rules! spam {
    () => (1isize);
}

fn spam() {
    spam!();
    (spam!());
    spam!().spam(spam!());
    for _ in spam!() {}
    || spam!();
    while spam!() {}
    break spam!();
    return spam!();
    match spam!() {
        _ if spam!() => spam!(),
    }
    spam!()(spam!());
    Spam { spam: spam!() };
    spam!()[spam!()];
    await spam!();
    spam!() as usize;
    &spam!();
    -spam!();
    spam!()..spam!();
    spam!() + spam!();
}
"#),
        @r###"
    ![0; 6) '1isize': isize
    ![0; 6) '1isize': isize
    ![0; 6) '1isize': isize
    ![0; 6) '1isize': isize
    ![0; 6) '1isize': isize
    ![0; 6) '1isize': isize
    ![0; 6) '1isize': isize
    ![0; 6) '1isize': isize
    ![0; 6) '1isize': isize
    ![0; 6) '1isize': isize
    ![0; 6) '1isize': isize
    ![0; 6) '1isize': isize
    ![0; 6) '1isize': isize
    ![0; 6) '1isize': isize
    ![0; 6) '1isize': isize
    ![0; 6) '1isize': isize
    ![0; 6) '1isize': isize
    ![0; 6) '1isize': isize
    ![0; 6) '1isize': isize
    ![0; 6) '1isize': isize
    ![0; 6) '1isize': isize
    ![0; 6) '1isize': isize
    ![0; 6) '1isize': isize
    ![0; 6) '1isize': isize
    ![0; 6) '1isize': isize
    [54; 457) '{     ...!(); }': !
    [88; 109) 'spam!(...am!())': {unknown}
    [115; 134) 'for _ ...!() {}': ()
    [119; 120) '_': {unknown}
    [132; 134) '{}': ()
    [139; 149) '|| spam!()': || -> isize
    [155; 171) 'while ...!() {}': ()
    [169; 171) '{}': ()
    [176; 189) 'break spam!()': !
    [195; 209) 'return spam!()': !
    [215; 269) 'match ...     }': isize
    [239; 240) '_': isize
    [274; 290) 'spam!(...am!())': {unknown}
    [296; 318) 'Spam {...m!() }': {unknown}
    [324; 340) 'spam!(...am!()]': {unknown}
    [365; 381) 'spam!(... usize': usize
    [387; 395) '&spam!()': &isize
    [401; 409) '-spam!()': isize
    [415; 431) 'spam!(...pam!()': {unknown}
    [437; 454) 'spam!(...pam!()': isize
    "###
    );
}

#[test]
fn infer_type_value_macro_having_same_name() {
    assert_snapshot!(
        infer(r#"
#[macro_export]
macro_rules! foo {
    () => {
        mod foo {
            pub use super::foo;
        }
    };
    ($x:tt) => {
        $x
    };
}

foo!();

fn foo() {
    let foo = foo::foo!(42i32);
}
"#),
        @r###"
    ![0; 5) '42i32': i32
    [171; 206) '{     ...32); }': ()
    [181; 184) 'foo': i32
    "###
    );
}

#[test]
fn processes_impls_generated_by_macros() {
    let t = type_at(
        r#"
//- /main.rs
macro_rules! m {
    ($ident:ident) => (impl Trait for $ident {})
}
trait Trait { fn foo(self) -> u128 {} }
struct S;
m!(S);
fn test() { S.foo()<|>; }
"#,
    );
    assert_eq!(t, "u128");
}

#[test]
fn infer_impl_items_generated_by_macros() {
    let t = type_at(
        r#"
//- /main.rs
macro_rules! m {
    () => (fn foo(&self) -> u128 {0})
}
struct S;
impl S {
    m!();
}

fn test() { S.foo()<|>; }
"#,
    );
    assert_eq!(t, "u128");
}

#[test]
fn infer_impl_items_generated_by_macros_chain() {
    let t = type_at(
        r#"
//- /main.rs
macro_rules! m_inner {
    () => {fn foo(&self) -> u128 {0}}
}
macro_rules! m {
    () => {m_inner!();}
}

struct S;
impl S {
    m!();
}

fn test() { S.foo()<|>; }
"#,
    );
    assert_eq!(t, "u128");
}

#[test]
fn infer_macro_with_dollar_crate_is_correct_in_expr() {
    let (db, pos) = TestDB::with_position(
        r#"
//- /main.rs crate:main deps:foo
fn test() {
    let x = (foo::foo!(1), foo::foo!(2));
    x<|>;
}

//- /lib.rs crate:foo
#[macro_export]
macro_rules! foo {
    (1) => { $crate::bar!() };
    (2) => { 1 + $crate::baz() };
}

#[macro_export]
macro_rules! bar {
    () => { 42 }
}

pub fn baz() -> usize { 31usize }
"#,
    );
    assert_eq!("(i32, usize)", type_at_pos(&db, pos));
}

#[test]
fn infer_type_value_non_legacy_macro_use_as() {
    assert_snapshot!(
        infer(r#"
mod m {
    macro_rules! _foo {
        ($x:ident) => { type $x = u64; }
    }
    pub(crate) use _foo as foo;
}

m::foo!(foo);
use foo as bar;
fn f() -> bar { 0 }
fn main() {
    let _a  = f();
}
"#),
        @r###"
        [159; 164) '{ 0 }': u64
        [161; 162) '0': u64
        [175; 197) '{     ...f(); }': ()
        [185; 187) '_a': u64
        [191; 192) 'f': fn f() -> u64
        [191; 194) 'f()': u64
    "###
    );
}

#[test]
fn infer_builtin_macros_line() {
    assert_snapshot!(
        infer(r#"
#[rustc_builtin_macro]
macro_rules! line {() => {}}

fn main() {
    let x = line!();
}
"#),
        @r###"
    ![0; 1) '0': i32
    [64; 88) '{     ...!(); }': ()
    [74; 75) 'x': i32
    "###
    );
}

#[test]
fn infer_builtin_macros_file() {
    assert_snapshot!(
        infer(r#"
#[rustc_builtin_macro]
macro_rules! file {() => {}}

fn main() {
    let x = file!();
}
"#),
        @r###"
    ![0; 2) '""': &str
    [64; 88) '{     ...!(); }': ()
    [74; 75) 'x': &str
    "###
    );
}

#[test]
fn infer_builtin_macros_column() {
    assert_snapshot!(
        infer(r#"
#[rustc_builtin_macro]
macro_rules! column {() => {}}

fn main() {
    let x = column!();
}
"#),
        @r###"
    ![0; 1) '0': i32
    [66; 92) '{     ...!(); }': ()
    [76; 77) 'x': i32
    "###
    );
}

#[test]
fn infer_builtin_macros_concat() {
    assert_snapshot!(
        infer(r#"
#[rustc_builtin_macro]
macro_rules! concat {() => {}}

fn main() {
    let x = concat!("hello", concat!("world", "!"));
}
"#),
        @r###"
    ![0; 13) '"helloworld!"': &str
    [66; 122) '{     ...")); }': ()
    [76; 77) 'x': &str
    "###
    );
}

#[test]
fn infer_derive_clone_simple() {
    let (db, pos) = TestDB::with_position(
        r#"
//- /main.rs crate:main deps:std
#[derive(Clone)]
struct S;
fn test() {
    S.clone()<|>;
}

//- /lib.rs crate:std
#[prelude_import]
use clone::*;
mod clone {
    trait Clone {
        fn clone(&self) -> Self;
    }
}
"#,
    );
    assert_eq!("S", type_at_pos(&db, pos));
}

#[test]
fn infer_derive_clone_with_params() {
    let (db, pos) = TestDB::with_position(
        r#"
//- /main.rs crate:main deps:std
#[derive(Clone)]
struct S;
#[derive(Clone)]
struct Wrapper<T>(T);
struct NonClone;
fn test() {
    (Wrapper(S).clone(), Wrapper(NonClone).clone())<|>;
}

//- /lib.rs crate:std
#[prelude_import]
use clone::*;
mod clone {
    trait Clone {
        fn clone(&self) -> Self;
    }
}
"#,
    );
    assert_eq!("(Wrapper<S>, {unknown})", type_at_pos(&db, pos));
}
<|endoftext|>


<commit_before>//! Transforms markdown
use std::borrow::Cow;

use ide_db::helpers::rust_doc::is_rust_fence;

const RUSTDOC_FENCE: &str = "```";

pub(crate) fn format_docs(src: &str) -> String {
    let mut processed_lines = Vec::new();
    let mut in_code_block = false;
    let mut is_rust = false;

    for line in src.lines() {
        let mut line = Cow::from(line);
        if in_code_block && is_rust && code_line_ignored_by_rustdoc(&line) {
            continue;
        }

        if let Some(header) = line.strip_prefix(RUSTDOC_FENCE) {
            in_code_block ^= true;

            if in_code_block {
                is_rust = is_rust_fence(header);

                if is_rust {
                    line = Cow::Borrowed("```rust");
                }
            }
        }

        if in_code_block {
            let trimmed = line.trim();
            if trimmed.starts_with("##") {
                line = Cow::Owned(line.replacen("##", "#", 1));
            }
        }

        processed_lines.push(line);
    }
    processed_lines.join("\n")
}

fn code_line_ignored_by_rustdoc(line: &str) -> bool {
    let trimmed = line.trim();
    trimmed == "#" || trimmed.starts_with("# ") || trimmed.starts_with("#\t")
}

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

    #[test]
    fn test_format_docs_adds_rust() {
        let comment = "```\nfn some_rust() {}\n```";
        assert_eq!(format_docs(comment), "```rust\nfn some_rust() {}\n```");
    }

    #[test]
    fn test_format_docs_handles_plain_text() {
        let comment = "```text\nthis is plain text\n```";
        assert_eq!(format_docs(comment), "```text\nthis is plain text\n```");
    }

    #[test]
    fn test_format_docs_handles_non_rust() {
        let comment = "```sh\nsupposedly shell code\n```";
        assert_eq!(format_docs(comment), "```sh\nsupposedly shell code\n```");
    }

    #[test]
    fn test_format_docs_handles_rust_alias() {
        let comment = "```ignore\nlet z = 55;\n```";
        assert_eq!(format_docs(comment), "```rust\nlet z = 55;\n```");
    }

    #[test]
    fn test_format_docs_handles_complex_code_block_attrs() {
        let comment = "```rust,no_run\nlet z = 55;\n```";
        assert_eq!(format_docs(comment), "```rust\nlet z = 55;\n```");
    }

    #[test]
    fn test_format_docs_handles_error_codes() {
        let comment = "```compile_fail,E0641\nlet b = 0 as *const _;\n```";
        assert_eq!(format_docs(comment), "```rust\nlet b = 0 as *const _;\n```");
    }

    #[test]
    fn test_format_docs_skips_comments_in_rust_block() {
        let comment =
            "```rust\n # skip1\n# skip2\n#stay1\nstay2\n#\n #\n   #    \n #\tskip3\n\t#\t\n```";
        assert_eq!(format_docs(comment), "```rust\n#stay1\nstay2\n```");
    }

    #[test]
    fn test_format_docs_does_not_skip_lines_if_plain_text() {
        let comment =
            "```text\n # stay1\n# stay2\n#stay3\nstay4\n#\n #\n   #    \n #\tstay5\n\t#\t\n```";
        assert_eq!(
            format_docs(comment),
            "```text\n # stay1\n# stay2\n#stay3\nstay4\n#\n #\n   #    \n #\tstay5\n\t#\t\n```",
        );
    }

    #[test]
    fn test_format_docs_keeps_comments_outside_of_rust_block() {
        let comment = " # stay1\n# stay2\n#stay3\nstay4\n#\n #\n   #    \n #\tstay5\n\t#\t";
        assert_eq!(format_docs(comment), comment);
    }

    #[test]
    fn test_format_docs_preserves_newlines() {
        let comment = "this\nis\nmultiline";
        assert_eq!(format_docs(comment), comment);
    }

    #[test]
    fn test_code_blocks_in_comments_marked_as_rust() {
        let comment = r#"```rust
fn main(){}
```
Some comment.
```
let a = 1;
```"#;

        assert_eq!(
            format_docs(comment),
            "```rust\nfn main(){}\n```\nSome comment.\n```rust\nlet a = 1;\n```"
        );
    }

    #[test]
    fn test_code_blocks_in_comments_marked_as_text() {
        let comment = r#"```text
filler
text
```
Some comment.
```
let a = 1;
```"#;

        assert_eq!(
            format_docs(comment),
            "```text\nfiller\ntext\n```\nSome comment.\n```rust\nlet a = 1;\n```"
        );
    }

    #[test]
    fn test_format_docs_handles_escape_double_hashes() {
        let comment = r#"```rust
let s = "foo
## bar # baz";
```"#;

        assert_eq!(format_docs(comment), "```rust\nlet s = \"foo\n# bar # baz\";\n```");
    }
}
<commit_msg>perf: avoid allocating by just slicing.<commit_after>//! Transforms markdown
use ide_db::helpers::rust_doc::is_rust_fence;

const RUSTDOC_FENCE: &str = "```";

pub(crate) fn format_docs(src: &str) -> String {
    let mut processed_lines = Vec::new();
    let mut in_code_block = false;
    let mut is_rust = false;

    for mut line in src.lines() {
        if in_code_block && is_rust && code_line_ignored_by_rustdoc(line) {
            continue;
        }

        if let Some(header) = line.strip_prefix(RUSTDOC_FENCE) {
            in_code_block ^= true;

            if in_code_block {
                is_rust = is_rust_fence(header);

                if is_rust {
                    line = "```rust";
                }
            }
        }

        if in_code_block {
            let trimmed = line.trim_start();
            if trimmed.starts_with("##") {
                line = &trimmed[1..];
            }
        }

        processed_lines.push(line);
    }
    processed_lines.join("\n")
}

fn code_line_ignored_by_rustdoc(line: &str) -> bool {
    let trimmed = line.trim();
    trimmed == "#" || trimmed.starts_with("# ") || trimmed.starts_with("#\t")
}

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

    #[test]
    fn test_format_docs_adds_rust() {
        let comment = "```\nfn some_rust() {}\n```";
        assert_eq!(format_docs(comment), "```rust\nfn some_rust() {}\n```");
    }

    #[test]
    fn test_format_docs_handles_plain_text() {
        let comment = "```text\nthis is plain text\n```";
        assert_eq!(format_docs(comment), "```text\nthis is plain text\n```");
    }

    #[test]
    fn test_format_docs_handles_non_rust() {
        let comment = "```sh\nsupposedly shell code\n```";
        assert_eq!(format_docs(comment), "```sh\nsupposedly shell code\n```");
    }

    #[test]
    fn test_format_docs_handles_rust_alias() {
        let comment = "```ignore\nlet z = 55;\n```";
        assert_eq!(format_docs(comment), "```rust\nlet z = 55;\n```");
    }

    #[test]
    fn test_format_docs_handles_complex_code_block_attrs() {
        let comment = "```rust,no_run\nlet z = 55;\n```";
        assert_eq!(format_docs(comment), "```rust\nlet z = 55;\n```");
    }

    #[test]
    fn test_format_docs_handles_error_codes() {
        let comment = "```compile_fail,E0641\nlet b = 0 as *const _;\n```";
        assert_eq!(format_docs(comment), "```rust\nlet b = 0 as *const _;\n```");
    }

    #[test]
    fn test_format_docs_skips_comments_in_rust_block() {
        let comment =
            "```rust\n # skip1\n# skip2\n#stay1\nstay2\n#\n #\n   #    \n #\tskip3\n\t#\t\n```";
        assert_eq!(format_docs(comment), "```rust\n#stay1\nstay2\n```");
    }

    #[test]
    fn test_format_docs_does_not_skip_lines_if_plain_text() {
        let comment =
            "```text\n # stay1\n# stay2\n#stay3\nstay4\n#\n #\n   #    \n #\tstay5\n\t#\t\n```";
        assert_eq!(
            format_docs(comment),
            "```text\n # stay1\n# stay2\n#stay3\nstay4\n#\n #\n   #    \n #\tstay5\n\t#\t\n```",
        );
    }

    #[test]
    fn test_format_docs_keeps_comments_outside_of_rust_block() {
        let comment = " # stay1\n# stay2\n#stay3\nstay4\n#\n #\n   #    \n #\tstay5\n\t#\t";
        assert_eq!(format_docs(comment), comment);
    }

    #[test]
    fn test_format_docs_preserves_newlines() {
        let comment = "this\nis\nmultiline";
        assert_eq!(format_docs(comment), comment);
    }

    #[test]
    fn test_code_blocks_in_comments_marked_as_rust() {
        let comment = r#"```rust
fn main(){}
```
Some comment.
```
let a = 1;
```"#;

        assert_eq!(
            format_docs(comment),
            "```rust\nfn main(){}\n```\nSome comment.\n```rust\nlet a = 1;\n```"
        );
    }

    #[test]
    fn test_code_blocks_in_comments_marked_as_text() {
        let comment = r#"```text
filler
text
```
Some comment.
```
let a = 1;
```"#;

        assert_eq!(
            format_docs(comment),
            "```text\nfiller\ntext\n```\nSome comment.\n```rust\nlet a = 1;\n```"
        );
    }

    #[test]
    fn test_format_docs_handles_escape_double_hashes() {
        let comment = r#"```rust
let s = "foo
## bar # baz";
```"#;

        assert_eq!(format_docs(comment), "```rust\nlet s = \"foo\n# bar # baz\";\n```");
    }
}
<|endoftext|>


<commit_before>use crate::ui::{UIWriter,
                UI};
use habitat_api_client as api_client;
use habitat_core as hcore;
use lazy_static::lazy_static;
use std::{collections::HashMap,
          env,
          ffi::OsStr,
          iter::FromIterator};

extern crate json;
#[macro_use]
extern crate log;
#[macro_use]
extern crate lazy_static;
extern crate serde;
#[macro_use]
extern crate serde_derive;
#[cfg_attr(test, macro_use)]
extern crate serde_json;
#[cfg(windows)]
extern crate winapi;

pub use self::error::{Error,
                      Result};

pub mod cli;
pub mod command;
pub mod error;
pub mod locked_env_var;
pub mod output;
pub mod package_graph;
pub mod templating;
pub mod types;
pub mod ui;
pub mod util;

lazy_static::lazy_static! {
    pub static ref PROGRAM_NAME: String = {
        match env::current_exe() {
            Ok(path) => path.file_stem().and_then(OsStr::to_str).unwrap().to_string(),
            Err(e) => {
                error!("Error getting path of current_exe: {}", e);
                String::from("hab-?")
            }
        }
    };
}

// TODO (CM): It would be nice to come up with a way to more
// programmatically manage these flags. It's a bit of a pain to define
// the flag, and then define the environment variables
// separately. Nothing statically guarantees that you've specified an
// variable for a flag.

// TODO (CM): It'd be great to have a built-in way to document them,
// too.

// TODO (CM): Part of that documentation might be *when* a flag was
// added. In general, long-lived flags are a code-smell.

// TODO (CM): It may also be useful to break out features by area of
// concern. We can have any number of bitflags-generated structs.

bitflags::bitflags! {
    /// All the feature flags that are recogized by Habitat.
    ///
    /// In general, feature flags are enabled by setting the corresponding
    /// environment variable.
    ///
    /// Your binary should call `FeatureFlag::from_env` to get a set
    /// of flags to use.
    ///
    /// To add a new feature flag, you will need to add the bit mask
    /// constant here, as well as a mapping from the feature to the
    /// environment variable to which it corresponds in the `ENV_VARS`
    /// map below.
    pub struct FeatureFlag: u32 {
        const LIST               = 0b0000_0000_0001;
        const TEST_EXIT          = 0b0000_0000_0010;
        const TEST_BOOT_FAIL     = 0b0000_0000_0100;
        const REDACT_HTTP        = 0b0000_0000_1000;
        const IGNORE_SIGNALS     = 0b0000_0001_0000;
        const OFFLINE_INSTALL    = 0b0000_0100_0000;
        const IGNORE_LOCAL       = 0b0000_1000_0000;
        const EVENT_STREAM       = 0b0001_0000_0000;
        const TRIGGER_ELECTION   = 0b0010_0000_0000;
        const CONFIGURE_SHUTDOWN = 0b0100_0000_0000;
    }
}

lazy_static! {
    static ref ENV_VARS: HashMap<FeatureFlag, &'static str> = {
        let mapping = vec![(FeatureFlag::LIST, "HAB_FEAT_LIST"),
                           (FeatureFlag::TEST_EXIT, "HAB_FEAT_TEST_EXIT"),
                           (FeatureFlag::TEST_BOOT_FAIL, "HAB_FEAT_BOOT_FAIL"),
                           (FeatureFlag::REDACT_HTTP, "HAB_FEAT_REDACT_HTTP"),
                           (FeatureFlag::IGNORE_SIGNALS, "HAB_FEAT_IGNORE_SIGNALS"),
                           (FeatureFlag::OFFLINE_INSTALL, "HAB_FEAT_OFFLINE_INSTALL"),
                           (FeatureFlag::IGNORE_LOCAL, "HAB_FEAT_IGNORE_LOCAL"),
                           (FeatureFlag::EVENT_STREAM, "HAB_FEAT_EVENT_STREAM"),
                           (FeatureFlag::TRIGGER_ELECTION, "HAB_FEAT_TRIGGER_ELECTION"),
                           (FeatureFlag::CONFIGURE_SHUTDOWN, "HAB_FEAT_CONFIGURE_SHUTDOWN")];
        HashMap::from_iter(mapping)
    };
}

impl FeatureFlag {
    /// If the environment variable for a flag is set to _anything_ but
    /// the empty string, it is activated.
    pub fn from_env(ui: &mut UI) -> Self {
        let mut flags = FeatureFlag::empty();

        for (feature, env_var) in ENV_VARS.iter() {
            if let Some(val) = env::var_os(env_var) {
                if !val.is_empty() {
                    flags.insert(*feature);
                    ui.warn(&format!("Enabling feature: {:?}", feature))
                      .unwrap();
                }
            }
        }

        // TODO (CM): Once the other TODOs above are done (especially the
        // documentation bits), it would be nice to extract this logic
        // into an actual discoverable CLI subcommand; it's a little weird
        // that you have to know how to enable a feature flag before you
        // can even find out that there *are* feature flags to enable.
        //
        // There's no reason why "list feature flags" should itself be a
        // feature-flag.
        if flags.contains(FeatureFlag::LIST) {
            ui.warn("Listing feature flags environment variables:")
              .unwrap();
            for (feature, env_var) in ENV_VARS.iter() {
                ui.warn(&format!("  * {:?}: {}={:?}",
                                 feature,
                                 env_var,
                                 env::var_os(env_var).unwrap_or_default()))
                  .unwrap();
            }
        }

        flags
    }
}

pub mod sync {
    use std::{collections::HashMap,
              sync::Mutex,
              thread::{self,
                       ThreadId},
              time::{Duration,
                     Instant}};

    type NameAndLastHeartbeat = (Option<String>, Instant);
    type HeartbeatMap = HashMap<ThreadId, NameAndLastHeartbeat>;
    lazy_static::lazy_static! {
        static ref THREAD_HEARTBEATS: Mutex<HeartbeatMap> = Default::default();
    }

    habitat_core::env_config_duration!(ThreadAliveThreshold,
                                       HAB_THREAD_ALIVE_THRESHOLD_SECS,
                                       Duration::from_secs(5 * 60));
    habitat_core::env_config_duration!(ThreadAliveCheckDelay,
                                       HAB_THREAD_ALIVE_CHECK_DELAY_SECS,
                                       Duration::from_secs(60));

    /// Call periodically from a thread which has a work loop to indicate that the thread is
    /// still alive and processing its loop. If this function is not called for more than
    /// `ThreadAliveThreshold`, it will be error logged as a likely deadlock.
    pub fn mark_thread_alive() {
        mark_thread_alive_impl(&mut THREAD_HEARTBEATS.lock()
                                                     .expect("THREAD_HEARTBEATS poisoned"));
    }

    fn mark_thread_alive_impl(heartbeats: &mut HeartbeatMap) {
        let thread = thread::current();
        heartbeats.insert(thread.id(),
                          (thread.name().map(str::to_string), Instant::now()));
    }

    /// Call once per binary to start the thread which will check that all the threads that
    /// call `mark_thread_alive` continue to do so.
    pub fn spawn_thread_alive_checker() {
        thread::Builder::new().name("thread-alive-check".to_string())
                              .spawn(|| {
                                  let delay = ThreadAliveCheckDelay::configured_value().into();
                                  let threshold = ThreadAliveThreshold::configured_value().into();
                                  loop {
                                      check_thread_heartbeats(threshold);
                                      thread::sleep(delay);
                                  }
                              })
                              .expect("Error spawning thread alive checker");
    }

    fn check_thread_heartbeats(threshold: Duration) {
        let heartbeats = &THREAD_HEARTBEATS.lock()
                                           .expect("THREAD_HEARTBEATS poisoned");
        for (name, last_heartbeat) in threads_missing_heartbeat(heartbeats, threshold) {
            error!("No heartbeat from {} in {} seconds; deadlock likely",
                   name.unwrap_or_else(|| { "unnamed thread".to_string() }),
                   last_heartbeat.elapsed().as_secs());
        }
    }

    fn threads_missing_heartbeat(heartbeats: &HeartbeatMap,
                                 threshold: Duration)
                                 -> Vec<NameAndLastHeartbeat> {
        heartbeats.iter()
                  .filter_map(|(thread_id, (thread_name, last_heartbeat))| {
                      let time_since_last_heartbeat = last_heartbeat.elapsed();
                      trace!("{:?} {:?} last heartbeat: {:?} ago",
                             thread_id,
                             thread_name,
                             time_since_last_heartbeat);
                      if time_since_last_heartbeat < threshold {
                          None
                      } else {
                          Some((thread_name.clone(), last_heartbeat.clone()))
                      }
                  })
                  .collect::<Vec<_>>()
    }

    #[cfg(test)]
    mod test {
        use super::*;
        use std::sync::{atomic::{AtomicBool,
                                 Ordering},
                        Arc};

        const TEST_THRESHOLD: Duration = Duration::from_millis(10);

        #[test]
        fn no_tracking_without_mark_thread_alive() {
            let heartbeats = HashMap::new();
            thread::spawn(|| {}).join().unwrap();
            thread::sleep(TEST_THRESHOLD * 2);
            assert!(threads_missing_heartbeat(&heartbeats, TEST_THRESHOLD).is_empty());
        }

        #[test]
        fn one_dead_thread() {
            lazy_static! {
                static ref HEARTBEATS: Mutex<HeartbeatMap> = Default::default();
            }
            thread::spawn(move || mark_thread_alive_impl(&mut HEARTBEATS.lock().unwrap())).join()
                                                                                .unwrap();
            thread::sleep(TEST_THRESHOLD * 2);
            assert_eq!(threads_missing_heartbeat(&HEARTBEATS.lock().unwrap(), TEST_THRESHOLD).len(),
                       1);
        }

        #[test]
        fn one_dead_one_alive() {
            lazy_static! {
                static ref HEARTBEATS: Mutex<HeartbeatMap> = Default::default();
            }

            let dead_thread_name = "expected-dead".to_string();
            let test_done: Arc<AtomicBool> = Default::default();
            let test_done2 = Arc::clone(&test_done);

            thread::Builder::new().name(dead_thread_name.clone())
                                  .spawn(move || {
                                      mark_thread_alive_impl(&mut HEARTBEATS.lock().unwrap())
                                  })
                                  .unwrap()
                                  .join()
                                  .unwrap();
            thread::spawn(move || {
                while !test_done2.load(Ordering::Relaxed) {
                    mark_thread_alive_impl(&mut HEARTBEATS.lock().unwrap());
                    thread::sleep(TEST_THRESHOLD / 2)
                }
            });

            thread::sleep(TEST_THRESHOLD * 2);

            let dead_thread_names = threads_missing_heartbeat(&HEARTBEATS.lock().unwrap(),
                                                              TEST_THRESHOLD).iter()
                                                                             .map(|(name, _)| name.clone())
                                                                             .collect::<Vec<_>>();
            assert_eq!(dead_thread_names, vec![Some(dead_thread_name)]);
            test_done.store(true, Ordering::Relaxed);
        }
    }

    #[cfg(feature = "deadlock_detection")]
    mod deadlock_detection {
        use super::*;
        use parking_lot::deadlock;
        use std::{sync::Once,
                  thread};

        static INIT: Once = Once::new();

        pub fn init() { INIT.call_once(spawn_deadlock_detector_thread); }

        fn spawn_deadlock_detector_thread() {
            thread::spawn(move || {
                loop {
                    thread::sleep(Duration::from_secs(10));
                    let deadlocks = deadlock::check_deadlock();
                    if deadlocks.is_empty() {
                        continue;
                    }

                    println!("{} deadlocks detected", deadlocks.len());
                    for (i, threads) in deadlocks.iter().enumerate() {
                        println!("Deadlock #{}", i);
                        for t in threads {
                            println!("Thread Id {:#?}", t.thread_id());
                            println!("{:#?}", t.backtrace());
                        }
                    }

                    // Unfortunately, we can't do anything to resolve the deadlock and
                    // continue, so we have to abort the whole process
                    std::process::exit(1);
                }
            });
        }
    }

    #[cfg(any(feature = "lock_as_rwlock", not(feature = "lock_as_mutex")))]
    type InnerLock<T> = parking_lot::RwLock<T>;
    #[cfg(feature = "lock_as_mutex")]
    type InnerLock<T> = parking_lot::Mutex<T>;

    #[cfg(any(feature = "lock_as_rwlock", not(feature = "lock_as_mutex")))]
    pub type ReadGuard<'a, T> = parking_lot::RwLockReadGuard<'a, T>;
    #[cfg(feature = "lock_as_mutex")]
    pub type ReadGuard<'a, T> = parking_lot::MutexGuard<'a, T>;

    #[cfg(any(feature = "lock_as_rwlock", not(feature = "lock_as_mutex")))]
    pub type WriteGuard<'a, T> = parking_lot::RwLockWriteGuard<'a, T>;
    #[cfg(feature = "lock_as_mutex")]
    pub type WriteGuard<'a, T> = parking_lot::MutexGuard<'a, T>;

    /// A lock which provides the interface of a read/write lock, but which has the option to
    /// internally use either a RwLock or a Mutex in order to make it easier to expose erroneous
    /// recursive locking in tests while still using an RwLock in production to avoid deadlocking
    /// as much as possible.
    #[derive(Debug)]
    pub struct Lock<T> {
        inner: InnerLock<T>,
    }

    impl<T> Lock<T> {
        pub fn new(val: T) -> Self {
            #[cfg(feature = "lock_as_mutex")]
            println!("Lock::new is using Mutex to help find recursive locking");

            #[cfg(feature = "deadlock_detection")]
            deadlock_detection::init();

            Self { inner: InnerLock::new(val), }
        }

        /// This acquires a read lock and will not deadlock if the same thread tries to acquire
        /// the lock recursively. However, it may result in writer starvation. Once we are confident
        /// that all recursive locking has been eliminated, we may replace this implementation
        /// and try_read_for (or add an additional methods) to provide fair locking for readers
        /// and writers.
        ///
        /// See https://github.com/habitat-sh/habitat/issues/6435
        pub fn read(&self) -> ReadGuard<T> {
            #[cfg(any(feature = "lock_as_rwlock", not(feature = "lock_as_mutex")))]
            {
                self.inner.read_recursive()
            }
            #[cfg(feature = "lock_as_mutex")]
            {
                self.inner.lock()
            }
        }

        pub fn try_read_for(&self, timeout: Duration) -> Option<ReadGuard<T>> {
            #[cfg(any(feature = "lock_as_rwlock", not(feature = "lock_as_mutex")))]
            {
                self.inner.try_read_recursive_for(timeout)
            }
            #[cfg(feature = "lock_as_mutex")]
            {
                self.inner.try_lock_for(timeout)
            }
        }

        pub fn write(&self) -> WriteGuard<T> {
            #[cfg(any(feature = "lock_as_rwlock", not(feature = "lock_as_mutex")))]
            {
                self.inner.write()
            }
            #[cfg(feature = "lock_as_mutex")]
            {
                self.inner.lock()
            }
        }
    }
}
<commit_msg>Clippy fixes<commit_after>use crate::ui::{UIWriter,
                UI};
use habitat_api_client as api_client;
use habitat_core as hcore;
use lazy_static::lazy_static;
use std::{collections::HashMap,
          env,
          ffi::OsStr,
          iter::FromIterator};

extern crate json;
#[macro_use]
extern crate log;
#[macro_use]
extern crate lazy_static;
extern crate serde;
#[macro_use]
extern crate serde_derive;
#[cfg_attr(test, macro_use)]
extern crate serde_json;
#[cfg(windows)]
extern crate winapi;

pub use self::error::{Error,
                      Result};

pub mod cli;
pub mod command;
pub mod error;
pub mod locked_env_var;
pub mod output;
pub mod package_graph;
pub mod templating;
pub mod types;
pub mod ui;
pub mod util;

lazy_static::lazy_static! {
    pub static ref PROGRAM_NAME: String = {
        match env::current_exe() {
            Ok(path) => path.file_stem().and_then(OsStr::to_str).unwrap().to_string(),
            Err(e) => {
                error!("Error getting path of current_exe: {}", e);
                String::from("hab-?")
            }
        }
    };
}

// TODO (CM): It would be nice to come up with a way to more
// programmatically manage these flags. It's a bit of a pain to define
// the flag, and then define the environment variables
// separately. Nothing statically guarantees that you've specified an
// variable for a flag.

// TODO (CM): It'd be great to have a built-in way to document them,
// too.

// TODO (CM): Part of that documentation might be *when* a flag was
// added. In general, long-lived flags are a code-smell.

// TODO (CM): It may also be useful to break out features by area of
// concern. We can have any number of bitflags-generated structs.

bitflags::bitflags! {
    /// All the feature flags that are recogized by Habitat.
    ///
    /// In general, feature flags are enabled by setting the corresponding
    /// environment variable.
    ///
    /// Your binary should call `FeatureFlag::from_env` to get a set
    /// of flags to use.
    ///
    /// To add a new feature flag, you will need to add the bit mask
    /// constant here, as well as a mapping from the feature to the
    /// environment variable to which it corresponds in the `ENV_VARS`
    /// map below.
    pub struct FeatureFlag: u32 {
        const LIST               = 0b0000_0000_0001;
        const TEST_EXIT          = 0b0000_0000_0010;
        const TEST_BOOT_FAIL     = 0b0000_0000_0100;
        const REDACT_HTTP        = 0b0000_0000_1000;
        const IGNORE_SIGNALS     = 0b0000_0001_0000;
        const OFFLINE_INSTALL    = 0b0000_0100_0000;
        const IGNORE_LOCAL       = 0b0000_1000_0000;
        const EVENT_STREAM       = 0b0001_0000_0000;
        const TRIGGER_ELECTION   = 0b0010_0000_0000;
        const CONFIGURE_SHUTDOWN = 0b0100_0000_0000;
    }
}

lazy_static! {
    static ref ENV_VARS: HashMap<FeatureFlag, &'static str> = {
        let mapping = vec![(FeatureFlag::LIST, "HAB_FEAT_LIST"),
                           (FeatureFlag::TEST_EXIT, "HAB_FEAT_TEST_EXIT"),
                           (FeatureFlag::TEST_BOOT_FAIL, "HAB_FEAT_BOOT_FAIL"),
                           (FeatureFlag::REDACT_HTTP, "HAB_FEAT_REDACT_HTTP"),
                           (FeatureFlag::IGNORE_SIGNALS, "HAB_FEAT_IGNORE_SIGNALS"),
                           (FeatureFlag::OFFLINE_INSTALL, "HAB_FEAT_OFFLINE_INSTALL"),
                           (FeatureFlag::IGNORE_LOCAL, "HAB_FEAT_IGNORE_LOCAL"),
                           (FeatureFlag::EVENT_STREAM, "HAB_FEAT_EVENT_STREAM"),
                           (FeatureFlag::TRIGGER_ELECTION, "HAB_FEAT_TRIGGER_ELECTION"),
                           (FeatureFlag::CONFIGURE_SHUTDOWN, "HAB_FEAT_CONFIGURE_SHUTDOWN")];
        HashMap::from_iter(mapping)
    };
}

impl FeatureFlag {
    /// If the environment variable for a flag is set to _anything_ but
    /// the empty string, it is activated.
    pub fn from_env(ui: &mut UI) -> Self {
        let mut flags = FeatureFlag::empty();

        for (feature, env_var) in ENV_VARS.iter() {
            if let Some(val) = env::var_os(env_var) {
                if !val.is_empty() {
                    flags.insert(*feature);
                    ui.warn(&format!("Enabling feature: {:?}", feature))
                      .unwrap();
                }
            }
        }

        // TODO (CM): Once the other TODOs above are done (especially the
        // documentation bits), it would be nice to extract this logic
        // into an actual discoverable CLI subcommand; it's a little weird
        // that you have to know how to enable a feature flag before you
        // can even find out that there *are* feature flags to enable.
        //
        // There's no reason why "list feature flags" should itself be a
        // feature-flag.
        if flags.contains(FeatureFlag::LIST) {
            ui.warn("Listing feature flags environment variables:")
              .unwrap();
            for (feature, env_var) in ENV_VARS.iter() {
                ui.warn(&format!("  * {:?}: {}={:?}",
                                 feature,
                                 env_var,
                                 env::var_os(env_var).unwrap_or_default()))
                  .unwrap();
            }
        }

        flags
    }
}

pub mod sync {
    use std::{collections::HashMap,
              sync::Mutex,
              thread::{self,
                       ThreadId},
              time::{Duration,
                     Instant}};

    type NameAndLastHeartbeat = (Option<String>, Instant);
    type HeartbeatMap = HashMap<ThreadId, NameAndLastHeartbeat>;
    lazy_static::lazy_static! {
        static ref THREAD_HEARTBEATS: Mutex<HeartbeatMap> = Default::default();
    }

    habitat_core::env_config_duration!(ThreadAliveThreshold,
                                       HAB_THREAD_ALIVE_THRESHOLD_SECS,
                                       Duration::from_secs(5 * 60));
    habitat_core::env_config_duration!(ThreadAliveCheckDelay,
                                       HAB_THREAD_ALIVE_CHECK_DELAY_SECS,
                                       Duration::from_secs(60));

    /// Call periodically from a thread which has a work loop to indicate that the thread is
    /// still alive and processing its loop. If this function is not called for more than
    /// `ThreadAliveThreshold`, it will be error logged as a likely deadlock.
    pub fn mark_thread_alive() {
        mark_thread_alive_impl(&mut THREAD_HEARTBEATS.lock()
                                                     .expect("THREAD_HEARTBEATS poisoned"));
    }

    fn mark_thread_alive_impl(heartbeats: &mut HeartbeatMap) {
        let thread = thread::current();
        heartbeats.insert(thread.id(),
                          (thread.name().map(str::to_string), Instant::now()));
    }

    /// Call once per binary to start the thread which will check that all the threads that
    /// call `mark_thread_alive` continue to do so.
    pub fn spawn_thread_alive_checker() {
        thread::Builder::new().name("thread-alive-check".to_string())
                              .spawn(|| {
                                  let delay = ThreadAliveCheckDelay::configured_value().into();
                                  let threshold = ThreadAliveThreshold::configured_value().into();
                                  loop {
                                      check_thread_heartbeats(threshold);
                                      thread::sleep(delay);
                                  }
                              })
                              .expect("Error spawning thread alive checker");
    }

    fn check_thread_heartbeats(threshold: Duration) {
        let heartbeats = &THREAD_HEARTBEATS.lock()
                                           .expect("THREAD_HEARTBEATS poisoned");
        for (name, last_heartbeat) in threads_missing_heartbeat(heartbeats, threshold) {
            error!("No heartbeat from {} in {} seconds; deadlock likely",
                   name.unwrap_or_else(|| { "unnamed thread".to_string() }),
                   last_heartbeat.elapsed().as_secs());
        }
    }

    fn threads_missing_heartbeat(heartbeats: &HeartbeatMap,
                                 threshold: Duration)
                                 -> Vec<NameAndLastHeartbeat> {
        heartbeats.iter()
                  .filter_map(|(thread_id, (thread_name, last_heartbeat))| {
                      let time_since_last_heartbeat = last_heartbeat.elapsed();
                      trace!("{:?} {:?} last heartbeat: {:?} ago",
                             thread_id,
                             thread_name,
                             time_since_last_heartbeat);
                      if time_since_last_heartbeat < threshold {
                          None
                      } else {
                          Some((thread_name.clone(), *last_heartbeat))
                      }
                  })
                  .collect::<Vec<_>>()
    }

    #[cfg(test)]
    mod test {
        use super::*;
        use std::sync::{atomic::{AtomicBool,
                                 Ordering},
                        Arc};

        const TEST_THRESHOLD: Duration = Duration::from_millis(10);

        #[test]
        fn no_tracking_without_mark_thread_alive() {
            let heartbeats = HashMap::new();
            thread::spawn(|| {}).join().unwrap();
            thread::sleep(TEST_THRESHOLD * 2);
            assert!(threads_missing_heartbeat(&heartbeats, TEST_THRESHOLD).is_empty());
        }

        #[test]
        fn one_dead_thread() {
            lazy_static! {
                static ref HEARTBEATS: Mutex<HeartbeatMap> = Default::default();
            }
            thread::spawn(move || mark_thread_alive_impl(&mut HEARTBEATS.lock().unwrap())).join()
                                                                                .unwrap();
            thread::sleep(TEST_THRESHOLD * 2);
            assert_eq!(threads_missing_heartbeat(&HEARTBEATS.lock().unwrap(), TEST_THRESHOLD).len(),
                       1);
        }

        #[test]
        fn one_dead_one_alive() {
            lazy_static! {
                static ref HEARTBEATS: Mutex<HeartbeatMap> = Default::default();
            }

            let dead_thread_name = "expected-dead".to_string();
            let test_done: Arc<AtomicBool> = Default::default();
            let test_done2 = Arc::clone(&test_done);

            thread::Builder::new().name(dead_thread_name.clone())
                                  .spawn(move || {
                                      mark_thread_alive_impl(&mut HEARTBEATS.lock().unwrap())
                                  })
                                  .unwrap()
                                  .join()
                                  .unwrap();
            thread::spawn(move || {
                while !test_done2.load(Ordering::Relaxed) {
                    mark_thread_alive_impl(&mut HEARTBEATS.lock().unwrap());
                    thread::sleep(TEST_THRESHOLD / 2)
                }
            });

            thread::sleep(TEST_THRESHOLD * 2);

            let dead_thread_names = threads_missing_heartbeat(&HEARTBEATS.lock().unwrap(),
                                                              TEST_THRESHOLD).iter()
                                                                             .map(|(name, _)| name.clone())
                                                                             .collect::<Vec<_>>();
            assert_eq!(dead_thread_names, vec![Some(dead_thread_name)]);
            test_done.store(true, Ordering::Relaxed);
        }
    }

    #[cfg(feature = "deadlock_detection")]
    mod deadlock_detection {
        use super::*;
        use parking_lot::deadlock;
        use std::{sync::Once,
                  thread};

        static INIT: Once = Once::new();

        pub fn init() { INIT.call_once(spawn_deadlock_detector_thread); }

        fn spawn_deadlock_detector_thread() {
            thread::spawn(move || {
                loop {
                    thread::sleep(Duration::from_secs(10));
                    let deadlocks = deadlock::check_deadlock();
                    if deadlocks.is_empty() {
                        continue;
                    }

                    println!("{} deadlocks detected", deadlocks.len());
                    for (i, threads) in deadlocks.iter().enumerate() {
                        println!("Deadlock #{}", i);
                        for t in threads {
                            println!("Thread Id {:#?}", t.thread_id());
                            println!("{:#?}", t.backtrace());
                        }
                    }

                    // Unfortunately, we can't do anything to resolve the deadlock and
                    // continue, so we have to abort the whole process
                    std::process::exit(1);
                }
            });
        }
    }

    #[cfg(any(feature = "lock_as_rwlock", not(feature = "lock_as_mutex")))]
    type InnerLock<T> = parking_lot::RwLock<T>;
    #[cfg(feature = "lock_as_mutex")]
    type InnerLock<T> = parking_lot::Mutex<T>;

    #[cfg(any(feature = "lock_as_rwlock", not(feature = "lock_as_mutex")))]
    pub type ReadGuard<'a, T> = parking_lot::RwLockReadGuard<'a, T>;
    #[cfg(feature = "lock_as_mutex")]
    pub type ReadGuard<'a, T> = parking_lot::MutexGuard<'a, T>;

    #[cfg(any(feature = "lock_as_rwlock", not(feature = "lock_as_mutex")))]
    pub type WriteGuard<'a, T> = parking_lot::RwLockWriteGuard<'a, T>;
    #[cfg(feature = "lock_as_mutex")]
    pub type WriteGuard<'a, T> = parking_lot::MutexGuard<'a, T>;

    /// A lock which provides the interface of a read/write lock, but which has the option to
    /// internally use either a RwLock or a Mutex in order to make it easier to expose erroneous
    /// recursive locking in tests while still using an RwLock in production to avoid deadlocking
    /// as much as possible.
    #[derive(Debug)]
    pub struct Lock<T> {
        inner: InnerLock<T>,
    }

    impl<T> Lock<T> {
        pub fn new(val: T) -> Self {
            #[cfg(feature = "lock_as_mutex")]
            println!("Lock::new is using Mutex to help find recursive locking");

            #[cfg(feature = "deadlock_detection")]
            deadlock_detection::init();

            Self { inner: InnerLock::new(val), }
        }

        /// This acquires a read lock and will not deadlock if the same thread tries to acquire
        /// the lock recursively. However, it may result in writer starvation. Once we are confident
        /// that all recursive locking has been eliminated, we may replace this implementation
        /// and try_read_for (or add an additional methods) to provide fair locking for readers
        /// and writers.
        ///
        /// See https://github.com/habitat-sh/habitat/issues/6435
        pub fn read(&self) -> ReadGuard<T> {
            #[cfg(any(feature = "lock_as_rwlock", not(feature = "lock_as_mutex")))]
            {
                self.inner.read_recursive()
            }
            #[cfg(feature = "lock_as_mutex")]
            {
                self.inner.lock()
            }
        }

        pub fn try_read_for(&self, timeout: Duration) -> Option<ReadGuard<T>> {
            #[cfg(any(feature = "lock_as_rwlock", not(feature = "lock_as_mutex")))]
            {
                self.inner.try_read_recursive_for(timeout)
            }
            #[cfg(feature = "lock_as_mutex")]
            {
                self.inner.try_lock_for(timeout)
            }
        }

        pub fn write(&self) -> WriteGuard<T> {
            #[cfg(any(feature = "lock_as_rwlock", not(feature = "lock_as_mutex")))]
            {
                self.inner.write()
            }
            #[cfg(feature = "lock_as_mutex")]
            {
                self.inner.lock()
            }
        }
    }
}
<|endoftext|>


<commit_before>// Copyright (c) 2018 Berkus Decker <berkus+github@metta.systems>
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

/// This example shows simple packet_fanout processing under linux.
/// PACKET_FANOUT in linux allows to offload packet processing to multiple threads.
/// See [man 7 packet](http://man7.org/linux/man-pages/man7/packet.7.html) for more details.
extern crate pnet;
extern crate pnet_datalink;

use pnet::datalink::{self, Config, FanoutOption, FanoutType, NetworkInterface};
use std::env;
use std::io::{self, Write};
use std::process;
use std::thread;

#[cfg(not(target_os = "linux"))]
fn main() {
    writeln!(io::stderr(), "fanout is only supported on Linux").unwrap();
    process::exit(1);
}

#[cfg(target_os = "linux")]
fn main() {
    use pnet::datalink::Channel::Ethernet;

    let iface_name = match env::args().nth(1) {
        Some(n) => n,
        None => {
            writeln!(io::stderr(), "USAGE: fanout <NETWORK INTERFACE> [hash|*round-robin*|cpu|rollover|rnd|qm|cbpf|ebpf] [group-id:123]").unwrap();
            process::exit(1);
        }
    };
    let interface_names_match = |iface: &NetworkInterface| iface.name == iface_name;

    // Find the network interface with the provided name
    let interfaces = datalink::interfaces();
    let interface = interfaces
        .into_iter()
        .filter(interface_names_match)
        .next()
        .unwrap();

    let fanout_type = match env::args().nth(2) {
        Some(n) => match n.to_lowercase().as_str() {
            "hash" => FanoutType::HASH,
            "round-robin" => FanoutType::LB,
            "cpu" => FanoutType::CPU,
            "rollover" => FanoutType::ROLLOVER,
            "rnd" => FanoutType::RND,
            "qm" => FanoutType::QM,
            "cbpf" => FanoutType::CBPF,
            "ebpf" => FanoutType::EBPF,
            _ => panic!("Unsupported fanout type, use one of hash, round-robin, cpu, rollover, rnd, qm, cbpf or ebpf")
        },
        None => FanoutType::LB,
    };

    let group_id = match env::args().nth(3) {
        Some(n) => n.parse::<u16>().unwrap(),
        None => 123,
    };

    let mut config: Config = Default::default();
    config.linux_fanout = Some(FanoutOption {
        group_id: group_id,
        fanout_type: fanout_type,
        defrag: true,
        rollover: false,
    });

    let mut threads = vec![];
    for x in 0..3 {
        let itf = interface.clone();
        let thread = thread::Builder::new()
            .name(format!("thread{}", x))
            .spawn(move || {
                // Create a channel to receive on
                let (_, mut rx) = match datalink::channel(&itf, config) {
                    Ok(Ethernet(tx, rx)) => (tx, rx),
                    Ok(_) => panic!("packetdump: unhandled channel type: {}"),
                    Err(e) => panic!("packetdump: unable to create channel: {}", e),
                };

                let handle = thread::current();

                loop {
                    match rx.next() {
                        Ok(_packet) => {
                            writeln!(
                                io::stdout(),
                                "Received packet on thread {:?}",
                                handle.name()
                            ).unwrap();
                        }
                        Err(e) => panic!("packetdump: unable to receive packet: {}", e),
                    }
                }
            })
            .unwrap();
        threads.push(thread);
    }

    for t in threads {
        t.join().unwrap();
    }
}
<commit_msg>Use system interface since the code is platform-dependent<commit_after>// Copyright (c) 2018 Berkus Decker <berkus+github@metta.systems>
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

/// This example shows simple packet_fanout processing under linux.
/// PACKET_FANOUT in linux allows to offload packet processing to multiple threads.
/// See [man 7 packet](http://man7.org/linux/man-pages/man7/packet.7.html) for more details.
extern crate pnet;
extern crate pnet_datalink;

use pnet::datalink::{self, Config, FanoutOption, FanoutType, NetworkInterface};
use std::env;
use std::io::{self, Write};
use std::process;
use std::thread;

#[cfg(not(target_os = "linux"))]
fn main() {
    writeln!(io::stderr(), "fanout is only supported on Linux").unwrap();
    process::exit(1);
}

#[cfg(target_os = "linux")]
fn main() {
    use pnet::datalink::Channel::Ethernet;

    let iface_name = match env::args().nth(1) {
        Some(n) => n,
        None => {
            writeln!(io::stderr(), "USAGE: fanout <NETWORK INTERFACE> [hash|*round-robin*|cpu|rollover|rnd|qm|cbpf|ebpf] [group-id:123]").unwrap();
            process::exit(1);
        }
    };
    let interface_names_match = |iface: &NetworkInterface| iface.name == iface_name;

    // Find the network interface with the provided name
    let interfaces = datalink::linux::interfaces();
    let interface = interfaces
        .into_iter()
        .filter(interface_names_match)
        .next()
        .unwrap();

    let fanout_type = match env::args().nth(2) {
        Some(n) => match n.to_lowercase().as_str() {
            "hash" => FanoutType::HASH,
            "round-robin" => FanoutType::LB,
            "cpu" => FanoutType::CPU,
            "rollover" => FanoutType::ROLLOVER,
            "rnd" => FanoutType::RND,
            "qm" => FanoutType::QM,
            "cbpf" => FanoutType::CBPF,
            "ebpf" => FanoutType::EBPF,
            _ => panic!("Unsupported fanout type, use one of hash, round-robin, cpu, rollover, rnd, qm, cbpf or ebpf")
        },
        None => FanoutType::LB,
    };

    let group_id = match env::args().nth(3) {
        Some(n) => n.parse::<u16>().unwrap(),
        None => 123,
    };

    let mut config: Config = Default::default();
    config.linux_fanout = Some(FanoutOption {
        group_id: group_id,
        fanout_type: fanout_type,
        defrag: true,
        rollover: false,
    });

    let mut threads = vec![];
    for x in 0..3 {
        let itf = interface.clone();
        let thread = thread::Builder::new()
            .name(format!("thread{}", x))
            .spawn(move || {
                // Create a channel to receive on
                let (_, mut rx) = match datalink::channel(&itf, config) {
                    Ok(Ethernet(tx, rx)) => (tx, rx),
                    Ok(_) => panic!("packetdump: unhandled channel type: {}"),
                    Err(e) => panic!("packetdump: unable to create channel: {}", e),
                };

                let handle = thread::current();

                loop {
                    match rx.next() {
                        Ok(_packet) => {
                            writeln!(
                                io::stdout(),
                                "Received packet on thread {:?}",
                                handle.name()
                            ).unwrap();
                        }
                        Err(e) => panic!("packetdump: unable to receive packet: {}", e),
                    }
                }
            })
            .unwrap();
        threads.push(thread);
    }

    for t in threads {
        t.join().unwrap();
    }
}
<|endoftext|>


<commit_before>// Copyright (c) 2015 T. Okubo
// This file is part of vlc-rs.
// Licensed under the MIT license, see the LICENSE file.

use ffi;

pub struct MediaLibrary {
    pub ptr: *mut ffi::libvlc_media_library_t,
}

impl Drop for MediaLibrary {
    fn drop(&mut self) {
        unsafe{ ffi::libvlc_media_library_release(self.ptr) };
    }
}
<commit_msg>Add methods to MediaLibrary<commit_after>// Copyright (c) 2015 T. Okubo
// This file is part of vlc-rs.
// Licensed under the MIT license, see the LICENSE file.

use ffi;
use ::{Instance, MediaList};

pub struct MediaLibrary {
    pub ptr: *mut ffi::libvlc_media_library_t,
}

impl MediaLibrary {
    /// Create an new Media Library object.
    pub fn new(instance: &Instance) -> Option<MediaLibrary> {
        unsafe{
            let p = ffi::libvlc_media_library_new(instance.ptr);
            if p.is_null() { None }else{ Some(MediaLibrary{ptr: p}) }
        }
    }

    /// Load media library.
    pub fn load(&self) -> Result<(), ()> {
        unsafe{
            if ffi::libvlc_media_library_load(self.ptr) == 0 { Ok(()) }else{ Err(()) }
        }
    }

    /// Get media library subitems.
    pub fn media_list(&self) -> Option<MediaList> {
        unsafe{
            let p = ffi::libvlc_media_library_media_list(self.ptr);
            if p.is_null() { None }else{ Some(MediaList{ptr: p}) }
        }
    }
}

impl Drop for MediaLibrary {
    fn drop(&mut self) {
        unsafe{ ffi::libvlc_media_library_release(self.ptr) };
    }
}
<|endoftext|>