<commit_before>//! Thread-local storage for JavaScript threads.
//!
//! At runtime, an instance of a Node.js addon can contain its own local storage,
//! which can then be shared and accessed as needed from Rust in a Neon module. This can
//! be useful for setting up long-lived state that needs to be shared between calls
//! of an addon's APIs.
//!
//! For example, an addon may wish to track the [thread ID][threadId] of each of its
//! instances:
//!
//! ```
//! # use neon::prelude::*;
//! # use neon::thread::LocalKey;
//! static THREAD_ID: LocalKey<u32> = LocalKey::new();
//!
//! pub fn thread_id<'cx, C: Context<'cx>>(cx: &mut C) -> NeonResult<u32> {
//!     THREAD_ID.get_or_try_init(cx, |cx| {
//!         let global = cx.global();
//!         let require: Handle<JsFunction> = global.get(cx, "require")?;
//!         let worker: Handle<JsObject> = require.call_with(cx)
//!             .arg(cx.string("node:worker_threads"))
//!             .apply(cx)?;
//!         let threadId: Handle<JsNumber> = worker.get(cx, "threadId")?;
//!         Ok(threadId.value(cx) as u32)
//!     }).cloned()
//! }
//! ```
//!
//! ### The Addon Lifecycle
//!
//! For some use cases, a single shared global constant stored in a `static` variable
//! might be sufficient:
//!
//! ```
//! static MY_CONSTANT: &'static str = "hello Neon";
//! ```
//!
//! This variable will be allocated when the addon is first loaded into the Node.js
//! process. This works fine for single-threaded applications, or global immutable
//! data.
//!
//! However, since the addition of [worker threads][workers] in Node v10,
//! modules can be instantiated multiple times in a single Node process. This means
//! that while the dynamically-loaded binary library (i.e., the Rust implementation of
//! the addon) is only loaded once in the running process, but its `main()` function
//! is executed multiple times with distinct module objects, once per application thread:
//!
//! ![The Node.js addon lifecycle, described in detail below.][lifecycle]
//!
//! This means that any thread-local data needs to be initialized separately for each
//! instance of the addon. This module provides a simple container type, [`LocalKey`](LocalKey),
//! for allocating and initializing thread-local data. (Technically, this data is stored in the
//! addon's [module instance][environment], which is equivalent to being thread-local.)
//!
//! A common example is when an addon defines a custom datatype, which cannot be used across
//! separate threads. The constructor for the datatype can be [rooted](crate::handle::Root) and
//! saved in thread-local storage:
//!
//! ```
//! # use neon::prelude::*;
//! # use neon::thread::LocalKey;
//! # fn initialize_my_datatype<'cx, C: Context<'cx>>(cx: &mut C) -> JsResult<'cx, JsFunction> { unimplemented!() }
//! static MY_CONSTRUCTOR: LocalKey<Root<JsFunction>> = LocalKey::new();
//!
//! pub fn my_constructor<'cx, C: Context<'cx>>(cx: &mut C) -> JsResult<'cx, JsFunction> {
//!     let constructor = MY_CONSTRUCTOR.get_or_try_init(cx, |cx| {
//!         let constructor: Handle<JsFunction> = initialize_my_datatype(cx)?;
//!         Ok(constructor.root(cx))
//!     })?;
//!     Ok(constructor.to_inner(cx))
//! }
//! ```
//!
//! Notice that if this code were implemented without a `LocalKey`, it would fail whenever
//! one thread stores an instance of the constructor and a different thread attempts to
//! access it with the call to [`to_inner()`](crate::handle::Root::to_inner).
//!
//! ### When to Use Thread-Local Storage
//!
//! Single-threaded applications don't generally need to worry about thread-local data.
//! There are two cases where Neon apps should consider storing static data in a
//! `LocalKey` storage cell:
//!
//! - **Multi-threaded applications:** If your Node application uses the `Worker`
//!   API, you'll want to store any static data that might get access from multiple
//!   threads in thread-local data.
//! - **Libraries:** If your addon is part of a library that could be used by multiple
//!   applications, you'll want to store static data in thread-local data in case the
//!   addon ends up instantiated by multiple threads in some future application.
//!
//! ### Why Not Use Standard TLS?
//!
//! Because the JavaScript engine may not tie JavaScript threads 1:1 to system threads,
//! it is recommended to use this module instead of the Rust standard thread-local storage
//! when tying data to a JavaScript thread.
//!
//! [environment]: https://nodejs.org/api/n-api.html#environment-life-cycle-apis
//! [lifecycle]: https://raw.githubusercontent.com/neon-bindings/neon/main/doc/lifecycle.png
//! [workers]: https://nodejs.org/api/worker_threads.html
//! [threadId]: https://nodejs.org/api/worker_threads.html#workerthreadid

use std::any::Any;
use std::marker::PhantomData;
use std::sync::atomic::{AtomicUsize, Ordering};

use once_cell::sync::OnceCell;

use crate::context::Context;
use crate::lifecycle::LocalCell;

static COUNTER: AtomicUsize = AtomicUsize::new(0);

fn next_id() -> usize {
    COUNTER.fetch_add(1, Ordering::SeqCst)
}

/// A JavaScript thread-local container that owns its contents, similar to
/// [`std::thread::LocalKey`](std::thread::LocalKey) but tied to a JavaScript thread rather
/// than a system thread.
///
/// ### Initialization and Destruction
///
/// Initialization is dynamically performed on the first call to one of the `init` methods
/// of `LocalKey`, and values that implement [`Drop`](std::ops::Drop) get destructed when
/// the JavaScript thread exits, i.e. when a worker thread terminates or the main thread
/// terminates on process exit.
#[derive(Default)]
pub struct LocalKey<T> {
    _type: PhantomData<T>,
    id: OnceCell<usize>,
}

impl<T> LocalKey<T> {
    /// Creates a new local value. This method is `const`, so it can be assigned to
    /// static variables.
    pub const fn new() -> Self {
        Self {
            _type: PhantomData,
            id: OnceCell::new(),
        }
    }

    fn id(&self) -> usize {
        *self.id.get_or_init(next_id)
    }
}

impl<T: Any + Send + 'static> LocalKey<T> {
    /// Gets the current value of the cell. Returns `None` if the cell has not
    /// yet been initialized.
    pub fn get<'cx, 'a, C>(&self, cx: &'a mut C) -> Option<&'cx T>
    where
        C: Context<'cx>,
    {
        // Unwrap safety: The type bound LocalKey<T> and the fact that every LocalKey has a unique
        // id guarantees that the cell is only ever assigned instances of type T.
        let r: Option<&T> =
            LocalCell::get(cx, self.id()).map(|value| value.downcast_ref().unwrap());

        // Safety: Since the Box is immutable and heap-allocated, it's guaranteed not to
        // move or change for the duration of the context.
        unsafe { std::mem::transmute::<Option<&'a T>, Option<&'cx T>>(r) }
    }

    /// Gets the current value of the cell, initializing it with the result of
    /// calling `f` if it has not yet been initialized.
    pub fn get_or_init<'cx, 'a, C, F>(&self, cx: &'a mut C, f: F) -> &'cx T
    where
        C: Context<'cx>,
        F: FnOnce() -> T,
    {
        // Unwrap safety: The type bound LocalKey<T> and the fact that every LocalKey has a unique
        // id guarantees that the cell is only ever assigned instances of type T.
        let r: &T = LocalCell::get_or_init(cx, self.id(), || Box::new(f()))
            .downcast_ref()
            .unwrap();

        // Safety: Since the Box is immutable and heap-allocated, it's guaranteed not to
        // move or change for the duration of the context.
        unsafe { std::mem::transmute::<&'a T, &'cx T>(r) }
    }

    /// Gets the current value of the cell, initializing it with the result of
    /// calling `f` if it has not yet been initialized. Returns `Err` if the
    /// callback triggers a JavaScript exception.
    ///
    /// # Panics
    ///
    /// During the execution of `f`, calling any methods on this `LocalKey` that
    /// attempt to initialize it will panic.
    pub fn get_or_try_init<'cx, 'a, C, E, F>(&self, cx: &'a mut C, f: F) -> Result<&'cx T, E>
    where
        C: Context<'cx>,
        F: FnOnce(&mut C) -> Result<T, E>,
    {
        // Unwrap safety: The type bound LocalKey<T> and the fact that every LocalKey has a unique
        // id guarantees that the cell is only ever assigned instances of type T.
        let r: &T = LocalCell::get_or_try_init(cx, self.id(), |cx| Ok(Box::new(f(cx)?)))?
            .downcast_ref()
            .unwrap();

        // Safety: Since the Box is immutable and heap-allocated, it's guaranteed not to
        // move or change for the duration of the context.
        Ok(unsafe { std::mem::transmute::<&'a T, &'cx T>(r) })
    }
}

impl<T: Any + Send + Default + 'static> LocalKey<T> {
    /// Gets the current value of the cell, initializing it with the default value
    /// if it has not yet been initialized.
    pub fn get_or_init_default<'cx, 'a, C>(&self, cx: &'a mut C) -> &'cx T
    where
        C: Context<'cx>,
    {
        self.get_or_init(cx, Default::default)
    }
}
<commit_msg>Idiomatic Rust variable name in doc example<commit_after>//! Thread-local storage for JavaScript threads.
//!
//! At runtime, an instance of a Node.js addon can contain its own local storage,
//! which can then be shared and accessed as needed from Rust in a Neon module. This can
//! be useful for setting up long-lived state that needs to be shared between calls
//! of an addon's APIs.
//!
//! For example, an addon may wish to track the [thread ID][threadId] of each of its
//! instances:
//!
//! ```
//! # use neon::prelude::*;
//! # use neon::thread::LocalKey;
//! static THREAD_ID: LocalKey<u32> = LocalKey::new();
//!
//! pub fn thread_id<'cx, C: Context<'cx>>(cx: &mut C) -> NeonResult<u32> {
//!     THREAD_ID.get_or_try_init(cx, |cx| {
//!         let global = cx.global();
//!         let require: Handle<JsFunction> = global.get(cx, "require")?;
//!         let worker: Handle<JsObject> = require.call_with(cx)
//!             .arg(cx.string("node:worker_threads"))
//!             .apply(cx)?;
//!         let thread_id: Handle<JsNumber> = worker.get(cx, "threadId")?;
//!         Ok(thread_id.value(cx) as u32)
//!     }).cloned()
//! }
//! ```
//!
//! ### The Addon Lifecycle
//!
//! For some use cases, a single shared global constant stored in a `static` variable
//! might be sufficient:
//!
//! ```
//! static MY_CONSTANT: &'static str = "hello Neon";
//! ```
//!
//! This variable will be allocated when the addon is first loaded into the Node.js
//! process. This works fine for single-threaded applications, or global immutable
//! data.
//!
//! However, since the addition of [worker threads][workers] in Node v10,
//! modules can be instantiated multiple times in a single Node process. This means
//! that while the dynamically-loaded binary library (i.e., the Rust implementation of
//! the addon) is only loaded once in the running process, but its `main()` function
//! is executed multiple times with distinct module objects, once per application thread:
//!
//! ![The Node.js addon lifecycle, described in detail below.][lifecycle]
//!
//! This means that any thread-local data needs to be initialized separately for each
//! instance of the addon. This module provides a simple container type, [`LocalKey`](LocalKey),
//! for allocating and initializing thread-local data. (Technically, this data is stored in the
//! addon's [module instance][environment], which is equivalent to being thread-local.)
//!
//! A common example is when an addon defines a custom datatype, which cannot be used across
//! separate threads. The constructor for the datatype can be [rooted](crate::handle::Root) and
//! saved in thread-local storage:
//!
//! ```
//! # use neon::prelude::*;
//! # use neon::thread::LocalKey;
//! # fn initialize_my_datatype<'cx, C: Context<'cx>>(cx: &mut C) -> JsResult<'cx, JsFunction> { unimplemented!() }
//! static MY_CONSTRUCTOR: LocalKey<Root<JsFunction>> = LocalKey::new();
//!
//! pub fn my_constructor<'cx, C: Context<'cx>>(cx: &mut C) -> JsResult<'cx, JsFunction> {
//!     let constructor = MY_CONSTRUCTOR.get_or_try_init(cx, |cx| {
//!         let constructor: Handle<JsFunction> = initialize_my_datatype(cx)?;
//!         Ok(constructor.root(cx))
//!     })?;
//!     Ok(constructor.to_inner(cx))
//! }
//! ```
//!
//! Notice that if this code were implemented without a `LocalKey`, it would fail whenever
//! one thread stores an instance of the constructor and a different thread attempts to
//! access it with the call to [`to_inner()`](crate::handle::Root::to_inner).
//!
//! ### When to Use Thread-Local Storage
//!
//! Single-threaded applications don't generally need to worry about thread-local data.
//! There are two cases where Neon apps should consider storing static data in a
//! `LocalKey` storage cell:
//!
//! - **Multi-threaded applications:** If your Node application uses the `Worker`
//!   API, you'll want to store any static data that might get access from multiple
//!   threads in thread-local data.
//! - **Libraries:** If your addon is part of a library that could be used by multiple
//!   applications, you'll want to store static data in thread-local data in case the
//!   addon ends up instantiated by multiple threads in some future application.
//!
//! ### Why Not Use Standard TLS?
//!
//! Because the JavaScript engine may not tie JavaScript threads 1:1 to system threads,
//! it is recommended to use this module instead of the Rust standard thread-local storage
//! when tying data to a JavaScript thread.
//!
//! [environment]: https://nodejs.org/api/n-api.html#environment-life-cycle-apis
//! [lifecycle]: https://raw.githubusercontent.com/neon-bindings/neon/main/doc/lifecycle.png
//! [workers]: https://nodejs.org/api/worker_threads.html
//! [threadId]: https://nodejs.org/api/worker_threads.html#workerthreadid

use std::any::Any;
use std::marker::PhantomData;
use std::sync::atomic::{AtomicUsize, Ordering};

use once_cell::sync::OnceCell;

use crate::context::Context;
use crate::lifecycle::LocalCell;

static COUNTER: AtomicUsize = AtomicUsize::new(0);

fn next_id() -> usize {
    COUNTER.fetch_add(1, Ordering::SeqCst)
}

/// A JavaScript thread-local container that owns its contents, similar to
/// [`std::thread::LocalKey`](std::thread::LocalKey) but tied to a JavaScript thread rather
/// than a system thread.
///
/// ### Initialization and Destruction
///
/// Initialization is dynamically performed on the first call to one of the `init` methods
/// of `LocalKey`, and values that implement [`Drop`](std::ops::Drop) get destructed when
/// the JavaScript thread exits, i.e. when a worker thread terminates or the main thread
/// terminates on process exit.
#[derive(Default)]
pub struct LocalKey<T> {
    _type: PhantomData<T>,
    id: OnceCell<usize>,
}

impl<T> LocalKey<T> {
    /// Creates a new local value. This method is `const`, so it can be assigned to
    /// static variables.
    pub const fn new() -> Self {
        Self {
            _type: PhantomData,
            id: OnceCell::new(),
        }
    }

    fn id(&self) -> usize {
        *self.id.get_or_init(next_id)
    }
}

impl<T: Any + Send + 'static> LocalKey<T> {
    /// Gets the current value of the cell. Returns `None` if the cell has not
    /// yet been initialized.
    pub fn get<'cx, 'a, C>(&self, cx: &'a mut C) -> Option<&'cx T>
    where
        C: Context<'cx>,
    {
        // Unwrap safety: The type bound LocalKey<T> and the fact that every LocalKey has a unique
        // id guarantees that the cell is only ever assigned instances of type T.
        let r: Option<&T> =
            LocalCell::get(cx, self.id()).map(|value| value.downcast_ref().unwrap());

        // Safety: Since the Box is immutable and heap-allocated, it's guaranteed not to
        // move or change for the duration of the context.
        unsafe { std::mem::transmute::<Option<&'a T>, Option<&'cx T>>(r) }
    }

    /// Gets the current value of the cell, initializing it with the result of
    /// calling `f` if it has not yet been initialized.
    pub fn get_or_init<'cx, 'a, C, F>(&self, cx: &'a mut C, f: F) -> &'cx T
    where
        C: Context<'cx>,
        F: FnOnce() -> T,
    {
        // Unwrap safety: The type bound LocalKey<T> and the fact that every LocalKey has a unique
        // id guarantees that the cell is only ever assigned instances of type T.
        let r: &T = LocalCell::get_or_init(cx, self.id(), || Box::new(f()))
            .downcast_ref()
            .unwrap();

        // Safety: Since the Box is immutable and heap-allocated, it's guaranteed not to
        // move or change for the duration of the context.
        unsafe { std::mem::transmute::<&'a T, &'cx T>(r) }
    }

    /// Gets the current value of the cell, initializing it with the result of
    /// calling `f` if it has not yet been initialized. Returns `Err` if the
    /// callback triggers a JavaScript exception.
    ///
    /// # Panics
    ///
    /// During the execution of `f`, calling any methods on this `LocalKey` that
    /// attempt to initialize it will panic.
    pub fn get_or_try_init<'cx, 'a, C, E, F>(&self, cx: &'a mut C, f: F) -> Result<&'cx T, E>
    where
        C: Context<'cx>,
        F: FnOnce(&mut C) -> Result<T, E>,
    {
        // Unwrap safety: The type bound LocalKey<T> and the fact that every LocalKey has a unique
        // id guarantees that the cell is only ever assigned instances of type T.
        let r: &T = LocalCell::get_or_try_init(cx, self.id(), |cx| Ok(Box::new(f(cx)?)))?
            .downcast_ref()
            .unwrap();

        // Safety: Since the Box is immutable and heap-allocated, it's guaranteed not to
        // move or change for the duration of the context.
        Ok(unsafe { std::mem::transmute::<&'a T, &'cx T>(r) })
    }
}

impl<T: Any + Send + Default + 'static> LocalKey<T> {
    /// Gets the current value of the cell, initializing it with the default value
    /// if it has not yet been initialized.
    pub fn get_or_init_default<'cx, 'a, C>(&self, cx: &'a mut C) -> &'cx T
    where
        C: Context<'cx>,
    {
        self.get_or_init(cx, Default::default)
    }
}
<|endoftext|>


<commit_before>mod shells;

// Std
use std::io::Write;

// Internal
use clap::{App, AppSettings, Arg};
pub use shells::*;

/// Generator trait which can be used to write generators
pub trait Generator {
    /// Returns the file name that is created when this generator is called during compile time.
    ///
    /// # Examples
    ///
    /// ```
    /// # use std::io::Write;
    /// # use clap::App;
    /// use clap_generate::Generator;
    ///
    /// pub struct Fish;
    ///
    /// impl Generator for Fish {
    /// #   fn generate(app: &App, buf: &mut dyn Write) {}
    ///     fn file_name(name: &str) -> String {
    ///         format!("{}.fish", name)
    ///     }
    /// }
    /// ```
    fn file_name(name: &str) -> String;

    /// Generates output out of [`clap::App`](../clap/struct.App.html).
    ///
    /// # Examples
    ///
    /// The following example generator displays the [`clap::App`](../clap/struct.App.html)
    /// as if it is printed using [`std::println`](https://doc.rust-lang.org/std/macro.println.html).
    ///
    /// ```
    /// use std::{io::Write, fmt::write};
    /// use clap::App;
    /// use clap_generate::Generator;
    ///
    /// pub struct ClapDebug;
    ///
    /// impl Generator for ClapDebug {
    ///     fn generate(app: &App, buf: &mut dyn Write) {
    ///         write!(buf, "{}", app).unwrap();
    ///     }
    /// #   fn file_name(name: &str) -> String {
    /// #    name.into()
    /// #   }
    /// }
    /// ```
    fn generate(app: &App, buf: &mut dyn Write);

    /// Gets all subcommands including child subcommands in the form of `("name", "bin_name")`.
    ///
    /// Subcommand `rustup toolchain install` would be converted to
    /// `("install", "rustup toolchain install")`.
    fn all_subcommands(app: &App) -> Vec<(String, String)> {
        let mut subcmds: Vec<_> = Self::subcommands(app);

        for sc_v in app.get_subcommands().map(|s| Self::all_subcommands(&s)) {
            subcmds.extend(sc_v);
        }

        subcmds
    }

    /// Finds the subcommand [`clap::App`][clap] from the given [`clap::App`][clap] with the given path.
    ///
    /// **NOTE:** `path` should not contain the root `bin_name`.
    ///
    /// [clap]: ../clap/struct.App.html
    fn find_subcommand_with_path<'help, 'app>(
        p: &'app App<'help>,
        path: Vec<&str>,
    ) -> &'app App<'help> {
        let mut app = p;

        for sc in path {
            app = app.find_subcommand(sc).unwrap();
        }

        app
    }

    /// Gets subcommands of [`clap::App`](../clap/struct.App.html) in the form of `("name", "bin_name")`.
    ///
    /// Subcommand `rustup toolchain install` would be converted to
    /// `("install", "rustup toolchain install")`.
    fn subcommands(p: &App) -> Vec<(String, String)> {
        debug!("subcommands: name={}", p.get_name());
        debug!("subcommands: Has subcommands...{:?}", p.has_subcommands());

        let mut subcmds = vec![];

        if !p.has_subcommands() {
            return subcmds;
        }

        for sc in p.get_subcommands() {
            let sc_bin_name = sc.get_bin_name().unwrap();

            debug!(
                "subcommands:iter: name={}, bin_name={}",
                sc.get_name(),
                sc_bin_name
            );

            subcmds.push((sc.get_name().to_string(), sc_bin_name.to_string()));
        }

        subcmds
    }

    /// Gets all the short options, their visible aliases and flags of a [`clap::App`](../clap/struct.App.html).
    /// Includes `h` and `V` depending on the [`clap::AppSettings`](../clap/enum.AppSettings.html).
    fn shorts_and_visible_aliases<'help>(p: &App<'help>) -> Vec<char> {
        debug!("shorts: name={}", p.get_name());

        let mut shorts_and_visible_aliases: Vec<char> = p
            .get_arguments()
            .filter_map(|a| {
                if a.get_index().is_none() {
                    if a.get_visible_short_aliases().is_some() && a.get_short().is_some() {
                        let mut shorts_and_visible_aliases = a.get_visible_short_aliases().unwrap();
                        shorts_and_visible_aliases.push(a.get_short().unwrap());
                        Some(shorts_and_visible_aliases)
                    } else if a.get_visible_short_aliases().is_none() && a.get_short().is_some() {
                        Some(vec![a.get_short().unwrap()])
                    } else {
                        None
                    }
                } else {
                    None
                }
            })
            .flatten()
            .collect();

        if shorts_and_visible_aliases
            .iter()
            .find(|x| **x == 'h')
            .is_none()
        {
            shorts_and_visible_aliases.push('h');
        }

        if !p.is_set(AppSettings::DisableVersion)
            && shorts_and_visible_aliases
                .iter()
                .find(|x| **x == 'V')
                .is_none()
        {
            shorts_and_visible_aliases.push('V');
        }

        shorts_and_visible_aliases
    }

    /// Gets all the long options and flags of a [`clap::App`](../clap/struct.App.html).
    /// Includes `help` and `version` depending on the [`clap::AppSettings`](../clap/enum.AppSettings.html).
    fn longs<'help>(p: &App<'help>) -> Vec<String> {
        debug!("longs: name={}", p.get_name());

        let mut longs: Vec<String> = p
            .get_arguments()
            .filter_map(|a| {
                if a.get_index().is_none() && a.get_long().is_some() {
                    Some(a.get_long().unwrap().to_string())
                } else {
                    None
                }
            })
            .collect();

        if longs.iter().find(|x| **x == "help").is_none() {
            longs.push(String::from("help"));
        }

        if !p.is_set(AppSettings::DisableVersion)
            && longs.iter().find(|x| **x == "version").is_none()
        {
            longs.push(String::from("version"));
        }

        longs
    }

    /// Gets all the flags of a [`clap::App`](../clap/struct.App.html).
    /// Includes `help` and `version` depending on the [`clap::AppSettings`](../clap/enum.AppSettings.html).
    fn flags<'help>(p: &App<'help>) -> Vec<Arg<'help>> {
        debug!("flags: name={}", p.get_name());

        let mut flags: Vec<_> = p.get_flags_no_heading().cloned().collect();

        if flags.iter().find(|x| x.get_name() == "help").is_none() {
            flags.push(
                Arg::new("help")
                    .short('h')
                    .long("help")
                    .about("Prints help information"),
            );
        }

        if !p.is_set(AppSettings::DisableVersion)
            && flags.iter().find(|x| x.get_name() == "version").is_none()
        {
            flags.push(
                Arg::new("version")
                    .short('V')
                    .long("version")
                    .about("Prints version information"),
            );
        }

        flags
    }
}

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

    struct Foo;

    impl Generator for Foo {
        fn generate(_: &App, _: &mut dyn Write) {}

        fn file_name(name: &str) -> String {
            name.to_string()
        }
    }

    fn common() -> App<'static> {
        let mut app = App::new("myapp")
            .subcommand(
                App::new("test").subcommand(App::new("config")).arg(
                    Arg::new("file")
                        .short('f')
                        .short_alias('c')
                        .visible_short_alias('p')
                        .long("file"),
                ),
            )
            .subcommand(App::new("hello"))
            .bin_name("my-app");

        app._build();
        app._build_bin_names();
        app
    }

    #[test]
    fn test_subcommands() {
        let app = common();

        assert_eq!(
            Foo::subcommands(&app),
            vec![
                ("test".to_string(), "my-app test".to_string()),
                ("hello".to_string(), "my-app hello".to_string()),
                ("help".to_string(), "my-app help".to_string()),
            ]
        );
    }

    #[test]
    fn test_all_subcommands() {
        let app = common();

        assert_eq!(
            Foo::all_subcommands(&app),
            vec![
                ("test".to_string(), "my-app test".to_string()),
                ("hello".to_string(), "my-app hello".to_string()),
                ("help".to_string(), "my-app help".to_string()),
                ("config".to_string(), "my-app test config".to_string()),
            ]
        );
    }

    #[test]
    fn test_find_subcommand_with_path() {
        let app = common();
        let sc_app = Foo::find_subcommand_with_path(&app, "test config".split(' ').collect());

        assert_eq!(sc_app.get_name(), "config");
    }

    #[test]
    fn test_flags() {
        let app = common();
        let flags = Foo::flags(&app);

        assert_eq!(flags.len(), 2);
        assert_eq!(flags[0].get_long(), Some("help"));
        assert_eq!(flags[1].get_long(), Some("version"));

        let sc_flags = Foo::flags(Foo::find_subcommand_with_path(&app, vec!["test"]));

        assert_eq!(sc_flags.len(), 3);
        assert_eq!(sc_flags[0].get_long(), Some("file"));
        assert_eq!(sc_flags[1].get_long(), Some("help"));
        assert_eq!(sc_flags[2].get_long(), Some("version"));
    }

    #[test]
    fn test_shorts() {
        let app = common();
        let shorts = Foo::shorts_and_visible_aliases(&app);

        assert_eq!(shorts.len(), 2);
        assert_eq!(shorts[0], 'h');
        assert_eq!(shorts[1], 'V');

        let sc_shorts =
            Foo::shorts_and_visible_aliases(Foo::find_subcommand_with_path(&app, vec!["test"]));

        assert_eq!(sc_shorts.len(), 4);
        assert_eq!(sc_shorts[0], 'p');
        assert_eq!(sc_shorts[1], 'f');
        assert_eq!(sc_shorts[2], 'h');
        assert_eq!(sc_shorts[3], 'V');
    }

    #[test]
    fn test_longs() {
        let app = common();
        let longs = Foo::longs(&app);

        assert_eq!(longs.len(), 2);
        assert_eq!(longs[0], "help");
        assert_eq!(longs[1], "version");

        let sc_longs = Foo::longs(Foo::find_subcommand_with_path(&app, vec!["test"]));

        assert_eq!(sc_longs.len(), 3);
        assert_eq!(sc_longs[0], "file");
        assert_eq!(sc_longs[1], "help");
        assert_eq!(sc_longs[2], "version");
    }
}
<commit_msg>refactor: Replace `it.find(...).is_none()` with `!it.any(...)`.<commit_after>mod shells;

// Std
use std::io::Write;

// Internal
use clap::{App, AppSettings, Arg};
pub use shells::*;

/// Generator trait which can be used to write generators
pub trait Generator {
    /// Returns the file name that is created when this generator is called during compile time.
    ///
    /// # Examples
    ///
    /// ```
    /// # use std::io::Write;
    /// # use clap::App;
    /// use clap_generate::Generator;
    ///
    /// pub struct Fish;
    ///
    /// impl Generator for Fish {
    /// #   fn generate(app: &App, buf: &mut dyn Write) {}
    ///     fn file_name(name: &str) -> String {
    ///         format!("{}.fish", name)
    ///     }
    /// }
    /// ```
    fn file_name(name: &str) -> String;

    /// Generates output out of [`clap::App`](../clap/struct.App.html).
    ///
    /// # Examples
    ///
    /// The following example generator displays the [`clap::App`](../clap/struct.App.html)
    /// as if it is printed using [`std::println`](https://doc.rust-lang.org/std/macro.println.html).
    ///
    /// ```
    /// use std::{io::Write, fmt::write};
    /// use clap::App;
    /// use clap_generate::Generator;
    ///
    /// pub struct ClapDebug;
    ///
    /// impl Generator for ClapDebug {
    ///     fn generate(app: &App, buf: &mut dyn Write) {
    ///         write!(buf, "{}", app).unwrap();
    ///     }
    /// #   fn file_name(name: &str) -> String {
    /// #    name.into()
    /// #   }
    /// }
    /// ```
    fn generate(app: &App, buf: &mut dyn Write);

    /// Gets all subcommands including child subcommands in the form of `("name", "bin_name")`.
    ///
    /// Subcommand `rustup toolchain install` would be converted to
    /// `("install", "rustup toolchain install")`.
    fn all_subcommands(app: &App) -> Vec<(String, String)> {
        let mut subcmds: Vec<_> = Self::subcommands(app);

        for sc_v in app.get_subcommands().map(|s| Self::all_subcommands(&s)) {
            subcmds.extend(sc_v);
        }

        subcmds
    }

    /// Finds the subcommand [`clap::App`][clap] from the given [`clap::App`][clap] with the given path.
    ///
    /// **NOTE:** `path` should not contain the root `bin_name`.
    ///
    /// [clap]: ../clap/struct.App.html
    fn find_subcommand_with_path<'help, 'app>(
        p: &'app App<'help>,
        path: Vec<&str>,
    ) -> &'app App<'help> {
        let mut app = p;

        for sc in path {
            app = app.find_subcommand(sc).unwrap();
        }

        app
    }

    /// Gets subcommands of [`clap::App`](../clap/struct.App.html) in the form of `("name", "bin_name")`.
    ///
    /// Subcommand `rustup toolchain install` would be converted to
    /// `("install", "rustup toolchain install")`.
    fn subcommands(p: &App) -> Vec<(String, String)> {
        debug!("subcommands: name={}", p.get_name());
        debug!("subcommands: Has subcommands...{:?}", p.has_subcommands());

        let mut subcmds = vec![];

        if !p.has_subcommands() {
            return subcmds;
        }

        for sc in p.get_subcommands() {
            let sc_bin_name = sc.get_bin_name().unwrap();

            debug!(
                "subcommands:iter: name={}, bin_name={}",
                sc.get_name(),
                sc_bin_name
            );

            subcmds.push((sc.get_name().to_string(), sc_bin_name.to_string()));
        }

        subcmds
    }

    /// Gets all the short options, their visible aliases and flags of a [`clap::App`](../clap/struct.App.html).
    /// Includes `h` and `V` depending on the [`clap::AppSettings`](../clap/enum.AppSettings.html).
    fn shorts_and_visible_aliases<'help>(p: &App<'help>) -> Vec<char> {
        debug!("shorts: name={}", p.get_name());

        let mut shorts_and_visible_aliases: Vec<char> = p
            .get_arguments()
            .filter_map(|a| {
                if a.get_index().is_none() {
                    if a.get_visible_short_aliases().is_some() && a.get_short().is_some() {
                        let mut shorts_and_visible_aliases = a.get_visible_short_aliases().unwrap();
                        shorts_and_visible_aliases.push(a.get_short().unwrap());
                        Some(shorts_and_visible_aliases)
                    } else if a.get_visible_short_aliases().is_none() && a.get_short().is_some() {
                        Some(vec![a.get_short().unwrap()])
                    } else {
                        None
                    }
                } else {
                    None
                }
            })
            .flatten()
            .collect();

        if !shorts_and_visible_aliases.iter().any(|&x| x == 'h') {
            shorts_and_visible_aliases.push('h');
        }

        if !p.is_set(AppSettings::DisableVersion)
            && !shorts_and_visible_aliases.iter().any(|&x| x == 'V')
        {
            shorts_and_visible_aliases.push('V');
        }

        shorts_and_visible_aliases
    }

    /// Gets all the long options and flags of a [`clap::App`](../clap/struct.App.html).
    /// Includes `help` and `version` depending on the [`clap::AppSettings`](../clap/enum.AppSettings.html).
    fn longs<'help>(p: &App<'help>) -> Vec<String> {
        debug!("longs: name={}", p.get_name());

        let mut longs: Vec<String> = p
            .get_arguments()
            .filter_map(|a| {
                if a.get_index().is_none() && a.get_long().is_some() {
                    Some(a.get_long().unwrap().to_string())
                } else {
                    None
                }
            })
            .collect();

        if !longs.iter().any(|x| *x == "help") {
            longs.push(String::from("help"));
        }

        if !p.is_set(AppSettings::DisableVersion) && !longs.iter().any(|x| *x == "version") {
            longs.push(String::from("version"));
        }

        longs
    }

    /// Gets all the flags of a [`clap::App`](../clap/struct.App.html).
    /// Includes `help` and `version` depending on the [`clap::AppSettings`](../clap/enum.AppSettings.html).
    fn flags<'help>(p: &App<'help>) -> Vec<Arg<'help>> {
        debug!("flags: name={}", p.get_name());

        let mut flags: Vec<_> = p.get_flags_no_heading().cloned().collect();

        if !flags.iter().any(|x| x.get_name() == "help") {
            flags.push(
                Arg::new("help")
                    .short('h')
                    .long("help")
                    .about("Prints help information"),
            );
        }

        if !p.is_set(AppSettings::DisableVersion)
            && !flags.iter().any(|x| x.get_name() == "version")
        {
            flags.push(
                Arg::new("version")
                    .short('V')
                    .long("version")
                    .about("Prints version information"),
            );
        }

        flags
    }
}

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

    struct Foo;

    impl Generator for Foo {
        fn generate(_: &App, _: &mut dyn Write) {}

        fn file_name(name: &str) -> String {
            name.to_string()
        }
    }

    fn common() -> App<'static> {
        let mut app = App::new("myapp")
            .subcommand(
                App::new("test").subcommand(App::new("config")).arg(
                    Arg::new("file")
                        .short('f')
                        .short_alias('c')
                        .visible_short_alias('p')
                        .long("file"),
                ),
            )
            .subcommand(App::new("hello"))
            .bin_name("my-app");

        app._build();
        app._build_bin_names();
        app
    }

    #[test]
    fn test_subcommands() {
        let app = common();

        assert_eq!(
            Foo::subcommands(&app),
            vec![
                ("test".to_string(), "my-app test".to_string()),
                ("hello".to_string(), "my-app hello".to_string()),
                ("help".to_string(), "my-app help".to_string()),
            ]
        );
    }

    #[test]
    fn test_all_subcommands() {
        let app = common();

        assert_eq!(
            Foo::all_subcommands(&app),
            vec![
                ("test".to_string(), "my-app test".to_string()),
                ("hello".to_string(), "my-app hello".to_string()),
                ("help".to_string(), "my-app help".to_string()),
                ("config".to_string(), "my-app test config".to_string()),
            ]
        );
    }

    #[test]
    fn test_find_subcommand_with_path() {
        let app = common();
        let sc_app = Foo::find_subcommand_with_path(&app, "test config".split(' ').collect());

        assert_eq!(sc_app.get_name(), "config");
    }

    #[test]
    fn test_flags() {
        let app = common();
        let flags = Foo::flags(&app);

        assert_eq!(flags.len(), 2);
        assert_eq!(flags[0].get_long(), Some("help"));
        assert_eq!(flags[1].get_long(), Some("version"));

        let sc_flags = Foo::flags(Foo::find_subcommand_with_path(&app, vec!["test"]));

        assert_eq!(sc_flags.len(), 3);
        assert_eq!(sc_flags[0].get_long(), Some("file"));
        assert_eq!(sc_flags[1].get_long(), Some("help"));
        assert_eq!(sc_flags[2].get_long(), Some("version"));
    }

    #[test]
    fn test_shorts() {
        let app = common();
        let shorts = Foo::shorts_and_visible_aliases(&app);

        assert_eq!(shorts.len(), 2);
        assert_eq!(shorts[0], 'h');
        assert_eq!(shorts[1], 'V');

        let sc_shorts =
            Foo::shorts_and_visible_aliases(Foo::find_subcommand_with_path(&app, vec!["test"]));

        assert_eq!(sc_shorts.len(), 4);
        assert_eq!(sc_shorts[0], 'p');
        assert_eq!(sc_shorts[1], 'f');
        assert_eq!(sc_shorts[2], 'h');
        assert_eq!(sc_shorts[3], 'V');
    }

    #[test]
    fn test_longs() {
        let app = common();
        let longs = Foo::longs(&app);

        assert_eq!(longs.len(), 2);
        assert_eq!(longs[0], "help");
        assert_eq!(longs[1], "version");

        let sc_longs = Foo::longs(Foo::find_subcommand_with_path(&app, vec!["test"]));

        assert_eq!(sc_longs.len(), 3);
        assert_eq!(sc_longs[0], "file");
        assert_eq!(sc_longs[1], "help");
        assert_eq!(sc_longs[2], "version");
    }
}
<|endoftext|>


<commit_before>// Lumol, an extensible molecular simulation engine
// Copyright (C) 2015-2016 G. Fraux — BSD license

//! Multi-dimmensional arrays based on ndarray
use ndarray::{Array, Ix};

use std::ops::{Index, IndexMut};
use std::cmp::PartialEq;
use types::Zero;

/// Two dimensional tensors, based on ndarray.
///
/// Most of the methods are simply forwarded to ndarray, so also look the doc
/// for this crate. This array type mainly supports indexing using tuples as
/// indices and is though as storage backend for multi-dimensional data.
///
/// ```
/// # use lumol::Array2;
/// let mut a = Array2::zeros((3, 5));
///
/// assert_eq!(a[(0, 4)], 0.0);
///
/// a[(0, 4)] = 7.0;
/// assert_eq!(a[(0, 4)], 7.0);
/// ```
#[derive(Debug, Clone)]
pub struct Array2<T>(Array<T, (Ix, Ix)>);

impl<T> Array2<T> {
    /// Get the shape of the array
    /// # Examples
    /// ```
    /// # use lumol::Array2;
    /// let a: Array2<f64> = Array2::zeros((3, 5));
    /// assert_eq!(a.shape(), (3, 5));
    /// ```
    pub fn shape(&self) -> (Ix, Ix) {
        let shape = self.0.shape();
        (shape[0], shape[1])
    }
}

impl<T: Zero + Clone> Array2<T> {
    /// Create a new `Array2` of the specified `size` filled with the
    /// `Zero::zero` return value.
    ///
    /// # Examples
    ///
    /// ```
    /// # use lumol::Array2;
    /// let a: Array2<f64> = Array2::zeros((8, 5));
    /// assert_eq!(a[(6, 2)], 0.0);
    /// ```
    pub fn zeros(size: (Ix, Ix)) -> Array2<T> {
        Array2(Array::<T, (Ix, Ix)>::zeros(size))
    }

    /// Resize the array if the current size is not `size`, and fill the
    /// new array with zeros.
    ///
    /// # Examples
    ///
    /// ```
    /// # use lumol::Array2;
    /// let mut a = Array2::zeros((8, 5));
    ///
    /// a[(3, 3)] = 42.0;
    ///
    /// // This does nothing
    /// a.resize_if_different((8, 5));
    /// assert_eq!(a[(3, 3)], 42.0);
    ///
    /// // This allocates a new array
    /// a.resize_if_different((8, 9));
    /// assert_eq!(a[(3, 3)], 0.0);
    /// ```
    pub fn resize_if_different(&mut self, size: (Ix, Ix)) {
        if self.0.shape() != &[size.0, size.1] {
            *self = Array2::zeros(size);
        }
    }
}

impl<T: Clone> Array2<T> {
    /// Assign the given scalar to all entries in this array
    /// # Examples
    /// ```
    /// # use lumol::Array2;
    /// let mut a = Array2::zeros((8, 5));
    /// a.assign(33.0);
    ///
    /// assert_eq!(a[(3, 4)], 33.0);
    /// ```
    pub fn assign(&mut self, value: T) {
        self.0.assign_scalar(&value);
    }
}

impl<T: Default> Array2<T> {
    /// Create a new `Array2` of the specified `size` filled with the
    /// `Default::default` return value.
    ///
    /// # Examples
    ///
    /// ```
    /// # use lumol::Array2;
    /// let a: Array2<f64> = Array2::zeros((8, 5));
    /// let b: Array2<f64> = Array2::default((8, 5));
    ///
    /// assert_eq!(a, b);
    /// ```
    pub fn default(size: (Ix, Ix)) -> Array2<T> {
        Array2(Array::<T, (Ix, Ix)>::default(size))
    }
}

impl<T: PartialEq> PartialEq for Array2<T> {
    fn eq(&self, other: &Array2<T>) -> bool {
        self == other
    }
}

impl<T> Index<(Ix, Ix)> for Array2<T> {
    type Output = T;
    fn index(&self, index: (Ix, Ix)) -> &T {
        unsafe {
            // ndarray does the check for us in debug builds
            self.0.uget(index)
        }
    }
}

impl<T> IndexMut<(Ix, Ix)> for Array2<T> {
    fn index_mut(&mut self, index: (Ix, Ix)) -> &mut T {
        unsafe {
            // ndarray does the check for us in debug builds
            self.0.uget_mut(index)
        }
    }
}

/******************************************************************************/

/// Three dimensional tensors, based on ndarray
///
/// Most of the methods are simply forwarded to ndarray, so also look the doc
/// for this crate. This array type mainly supports indexing using tuples as
/// indices and is though as storage backend for multi-dimensional data.
///
/// ```
/// # use lumol::Array3;
/// let mut a = Array3::zeros((3, 5, 2));
///
/// assert_eq!(a[(0, 4, 1)], 0.0);
///
/// a[(0, 4, 1)] = 7.0;
/// assert_eq!(a[(0, 4, 1)], 7.0);
/// ```
#[derive(Debug, Clone)]
pub struct Array3<T>(Array<T, (Ix, Ix, Ix)>);

impl<T> Array3<T> {
    /// Get the shape of the array.
    /// # Examples
    /// ```
    /// # use lumol::Array3;
    /// let a: Array3<f64> = Array3::zeros((3, 5, 7));
    /// assert_eq!(a.shape(), (3, 5, 7));
    /// ```
    pub fn shape(&self) -> (Ix, Ix, Ix) {
        let shape = self.0.shape();
        (shape[0], shape[1], shape[2])
    }
}

impl<T: Zero + Clone> Array3<T> {
    /// Create a new `Array3` of the specified `size` filled with the
    /// `Zero::zero` return value.
    ///
    /// # Examples
    ///
    /// ```
    /// # use lumol::Array3;
    /// let a: Array3<f64> = Array3::zeros((8, 5, 2));
    /// assert_eq!(a[(6, 2, 0)], 0.0);
    /// ```
    pub fn zeros(size: (Ix, Ix, Ix)) -> Array3<T> {
        Array3(Array::<T, (Ix, Ix, Ix)>::zeros(size))
    }

    /// Resize the array if the current size is not `size`, and fill the
    /// new array with zeros.
    ///
    /// # Examples
    ///
    /// ```
    /// # use lumol::Array3;
    /// let mut a = Array3::zeros((8, 5, 7));
    ///
    /// a[(3, 3, 3)] = 42.0;
    ///
    /// // This does nothing
    /// a.resize_if_different((8, 5, 7));
    /// assert_eq!(a[(3, 3, 3)], 42.0);
    ///
    /// // This allocates a new array
    /// a.resize_if_different((8, 5, 6));
    /// assert_eq!(a[(3, 3, 3)], 0.0);
    /// ```
    pub fn resize_if_different(&mut self, size: (Ix, Ix, Ix)) {
        if self.0.shape() != &[size.0, size.1, size.2] {
            *self = Array3::zeros(size);
        }
    }
}

impl<T: Clone> Array3<T> {
    /// Assign the given scalar to all entries in this array
    pub fn assign(&mut self, value: T) {
        self.0.assign_scalar(&value);
    }
}

impl<T: Default> Array3<T> {
    /// Create a new `Array3` of the specified `size` filled with the
    /// `Default::default` return value.
    /// `Default::default` return value.
    ///
    /// # Examples
    ///
    /// ```
    /// # use lumol::Array3;
    /// let a: Array3<f64> = Array3::zeros((8, 5, 2));
    /// let b: Array3<f64> = Array3::default((8, 5, 2));
    ///
    /// assert_eq!(a, b);
    /// ```
    pub fn default(size: (Ix, Ix, Ix)) -> Array3<T>{
        Array3(Array::<T, (Ix, Ix, Ix)>::default(size))
    }
}

impl<T> Index<(Ix, Ix, Ix)> for Array3<T> {
    type Output = T;
    fn index(&self, index: (Ix, Ix, Ix)) -> &T {
        unsafe {
            // ndarray does the check for us in debug builds
            self.0.uget(index)
        }
    }
}

impl<T> IndexMut<(Ix, Ix, Ix)> for Array3<T> {
    fn index_mut(&mut self, index: (Ix, Ix, Ix)) -> &mut T {
        unsafe {
            // ndarray does the check for us in debug builds
            self.0.uget_mut(index)
        }
    }
}

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

        #[test]
        fn zeros() {
            let a: Array2<f64> = Array2::zeros((3, 4));
            for i in 0..3 {
                for j in 0..4 {
                    assert_eq!(a[(i, j)], 0.0);
                }
            }
        }

        #[test]
        fn default() {
            #[derive(Clone)] struct F64(f64);
            impl Default for F64 {fn default() -> F64 { F64(42.0) }}

            let a: Array2<F64> = Array2::default((3, 4));
            for i in 0..3 {
                for j in 0..4 {
                    assert_eq!(a[(i, j)].0, 42.0);
                }
            }
        }

        #[test]
        fn resize() {
            let mut a: Array2<f64> = Array2::zeros((3, 4));
            assert_eq!(a.shape(), (3, 4));
            a[(1, 1)] = 42.0;

            a.resize_if_different((7, 90));
            assert_eq!(a.shape(), (7, 90));
            assert_eq!(a[(1, 1)], 0.0);

            a[(1, 1)] = 42.0;
            a.resize_if_different((7, 90));
            assert_eq!(a[(1, 1)], 42.0);
        }

        #[test]
        fn index() {
            let mut a: Array2<f64> = Array2::zeros((3, 4));

            assert_eq!(a[(1, 3)], 0.0);

            a[(1, 3)] = 45.0;
            assert_eq!(a[(1, 3)], 45.0);
        }

        #[test]
        #[should_panic]
        #[cfg(debug_assertions)]
        fn out_of_bound_1() {
            let a: Array2<f64> = Array2::zeros((3, 4));
            let _ = a[(5, 1)];
        }

        #[test]
        #[should_panic]
        #[cfg(debug_assertions)]
        fn out_of_bound_2() {
            let a: Array2<f64> = Array2::zeros((3, 4));
            let _ = a[(2, 7)];
        }
    }

    mod array3 {
        use super::super::Array3;

        #[test]
        fn zeros() {
            let a: Array3<f64> = Array3::zeros((3, 4, 8));
            for i in 0..3 {
                for j in 0..4 {
                    for k in 0..8 {
                        assert_eq!(a[(i, j, k)], 0.0);
                    }
                }
            }
        }

        #[test]
        fn default() {
            #[derive(Clone)] struct F64(f64);
            impl Default for F64 {fn default() -> F64 { F64(42.0) }}

            let a: Array3<F64> = Array3::default((3, 4, 8));
            for i in 0..3 {
                for j in 0..4 {
                    for k in 0..8 {
                        assert_eq!(a[(i, j, k)].0, 42.0);
                    }
                }
            }
        }

        #[test]
        fn resize() {
            let mut a: Array3<f64> = Array3::zeros((3, 4, 5));
            assert_eq!(a.shape(), (3, 4, 5));
            a[(1, 1, 1)] = 42.0;

            a.resize_if_different((7, 90, 8));
            assert_eq!(a.shape(), (7, 90, 8));
            assert_eq!(a[(1, 1, 1)], 0.0);

            a[(1, 1, 1)] = 42.0;
            a.resize_if_different((7, 90, 8));
            assert_eq!(a[(1, 1, 1)], 42.0);
        }

        #[test]
        fn index() {
            let mut a: Array3<f64> = Array3::zeros((3, 4, 5));
            assert_eq!(a[(1, 3, 2)], 0.0);

            a[(1, 3, 2)] = 45.0;
            assert_eq!(a[(1, 3, 2)], 45.0);
        }

        #[test]
        #[should_panic]
        #[cfg(debug_assertions)]
        fn out_of_bound_1() {
            let a: Array3<f64> = Array3::zeros((3, 4, 89));
            let _ = a[(5, 1, 6)];
        }

        #[test]
        #[should_panic]
        #[cfg(debug_assertions)]
        fn out_of_bound_2() {
            let a: Array3<f64> = Array3::zeros((3, 4, 89));
            let _ = a[(2, 67, 6)];
        }

        #[test]
        #[should_panic]
        #[cfg(debug_assertions)]
        fn out_of_bound_3() {
            let a: Array3<f64> = Array3::zeros((3, 4, 89));
            let _ = a[(2, 1, 600)];
        }
    }
}
<commit_msg>Fix a stack overflow error in PartialEq implementation<commit_after>// Lumol, an extensible molecular simulation engine
// Copyright (C) 2015-2016 G. Fraux — BSD license

//! Multi-dimmensional arrays based on ndarray
use ndarray::{Array, Ix};

use std::ops::{Index, IndexMut};
use types::Zero;

/// Two dimensional tensors, based on ndarray.
///
/// Most of the methods are simply forwarded to ndarray, so also look the doc
/// for this crate. This array type mainly supports indexing using tuples as
/// indices and is though as storage backend for multi-dimensional data.
///
/// ```
/// # use lumol::Array2;
/// let mut a = Array2::zeros((3, 5));
///
/// assert_eq!(a[(0, 4)], 0.0);
///
/// a[(0, 4)] = 7.0;
/// assert_eq!(a[(0, 4)], 7.0);
/// ```
#[derive(Debug, Clone, PartialEq)]
pub struct Array2<T>(Array<T, (Ix, Ix)>);

impl<T> Array2<T> {
    /// Get the shape of the array
    /// # Examples
    /// ```
    /// # use lumol::Array2;
    /// let a: Array2<f64> = Array2::zeros((3, 5));
    /// assert_eq!(a.shape(), (3, 5));
    /// ```
    pub fn shape(&self) -> (Ix, Ix) {
        let shape = self.0.shape();
        (shape[0], shape[1])
    }
}

impl<T: Zero + Clone> Array2<T> {
    /// Create a new `Array2` of the specified `size` filled with the
    /// `Zero::zero` return value.
    ///
    /// # Examples
    ///
    /// ```
    /// # use lumol::Array2;
    /// let a: Array2<f64> = Array2::zeros((8, 5));
    /// assert_eq!(a[(6, 2)], 0.0);
    /// ```
    pub fn zeros(size: (Ix, Ix)) -> Array2<T> {
        Array2(Array::<T, (Ix, Ix)>::zeros(size))
    }

    /// Resize the array if the current size is not `size`, and fill the
    /// new array with zeros.
    ///
    /// # Examples
    ///
    /// ```
    /// # use lumol::Array2;
    /// let mut a = Array2::zeros((8, 5));
    ///
    /// a[(3, 3)] = 42.0;
    ///
    /// // This does nothing
    /// a.resize_if_different((8, 5));
    /// assert_eq!(a[(3, 3)], 42.0);
    ///
    /// // This allocates a new array
    /// a.resize_if_different((8, 9));
    /// assert_eq!(a[(3, 3)], 0.0);
    /// ```
    pub fn resize_if_different(&mut self, size: (Ix, Ix)) {
        if self.0.shape() != &[size.0, size.1] {
            *self = Array2::zeros(size);
        }
    }
}

impl<T: Clone> Array2<T> {
    /// Assign the given scalar to all entries in this array
    /// # Examples
    /// ```
    /// # use lumol::Array2;
    /// let mut a = Array2::zeros((8, 5));
    /// a.assign(33.0);
    ///
    /// assert_eq!(a[(3, 4)], 33.0);
    /// ```
    pub fn assign(&mut self, value: T) {
        self.0.assign_scalar(&value);
    }
}

impl<T: Default> Array2<T> {
    /// Create a new `Array2` of the specified `size` filled with the
    /// `Default::default` return value.
    ///
    /// # Examples
    ///
    /// ```
    /// # use lumol::Array2;
    /// let a: Array2<f64> = Array2::zeros((8, 5));
    /// let b: Array2<f64> = Array2::default((8, 5));
    ///
    /// assert_eq!(a, b);
    /// ```
    pub fn default(size: (Ix, Ix)) -> Array2<T> {
        Array2(Array::<T, (Ix, Ix)>::default(size))
    }
}

impl<T> Index<(Ix, Ix)> for Array2<T> {
    type Output = T;
    fn index(&self, index: (Ix, Ix)) -> &T {
        unsafe {
            // ndarray does the check for us in debug builds
            self.0.uget(index)
        }
    }
}

impl<T> IndexMut<(Ix, Ix)> for Array2<T> {
    fn index_mut(&mut self, index: (Ix, Ix)) -> &mut T {
        unsafe {
            // ndarray does the check for us in debug builds
            self.0.uget_mut(index)
        }
    }
}

/******************************************************************************/

/// Three dimensional tensors, based on ndarray
///
/// Most of the methods are simply forwarded to ndarray, so also look the doc
/// for this crate. This array type mainly supports indexing using tuples as
/// indices and is though as storage backend for multi-dimensional data.
///
/// ```
/// # use lumol::Array3;
/// let mut a = Array3::zeros((3, 5, 2));
///
/// assert_eq!(a[(0, 4, 1)], 0.0);
///
/// a[(0, 4, 1)] = 7.0;
/// assert_eq!(a[(0, 4, 1)], 7.0);
/// ```
#[derive(Debug, Clone, PartialEq)]
pub struct Array3<T>(Array<T, (Ix, Ix, Ix)>);

impl<T> Array3<T> {
    /// Get the shape of the array.
    /// # Examples
    /// ```
    /// # use lumol::Array3;
    /// let a: Array3<f64> = Array3::zeros((3, 5, 7));
    /// assert_eq!(a.shape(), (3, 5, 7));
    /// ```
    pub fn shape(&self) -> (Ix, Ix, Ix) {
        let shape = self.0.shape();
        (shape[0], shape[1], shape[2])
    }
}

impl<T: Zero + Clone> Array3<T> {
    /// Create a new `Array3` of the specified `size` filled with the
    /// `Zero::zero` return value.
    ///
    /// # Examples
    ///
    /// ```
    /// # use lumol::Array3;
    /// let a: Array3<f64> = Array3::zeros((8, 5, 2));
    /// assert_eq!(a[(6, 2, 0)], 0.0);
    /// ```
    pub fn zeros(size: (Ix, Ix, Ix)) -> Array3<T> {
        Array3(Array::<T, (Ix, Ix, Ix)>::zeros(size))
    }

    /// Resize the array if the current size is not `size`, and fill the
    /// new array with zeros.
    ///
    /// # Examples
    ///
    /// ```
    /// # use lumol::Array3;
    /// let mut a = Array3::zeros((8, 5, 7));
    ///
    /// a[(3, 3, 3)] = 42.0;
    ///
    /// // This does nothing
    /// a.resize_if_different((8, 5, 7));
    /// assert_eq!(a[(3, 3, 3)], 42.0);
    ///
    /// // This allocates a new array
    /// a.resize_if_different((8, 5, 6));
    /// assert_eq!(a[(3, 3, 3)], 0.0);
    /// ```
    pub fn resize_if_different(&mut self, size: (Ix, Ix, Ix)) {
        if self.0.shape() != &[size.0, size.1, size.2] {
            *self = Array3::zeros(size);
        }
    }
}

impl<T: Clone> Array3<T> {
    /// Assign the given scalar to all entries in this array
    pub fn assign(&mut self, value: T) {
        self.0.assign_scalar(&value);
    }
}

impl<T: Default> Array3<T> {
    /// Create a new `Array3` of the specified `size` filled with the
    /// `Default::default` return value.
    /// `Default::default` return value.
    ///
    /// # Examples
    ///
    /// ```
    /// # use lumol::Array3;
    /// let a: Array3<f64> = Array3::zeros((8, 5, 2));
    /// let b: Array3<f64> = Array3::default((8, 5, 2));
    ///
    /// assert_eq!(a, b);
    /// ```
    pub fn default(size: (Ix, Ix, Ix)) -> Array3<T>{
        Array3(Array::<T, (Ix, Ix, Ix)>::default(size))
    }
}

impl<T> Index<(Ix, Ix, Ix)> for Array3<T> {
    type Output = T;
    fn index(&self, index: (Ix, Ix, Ix)) -> &T {
        unsafe {
            // ndarray does the check for us in debug builds
            self.0.uget(index)
        }
    }
}

impl<T> IndexMut<(Ix, Ix, Ix)> for Array3<T> {
    fn index_mut(&mut self, index: (Ix, Ix, Ix)) -> &mut T {
        unsafe {
            // ndarray does the check for us in debug builds
            self.0.uget_mut(index)
        }
    }
}

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

        #[test]
        fn zeros() {
            let a: Array2<f64> = Array2::zeros((3, 4));
            for i in 0..3 {
                for j in 0..4 {
                    assert_eq!(a[(i, j)], 0.0);
                }
            }
        }

        #[test]
        fn default() {
            #[derive(Clone)] struct F64(f64);
            impl Default for F64 {fn default() -> F64 { F64(42.0) }}

            let a: Array2<F64> = Array2::default((3, 4));
            for i in 0..3 {
                for j in 0..4 {
                    assert_eq!(a[(i, j)].0, 42.0);
                }
            }
        }

        #[test]
        fn resize() {
            let mut a: Array2<f64> = Array2::zeros((3, 4));
            assert_eq!(a.shape(), (3, 4));
            a[(1, 1)] = 42.0;

            a.resize_if_different((7, 90));
            assert_eq!(a.shape(), (7, 90));
            assert_eq!(a[(1, 1)], 0.0);

            a[(1, 1)] = 42.0;
            a.resize_if_different((7, 90));
            assert_eq!(a[(1, 1)], 42.0);
        }

        #[test]
        fn index() {
            let mut a: Array2<f64> = Array2::zeros((3, 4));

            assert_eq!(a[(1, 3)], 0.0);

            a[(1, 3)] = 45.0;
            assert_eq!(a[(1, 3)], 45.0);
        }

        #[test]
        #[should_panic]
        #[cfg(debug_assertions)]
        fn out_of_bound_1() {
            let a: Array2<f64> = Array2::zeros((3, 4));
            let _ = a[(5, 1)];
        }

        #[test]
        #[should_panic]
        #[cfg(debug_assertions)]
        fn out_of_bound_2() {
            let a: Array2<f64> = Array2::zeros((3, 4));
            let _ = a[(2, 7)];
        }
    }

    mod array3 {
        use super::super::Array3;

        #[test]
        fn zeros() {
            let a: Array3<f64> = Array3::zeros((3, 4, 8));
            for i in 0..3 {
                for j in 0..4 {
                    for k in 0..8 {
                        assert_eq!(a[(i, j, k)], 0.0);
                    }
                }
            }
        }

        #[test]
        fn default() {
            #[derive(Clone)] struct F64(f64);
            impl Default for F64 {fn default() -> F64 { F64(42.0) }}

            let a: Array3<F64> = Array3::default((3, 4, 8));
            for i in 0..3 {
                for j in 0..4 {
                    for k in 0..8 {
                        assert_eq!(a[(i, j, k)].0, 42.0);
                    }
                }
            }
        }

        #[test]
        fn resize() {
            let mut a: Array3<f64> = Array3::zeros((3, 4, 5));
            assert_eq!(a.shape(), (3, 4, 5));
            a[(1, 1, 1)] = 42.0;

            a.resize_if_different((7, 90, 8));
            assert_eq!(a.shape(), (7, 90, 8));
            assert_eq!(a[(1, 1, 1)], 0.0);

            a[(1, 1, 1)] = 42.0;
            a.resize_if_different((7, 90, 8));
            assert_eq!(a[(1, 1, 1)], 42.0);
        }

        #[test]
        fn index() {
            let mut a: Array3<f64> = Array3::zeros((3, 4, 5));
            assert_eq!(a[(1, 3, 2)], 0.0);

            a[(1, 3, 2)] = 45.0;
            assert_eq!(a[(1, 3, 2)], 45.0);
        }

        #[test]
        #[should_panic]
        #[cfg(debug_assertions)]
        fn out_of_bound_1() {
            let a: Array3<f64> = Array3::zeros((3, 4, 89));
            let _ = a[(5, 1, 6)];
        }

        #[test]
        #[should_panic]
        #[cfg(debug_assertions)]
        fn out_of_bound_2() {
            let a: Array3<f64> = Array3::zeros((3, 4, 89));
            let _ = a[(2, 67, 6)];
        }

        #[test]
        #[should_panic]
        #[cfg(debug_assertions)]
        fn out_of_bound_3() {
            let a: Array3<f64> = Array3::zeros((3, 4, 89));
            let _ = a[(2, 1, 600)];
        }
    }
}
<|endoftext|>


<commit_before>use rustc_middle::mir;
use rustc_span::Symbol;
use rustc_target::spec::abi::Abi;

use crate::*;
use shims::foreign_items::EmulateByNameResult;

impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {}

pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> {
    fn emulate_foreign_item_by_name(
        &mut self,
        link_name: Symbol,
        abi: Abi,
        args: &[OpTy<'tcx, Tag>],
        dest: &PlaceTy<'tcx, Tag>,
        _ret: mir::BasicBlock,
    ) -> InterpResult<'tcx, EmulateByNameResult<'mir, 'tcx>> {
        let this = self.eval_context_mut();
        match link_name.as_str() {
            _ => return Ok(EmulateByNameResult::NotSupported),
        }
        Ok(EmulateByNameResult::NeedsJumping)
    }
}
<commit_msg>Add `pthread_attr_getstack` shim<commit_after>use rustc_middle::mir;
use rustc_span::Symbol;
use rustc_target::spec::abi::Abi;

use crate::*;
use shims::foreign_items::EmulateByNameResult;

impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {}

pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> {
    fn emulate_foreign_item_by_name(
        &mut self,
        link_name: Symbol,
        abi: Abi,
        args: &[OpTy<'tcx, Tag>],
        dest: &PlaceTy<'tcx, Tag>,
        _ret: mir::BasicBlock,
    ) -> InterpResult<'tcx, EmulateByNameResult<'mir, 'tcx>> {
        let this = self.eval_context_mut();
        match link_name.as_str() {
            // Querying system information
            "pthread_attr_getstack" => {
                // We don't support "pthread_attr_setstack", so we just pretend all stacks have the same values here.
                let [attr_place, addr_place, size_place] =
                    this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
                this.deref_operand(attr_place)?;
                let addr_place = this.deref_operand(addr_place)?;
                let size_place = this.deref_operand(size_place)?;

                this.write_scalar(
                    Scalar::from_uint(STACK_ADDR, this.pointer_size()),
                    &addr_place.into(),
                )?;
                this.write_scalar(
                    Scalar::from_uint(STACK_SIZE, this.pointer_size()),
                    &size_place.into(),
                )?;

                // Return success (`0`).
                this.write_null(dest)?;
            }
            _ => return Ok(EmulateByNameResult::NotSupported),
        }
        Ok(EmulateByNameResult::NeedsJumping)
    }
}
<|endoftext|>


<commit_before>use num::Num;
use point::Point2D;
use size::Size2D;
use cmp::{Eq, Ord};

pub struct Rect<T:Copy Num> {
    origin: Point2D<T>,
    size: Size2D<T>

}

pub pure fn Rect<T:Copy Num>(origin: Point2D<T>, size: Size2D<T>) -> Rect<T> {
    return Rect {
        origin: copy origin,
        size: copy size
    }
}

impl<T: Copy Num Ord> Rect<T> {
    pure fn intersects(other: &Rect<T>) -> bool {
        self.origin.x < other.origin.x.add(&other.size.width) &&
       other.origin.x <  self.origin.x.add(&self.size.width) &&
        self.origin.y < other.origin.y.add(&other.size.height) &&
       other.origin.y <  self.origin.y.add(&self.size.height)
    }
}

impl<T: Copy Num Ord> Rect<T> {
    pure fn intersection(other: &Rect<T>) -> Option<Rect<T>> {
        if !self.intersects(other) { return None }

        Some(Rect(Point2D(max(self.origin.x, other.origin.x),
                            max(self.origin.y, other.origin.y)),
                  Size2D(min(self.origin.x.add(&self.size.width),
                            other.origin.x.add(&other.size.width)),
                         min(self.origin.y.add(&self.size.height),
                            other.origin.y.add(&other.size.height)))
        ))
    }

    pure fn union(other: &Rect<T>) -> Rect<T> {
        Rect {
            origin: Point2D(min(self.origin.x, other.origin.x),
                            min(self.origin.y, other.origin.y)),
            size: Size2D(max(self.origin.x.add(&self.size.width),
                            other.origin.x.add(&other.size.width)),
                         max(self.origin.y.add(&self.size.height),
                            other.origin.y.add(&other.size.height)))
        }
    }
}

impl<T: Copy Num> Rect<T> {
    pure fn translate(other: &Point2D<T>) -> Rect<T> {
        Rect {
            origin: Point2D(self.origin.x.add(&other.x),
                            self.origin.y.add(&other.y)),
            size: copy self.size
        }
    }
}

impl<T: Copy Num Eq> Rect<T>: Eq {
    pure fn eq(other: &Rect<T>) -> bool {
        self.origin == other.origin && self.size == other.size
    }
    pure fn ne(other: &Rect<T>) -> bool {
        !self.eq(other)
    }
}

pub pure fn min<T: Copy Num Ord>(x: T, y: T) -> T {
    if x <= y { x } else { y }
}

pub pure fn max<T: Copy Num Ord>(x: T, y: T) -> T {
    if x >= y { x } else { y }
}
<commit_msg>Add some simple unit tests for max, min, translate()<commit_after>use num::Num;
use point::Point2D;
use size::Size2D;
use cmp::{Eq, Ord};

pub struct Rect<T:Copy Num> {
    origin: Point2D<T>,
    size: Size2D<T>

}

pub pure fn Rect<T:Copy Num>(origin: Point2D<T>, size: Size2D<T>) -> Rect<T> {
    return Rect {
        origin: copy origin,
        size: copy size
    }
}

impl<T: Copy Num Ord> Rect<T> {
    pure fn intersects(other: &Rect<T>) -> bool {
        self.origin.x < other.origin.x.add(&other.size.width) &&
       other.origin.x <  self.origin.x.add(&self.size.width) &&
        self.origin.y < other.origin.y.add(&other.size.height) &&
       other.origin.y <  self.origin.y.add(&self.size.height)
    }
}

impl<T: Copy Num Ord> Rect<T> {
    pure fn intersection(other: &Rect<T>) -> Option<Rect<T>> {
        if !self.intersects(other) { return None }

        Some(Rect(Point2D(max(self.origin.x, other.origin.x),
                            max(self.origin.y, other.origin.y)),
                  Size2D(min(self.origin.x.add(&self.size.width),
                            other.origin.x.add(&other.size.width)),
                         min(self.origin.y.add(&self.size.height),
                            other.origin.y.add(&other.size.height)))
        ))
    }

    pure fn union(other: &Rect<T>) -> Rect<T> {
        Rect {
            origin: Point2D(min(self.origin.x, other.origin.x),
                            min(self.origin.y, other.origin.y)),
            size: Size2D(max(self.origin.x.add(&self.size.width),
                            other.origin.x.add(&other.size.width)),
                         max(self.origin.y.add(&self.size.height),
                            other.origin.y.add(&other.size.height)))
        }
    }
}

impl<T: Copy Num> Rect<T> {
    pure fn translate(other: &Point2D<T>) -> Rect<T> {
        Rect {
            origin: Point2D(self.origin.x.add(&other.x),
                            self.origin.y.add(&other.y)),
            size: copy self.size
        }
    }
}

impl<T: Copy Num Eq> Rect<T>: Eq {
    pure fn eq(other: &Rect<T>) -> bool {
        self.origin == other.origin && self.size == other.size
    }
    pure fn ne(other: &Rect<T>) -> bool {
        !self.eq(other)
    }
}

pub pure fn min<T: Copy Num Ord>(x: T, y: T) -> T {
    if x <= y { x } else { y }
}

pub pure fn max<T: Copy Num Ord>(x: T, y: T) -> T {
    if x >= y { x } else { y }
}

#[test]
fn test_min_max() {
    assert min(0, 1) == 0;
    assert min(-1.0, 0.0) == -1.0;

    assert max(0, 1) == 1;
    assert max(-1.0, 0.0) == 0.0;
}

#[test]
fn test_translate() {
    let p = Rect(Point2D(0, 0), Size2D(50, 40));
    let pp = p.translate(&Point2D(10,15));

    assert pp.size.width == 50;
    assert pp.size.height == 40;
    assert pp.origin.x == 10;
    assert pp.origin.y == 15;

    let r = Rect(Point2D(-10, -5), Size2D(50, 40));
    let rr = r.translate(&Point2D(0,-10));

    assert rr.size.width == 50;
    assert rr.size.height == 40;
    assert rr.origin.x == -10;
    assert rr.origin.y == -15;
}<|endoftext|>


<commit_before>trait Alive {
    fn alive(&self);
}

// Obj: simple struct
// ////////////////////////////////////////////////////////

struct Obj {
    name: String,
}

impl Obj {
    fn new( name: &str ) -> Obj {
        let o = Obj{ name: name.to_string() };
        let ptr: *const Obj = &o;
        println!("+ Constructed Obj name={} @{:?}", name, ptr);
        o
    }
}

impl Alive for Obj {
    fn alive(&self) {
        let ptr: *const Obj = self;
        println!("= Obj name={} is alive @{:?}", self.name, ptr);
    }
}

impl Drop for Obj {
    fn drop(&mut self) {
        let ptr: *const Obj = self;
        println!("- Dropping Obj name={} @{:?}", self.name, ptr);
    }
}

impl Clone for Obj {
    fn clone(&self) -> Self {
        Obj::new( &self.name[..] )
    }

    fn clone_from(&mut self, source: &Self) {
        self.name = source.name.clone();
    }
}

// Obj: copyable struct
// ////////////////////////////////////////////////////////

#[derive(Copy, Clone)]
struct CopyObj {
    name: &'static str,
}

impl CopyObj {
    fn new( name: &'static str ) -> CopyObj {
        let o = CopyObj{ name: name };
        let ptr: *const CopyObj = &o;
        println!("+ Constructed CopyObj name={} @{:?}", name, ptr);
        o
    }
}

impl Alive for CopyObj {
    fn alive(&self) {
        let ptr: *const CopyObj = self;
        println!("= CopyObj name={} is alive @{:?}", self.name, ptr);
    }
}

// Remarks: Drop cannot be implemented for "Copy" types.

// checking
// ////////////////////////////////////////////////////////

fn print_alive_by_ref<T: Alive>(o: &T) {
    println!("> enter print_alive_by_ref()");
    o.alive();
    println!("< exit print_alive_by_ref()");
}

fn print_alive_by_mut_ref<T: Alive>(o: &mut T) {
    println!("> enter print_alive_by_mut_ref()");
    o.alive();
    println!("< exit print_alive_by_mut_ref()");
}

fn print_alive_by_value<T: Alive>(o: T) {
    println!("> enter print_alive_by_value()");
    o.alive();
    println!("< exit print_alive_by_value()");
}

fn main() {
    println!("> enter main()");
    let mut o1 = Obj::new( "main" );
    o1.alive();
    print_alive_by_ref(&o1);
    print_alive_by_mut_ref(&mut o1);
    {
        let mut o1_clone = o1.clone();
        o1_clone.name = "main_clone".to_string();
        o1_clone.alive();
        print_alive_by_value(o1); // pass by move semantic
        println!("returned from print_alive_by_value, o1 should have been destroyed");
        o1_clone.alive();
    }
    println!("exit sub-scope, o1_clone should have been destroyed");
    println!("");

    let mut o2 = CopyObj::new( "main_copyable" );
    o2.alive();
    print_alive_by_ref(&o2);
    print_alive_by_mut_ref(&mut o2);
    let mut o2_clone = o2.clone();
    o2_clone.name = "main_copyable_clone";
    o2_clone.alive();
    print_alive_by_value(o2); // pass by copy semantic
    // because CopyObj implements the Copy trait, it can still be use
    o2.alive();
    o2_clone.alive();
    println!("");
    println!("< exit main()");
}
<commit_msg>Added checking for Box.<commit_after>use std::rc::Rc;
use std::borrow::Borrow;

trait Alive {
    fn alive(&self);
}

// Implement for single-threaded referenced counted pointer by forwarding to the underlying type.
impl<T: Alive> Alive for Rc<T> {
    fn alive(&self) {
        let obj: &T = self.borrow();
        obj.alive();
    }
}

// Implement for Box
impl<T: Alive> Alive for Box<T> {
    fn alive(&self) {
        let obj: &T = self.borrow();
        obj.alive();
    }
}

// Obj: simple struct
// ////////////////////////////////////////////////////////

struct Obj {
    name: String,
}

impl Obj {
    fn new( name: &str ) -> Obj {
        let o = Obj{ name: name.to_string() };
        let ptr: *const Obj = &o;
        println!("+ Constructed Obj name={} @{:?}", name, ptr);
        o
    }
}

impl Alive for Obj {
    fn alive(&self) {
        let ptr: *const Obj = self;
        println!("= Obj name={} is alive @{:?}", self.name, ptr);
    }
}

impl Drop for Obj {
    fn drop(&mut self) {
        let ptr: *const Obj = self;
        println!("- Dropping Obj name={} @{:?}", self.name, ptr);
    }
}

impl Clone for Obj {
    fn clone(&self) -> Self {
        Obj::new( &self.name[..] )
    }

    fn clone_from(&mut self, source: &Self) {
        self.name = source.name.clone();
    }
}

// Obj: copyable struct
// ////////////////////////////////////////////////////////

#[derive(Copy, Clone)]
struct CopyObj {
    name: &'static str,
}

impl CopyObj {
    fn new( name: &'static str ) -> CopyObj {
        let o = CopyObj{ name: name };
        let ptr: *const CopyObj = &o;
        println!("+ Constructed CopyObj name={} @{:?}", name, ptr);
        o
    }
}

impl Alive for CopyObj {
    fn alive(&self) {
        let ptr: *const CopyObj = self;
        println!("= CopyObj name={} is alive @{:?}", self.name, ptr);
    }
}

// Remarks: Drop cannot be implemented for "Copy" types.

// checking
// ////////////////////////////////////////////////////////

fn print_alive_by_ref<T: Alive>(o: &T) {
    println!("> enter print_alive_by_ref()");
    o.alive();
    println!("< exit print_alive_by_ref()");
}

fn print_alive_by_mut_ref<T: Alive>(o: &mut T) {
    println!("> enter print_alive_by_mut_ref()");
    o.alive();
    println!("< exit print_alive_by_mut_ref()");
}

fn print_alive_by_value<T: Alive>(o: T) {
    println!("> enter print_alive_by_value()");
    o.alive();
    println!("< exit print_alive_by_value()");
}

fn main() {
    println!("> enter main()");

    // Non-copyable Obj (pass using move semantic)
    let mut o1 = Obj::new( "main" );
    o1.alive();
    print_alive_by_ref(&o1);
    print_alive_by_mut_ref(&mut o1);
    {
        let mut o1_clone = o1.clone();
        o1_clone.name = "main_clone".to_string();
        o1_clone.alive();
        print_alive_by_value(o1); // pass by move semantic
        println!("returned from print_alive_by_value, o1 should have been destroyed");
        o1_clone.alive();
    }
    println!("exit sub-scope, o1_clone should have been destroyed");
    println!("");

    // Copyable Obj (pass using copy)
    let mut o2 = CopyObj::new( "main_copyable" );
    o2.alive();
    print_alive_by_ref(&o2);
    print_alive_by_mut_ref(&mut o2);
    let mut o2_clone = o2.clone();
    o2_clone.name = "main_copyable_clone";
    o2_clone.alive();
    print_alive_by_value(o2); // pass by copy semantic
    // because CopyObj implements the Copy trait, it can still be use
    o2.alive();
    o2_clone.alive();
    println!("");

    // Ref counted Non-copyable obj
    let mut ro1 = Rc::new( Obj::new("rc_main") );
    ro1.alive();
    print_alive_by_ref(&ro1);
    print_alive_by_mut_ref(&mut ro1);
// Q: what trait is needed?!?
//    print_alive_by_mut_ref(&mut ro1.get_mut().unwrap());
    print_alive_by_value(ro1); // pass by move semantic
    println!("returned from print_alive_by_value, rc_main should have been destroyed");
    println!("");

    // Ref counted Non-copyable obj (keeping another reference on the ref counted pointer)
    let ro2 = Rc::new( Obj::new("rc_main2") );
    ro2.alive();
    {
        let ro2_clone = ro2.clone(); // "copy" the ref count ptr, increasing the number of reference
        print_alive_by_value(ro2); // pass by move semantic
        ro2_clone.alive();
    }
    println!("exit sub-scope, rc_main2 should have been destroyed");
    println!("");

    // Boxed non-copyable obj (hold a pointer to a dynamically allocated Obj)
    let mut bo1 = Box::new( Obj::new("box_main") );
    bo1.alive();
    print_alive_by_ref(&bo1);
    print_alive_by_mut_ref(&mut bo1);
    print_alive_by_ref(&*bo1);
    {
        let mut bo1_clone = bo1.clone(); // allocate a new clone of the pointed value
        (*bo1_clone).name = "box_main_clone".to_string();
        bo1_clone.alive();
        print_alive_by_value(bo1); // pass by move semantic
        println!("returned from print_alive_by_value, box_main should have been destroyed");
    }
    println!("exit sub-scope, box_main_clone should have been destroyed");
    println!("");

    println!("< exit main()");
}
<|endoftext|>