<commit_before>// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.

//! This is generic code for platforms that use the Tls organization described below. It's
//! called var1 because it's the first variant described in Drepper's Tls paper.
//!
//! The memory is organized as follows:
//!
//! ----------------------------------------------------------------------
//! | private area | dtv area | padding |          tls area              |
//! ----------------------------------------------------------------------
//!       ________/ \_______
//!      /the thread pointer\
//!
//! The alignment of the thread pointer must be the maximum of the alignments of the
//! private area, the dtv area, and the tls area. The padding is calculated by rounding
//! the size of the dtv area up to a multiple of the tls area's alignment. For example, if
//! the dtv area has size 8 and the tls area has alignment 16, then the padding is 8
//! bytes.
//!
//! The dtv area is unused in statically linked programs (which is all that tls supports
//! at the moment) and is unused in tls.

use core::{mem, ptr};
use super::super::{STATIC_IMAGE, Private};
use super::{DTVR_ALIGN, DTVR_SIZE};
use base::prelude::*;

/// Calculates the maximum alignment of the private area, the dtv area, and the tls area.
///
/// [argument, tls_align]
/// The alignment of the tls area.
///
/// [return_value]
/// The calculated alignment.
fn max_align(tls_align: usize) -> usize {
    // This is the maximum of the three values, using that they are all powers of two.
    //
    // Another way to write this:
    //
    // !(!(tls_align - 1) & !(mem::align_of::<Private>() - 1) & !(DTVR_ALIGN - 1)) + 1
    //
    // The way below has 3 instructions instead of the 5 above (remember that the last two
    // numbers are known at compile time). But I'm not sure how expensive `leading_zeros`
    // is.

    (isize::min() as usize) // this is the number with only the highest bit set
        >> (tls_align | mem::align_of::<Private>() | DTVR_ALIGN).leading_zeros()
}

/// Calculates the size required for the tls block.
///
/// [return_value]
/// The calculated size.
///
/// = Remarks
///
/// The size returned is a little bit more than what is strictly required, but it allows
/// the user to pass arbitrary pointers to the function below.
pub fn mem_size() -> usize {
    let (tls_size, tls_align) = match unsafe { STATIC_IMAGE } {
        Some(i) => (i.mem_size, i.alignment),
        _ => (0, 1),
    };
    max_align(tls_align) - 1 + mem::size_of::<Private>() +
        align!(DTVR_SIZE, [%] tls_align) + tls_size
}

/// Installs the tls into memory.
///
/// [argument, mem]
/// The memory in which the tls will be placed.
///
/// [return_value]
/// Returns a pointer to the private area and the thread pointer.
///
/// = Remarks
///
/// `mem` does not have any alignment requirements. However, the memory pointed to must
/// have size at least `mem_size()` or the behavior is undefined.
///
/// The memory passed to this function must be zeroed or the behavior is undefined.
pub unsafe fn place_tls(mut mem: *mut u8) -> (*mut Private, *mut u8) {
    let (private, tp);

    if let Some(ref image) = STATIC_IMAGE {
        let max_align = max_align(image.alignment);

        mem = align!(mem as usize, [+] mem::size_of::<Private>(),
                     [%] max_align) as *mut u8;
        private = mem as *mut Private;
        mem = mem.add(mem::size_of::<Private>());
        tp = mem;
        mem = mem.add(align!(DTVR_SIZE, [%] image.alignment));
        ptr::memcpy(mem, image.addr, image.file_size);
    } else {
        let max_align = max_align(1);

        mem = align!(mem as usize, [+] mem::size_of::<Private>(),
                     [%] max_align) as *mut u8;
        private = mem as *mut Private;
        tp = mem.add(mem::size_of::<Private>());
    }

    (private, tp)
}

/// Calculates the position of the private area.
///
/// [argument, tp]
/// The thread pointer.
///
/// [return_value]
/// A pointer to the private area.
pub unsafe fn get_private(tp: *mut u8) -> *mut Private {
    mem.sub(mem::size_of::<Private>()) as *mut Private
}
<commit_msg>fix tls var1 typo<commit_after>// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.

//! This is generic code for platforms that use the Tls organization described below. It's
//! called var1 because it's the first variant described in Drepper's Tls paper.
//!
//! The memory is organized as follows:
//!
//! ----------------------------------------------------------------------
//! | private area | dtv area | padding |          tls area              |
//! ----------------------------------------------------------------------
//!       ________/ \_______
//!      /the thread pointer\
//!
//! The alignment of the thread pointer must be the maximum of the alignments of the
//! private area, the dtv area, and the tls area. The padding is calculated by rounding
//! the size of the dtv area up to a multiple of the tls area's alignment. For example, if
//! the dtv area has size 8 and the tls area has alignment 16, then the padding is 8
//! bytes.
//!
//! The dtv area is unused in statically linked programs (which is all that tls supports
//! at the moment) and is unused in tls.

use core::{mem, ptr};
use super::super::{STATIC_IMAGE, Private};
use super::{DTVR_ALIGN, DTVR_SIZE};
use base::prelude::*;

/// Calculates the maximum alignment of the private area, the dtv area, and the tls area.
///
/// [argument, tls_align]
/// The alignment of the tls area.
///
/// [return_value]
/// The calculated alignment.
fn max_align(tls_align: usize) -> usize {
    // This is the maximum of the three values, using that they are all powers of two.
    //
    // Another way to write this:
    //
    // !(!(tls_align - 1) & !(mem::align_of::<Private>() - 1) & !(DTVR_ALIGN - 1)) + 1
    //
    // The way below has 3 instructions instead of the 5 above (remember that the last two
    // numbers are known at compile time). But I'm not sure how expensive `leading_zeros`
    // is.

    (isize::min() as usize) // this is the number with only the highest bit set
        >> (tls_align | mem::align_of::<Private>() | DTVR_ALIGN).leading_zeros()
}

/// Calculates the size required for the tls block.
///
/// [return_value]
/// The calculated size.
///
/// = Remarks
///
/// The size returned is a little bit more than what is strictly required, but it allows
/// the user to pass arbitrary pointers to the function below.
pub fn mem_size() -> usize {
    let (tls_size, tls_align) = match unsafe { STATIC_IMAGE } {
        Some(i) => (i.mem_size, i.alignment),
        _ => (0, 1),
    };
    max_align(tls_align) - 1 + mem::size_of::<Private>() +
        align!(DTVR_SIZE, [%] tls_align) + tls_size
}

/// Installs the tls into memory.
///
/// [argument, mem]
/// The memory in which the tls will be placed.
///
/// [return_value]
/// Returns a pointer to the private area and the thread pointer.
///
/// = Remarks
///
/// `mem` does not have any alignment requirements. However, the memory pointed to must
/// have size at least `mem_size()` or the behavior is undefined.
///
/// The memory passed to this function must be zeroed or the behavior is undefined.
pub unsafe fn place_tls(mut mem: *mut u8) -> (*mut Private, *mut u8) {
    let (private, tp);

    if let Some(ref image) = STATIC_IMAGE {
        let max_align = max_align(image.alignment);

        mem = align!(mem as usize, [+] mem::size_of::<Private>(),
                     [%] max_align) as *mut u8;
        private = mem as *mut Private;
        mem = mem.add(mem::size_of::<Private>());
        tp = mem;
        mem = mem.add(align!(DTVR_SIZE, [%] image.alignment));
        ptr::memcpy(mem, image.addr, image.file_size);
    } else {
        let max_align = max_align(1);

        mem = align!(mem as usize, [+] mem::size_of::<Private>(),
                     [%] max_align) as *mut u8;
        private = mem as *mut Private;
        tp = mem.add(mem::size_of::<Private>());
    }

    (private, tp)
}

/// Calculates the position of the private area.
///
/// [argument, tp]
/// The thread pointer.
///
/// [return_value]
/// A pointer to the private area.
pub unsafe fn get_private(tp: *mut u8) -> *mut Private {
    tp.sub(mem::size_of::<Private>()) as *mut Private
}
<|endoftext|>


<commit_before><commit_msg>24 => 1000<commit_after><|endoftext|>


<commit_before>use std::collections::HashMap;

use args::SubCommand;
use args::flagarg::FlagArg;
use args::optarg::OptArg;
use args::posarg::PosArg;

/// Used to get information about the arguments that
/// where supplied to the program at runtime.
///
///
/// Fields of `ArgMatches` aren't designed to be used directly, only
/// the methods in order to query information.
///
/// # Example
///
/// ```no_run
/// # use clap::{App, Arg};
/// let matches = App::new("MyApp")
/// // adding of arguments and configuration goes here...
/// #                    .arg(Arg::new("config")
/// #                               .long("config")
/// #                               .required(true)
/// #                               .takes_value(true))
/// #                    .arg(Arg::new("debug")
/// #                                   .short("d")
/// #                                   .multiple(true))
///                     .get_matches();
/// // if you had an argument named "output" that takes a value
/// if let Some(o) = matches.value_of("output") {
///     println!("Value for output: {}", o);
/// }
///
/// // Although not advised, if you have a required argument
/// // you can call .unwrap() because the program will exit long before
/// // here at noticing the user didn't supply a required argument...
/// // use at your own risk ;)
/// println!("Config file: {}", matches.value_of("config").unwrap());
///
/// // You can check the present of an argument
/// if matches.is_present("debug") {
///     // Checking if "debug" was present was necessary,
///     // as occurrences returns 0 if a flag isn't found
///     // but we can check how many times "debug" was found
///     // if we allow multiple (if multiple isn't allowed it always be 1 or 0)
///     if matches.occurrences_of("debug") > 1 {
///         println!("Debug mode is REALLY on");
///     } else {
///         println!("Debug mode kind of on");
///     }
/// }
///
/// // You can get the sub-matches of a particular subcommand (in this case "test")
/// // If "test" had it's own "-l" flag you could check for it's presence accordingly
/// if let Some(ref matches) = matches.subcommand_matches("test") {
///     if matches.is_present("list") {
///         println!("Printing testing lists...");
///     } else {
///         println!("Not printing testing lists...");
///     }
/// }
pub struct ArgMatches<'a> {
    // pub matches_of: &'static str,
    pub flags: HashMap<&'a str, FlagArg>,
    pub opts: HashMap<&'a str, OptArg>,
    pub positionals: HashMap<&'a str, PosArg>,
    pub subcommand: Option<Box<SubCommand<'a>>>
}

impl<'a> ArgMatches<'a> {
    /// Creates a new instance of `ArgMatches`. This ins't called directly, but
    /// through the `.get_matches()` method of `App`
    ///
    /// # Example
    ///
    /// ```no_run
    /// # use clap::{App, Arg};
    /// let matches = App::new("myprog").get_matches();
    /// ```
    pub fn new() -> ArgMatches<'a> {
        ArgMatches {
            // matches_of: name,
            flags: HashMap::new(),
            opts: HashMap::new(),
            positionals: HashMap::new(),
            subcommand: None
        }
    }

    /// Gets the value of a specific option or positional argument (i.e. an argument that takes
    /// an additional value at runtime). If the option wasn't present at runtime
    /// it returns `None`.
    ///
    /// *NOTE:* If getting a value for an option or positional argument that allows multiples,
    /// prefer `values_of()` as `value_of()` will only return the _*first*_ value.
    ///
    /// # Example
    ///
    /// ```no_run
    /// # use clap::{App, Arg};
    /// # let matches = App::new("myapp").arg(Arg::new("output").takes_value(true)).get_matches();
    /// if let Some(o) = matches.value_of("output") {
    ///        println!("Value for output: {}", o);
    /// }
    /// ```
    pub fn value_of<'n>(&self, name: &'n str) -> Option<&str> {
        if let Some(ref opt) = self.opts.get(name) {
            if let Some(ref s) = opt.values.iter().nth(0) {
                return Some(&s[..]);
            }
        }
        if let Some(ref pos) = self.positionals.get(name) {
            if let Some(ref s) = pos.values.iter().nth(0) {
                return Some(&s[..]);
            }
        }
        None
    }

    /// Gets the values of a specific option or positional argument in a vector (i.e. an argument
    /// that takes an additional value at runtime). If the option wasn't present at runtime it
    /// returns `None`
    ///
    /// # Example
    ///
    /// ```no_run
    /// # use clap::{App, Arg};
    /// # let matches = App::new("myapp").arg(Arg::new("output").takes_value(true)).get_matches();
    /// // If the program had option "-c" that took a value and was run
    /// // via "myapp -o some -o other -o file"
    /// // values_of() would return a [&str; 3] ("some", "other", "file")
    /// if let Some(os) = matches.values_of("output") {
    ///        for o in os {
    ///            println!("A value for output: {}", o);
    ///        }
    /// }
    /// ```
    pub fn values_of<'n>(&self, name: &'n str) -> Option<Vec<&str>> {
        if let Some(ref opt) = self.opts.get(name) {
            if opt.values.is_empty() { return None; }

            return Some(opt.values.iter().map(|s| &s[..]).collect::<Vec<_>>());
        }
        if let Some(ref pos) = self.positionals.get(name) {
            if pos.values.is_empty() { return None; }

            return Some(pos.values.iter().map(|s| &s[..]).collect::<Vec<_>>());
        }
        None
    }

    /// Checks if a flag was argument was supplied at runtime. **DOES NOT** work for
    /// option or positional arguments (use `.value_of()` instead)
    ///
    ///
    /// # Example
    ///
    /// ```no_run
    /// # use clap::{App, Arg};
    /// # let matches = App::new("myapp").arg(Arg::new("output").takes_value(true)).get_matches();
    /// if matches.is_present("output") {
    ///        println!("The output argument was used!");
    /// }
    /// ```
    pub fn is_present<'n>(&self, name: &'n str) -> bool {
        if let Some(ref sc) = self.subcommand {
            if sc.name == name { return true; }
        }
        if self.flags.contains_key(name) {return true;}
        if self.opts.contains_key(name) {return true;}
        if self.positionals.contains_key(name) {return true;}
        false
    }

    /// Checks the number of occurrences of an option, flag, or positional argument at runtime.
    /// If an option or flag isn't present it will return `0`, if the option or flag doesn't
    /// allow multiple occurrences, it will return `1` no matter how many times it occurred
    /// (unless it wasn't prsent) at all.
    ///
    ///
    /// # Example
    ///
    /// ```no_run
    /// # use clap::{App, Arg};
    /// # let matches = App::new("myapp").arg(Arg::new("output").takes_value(true)).get_matches();
    /// if matches.occurrences_of("debug") > 1 {
    ///     println!("Debug mode is REALLY on");
    /// } else {
    ///     println!("Debug mode kind of on");
    /// }
    /// ```
    pub fn occurrences_of<'n>(&self, name: &'n str) -> u8 {
        if let Some(ref f) = self.flags.get(name) {
            return f.occurrences;
        }
        if let Some(ref o) = self.opts.get(name) {
            return o.occurrences;
        }
        if let Some(ref p) = self.positionals.get(name) {
            return p.occurrences;
        }
        0
    }

    /// If a subcommand was found, returns the ArgMatches struct associated with it's matches
    ///
    ///
    /// # Example
    ///
    /// ```no_run
    /// # use clap::{App, Arg, SubCommand};
    /// # let app_matches = App::new("myapp").subcommand(SubCommand::new("test")).get_matches();
    /// if let Some(matches) = app_matches.subcommand_matches("test") {
    ///     // Use matches as normal
    /// }
    /// ```
    pub fn subcommand_matches<'n>(&self, name: &'n str) -> Option<&ArgMatches> {
        if let Some( ref sc) = self.subcommand {
            if sc.name != name { return None; }
            return Some(&sc.matches);
        }
        None
    }

    /// If a subcommand was found, returns the name associated with it
    ///
    ///
    /// # Example
    ///
    /// ```no_run
    /// # use clap::{App, Arg, SubCommand};
    /// # let app_matches = App::new("myapp").subcommand(SubCommand::new("test")).get_matches();
    /// match app_matches.subcommand_name() {
    ///     Some("test")   => {}, // test was used
    ///     Some("config") => {}, // config was used
    ///     _              => {}, // Either no subcommand or one not tested for...
    /// }
    /// ```
    pub fn subcommand_name(&self) -> Option<&str> {
        if let Some( ref sc ) = self.subcommand {
            return Some(&sc.name[..]);
        }
        None
    }
}<commit_msg>feat(SubCommands): add method to get name and subcommand matches together<commit_after>use std::collections::HashMap;

use args::SubCommand;
use args::flagarg::FlagArg;
use args::optarg::OptArg;
use args::posarg::PosArg;

/// Used to get information about the arguments that
/// where supplied to the program at runtime.
///
///
/// Fields of `ArgMatches` aren't designed to be used directly, only
/// the methods in order to query information.
///
/// # Example
///
/// ```no_run
/// # use clap::{App, Arg};
/// let matches = App::new("MyApp")
/// // adding of arguments and configuration goes here...
/// #                    .arg(Arg::new("config")
/// #                               .long("config")
/// #                               .required(true)
/// #                               .takes_value(true))
/// #                    .arg(Arg::new("debug")
/// #                                   .short("d")
/// #                                   .multiple(true))
///                     .get_matches();
/// // if you had an argument named "output" that takes a value
/// if let Some(o) = matches.value_of("output") {
///     println!("Value for output: {}", o);
/// }
///
/// // Although not advised, if you have a required argument
/// // you can call .unwrap() because the program will exit long before
/// // here at noticing the user didn't supply a required argument...
/// // use at your own risk ;)
/// println!("Config file: {}", matches.value_of("config").unwrap());
///
/// // You can check the present of an argument
/// if matches.is_present("debug") {
///     // Checking if "debug" was present was necessary,
///     // as occurrences returns 0 if a flag isn't found
///     // but we can check how many times "debug" was found
///     // if we allow multiple (if multiple isn't allowed it always be 1 or 0)
///     if matches.occurrences_of("debug") > 1 {
///         println!("Debug mode is REALLY on");
///     } else {
///         println!("Debug mode kind of on");
///     }
/// }
///
/// // You can get the sub-matches of a particular subcommand (in this case "test")
/// // If "test" had it's own "-l" flag you could check for it's presence accordingly
/// if let Some(ref matches) = matches.subcommand_matches("test") {
///     if matches.is_present("list") {
///         println!("Printing testing lists...");
///     } else {
///         println!("Not printing testing lists...");
///     }
/// }
pub struct ArgMatches<'a> {
    // pub matches_of: &'static str,
    pub flags: HashMap<&'a str, FlagArg>,
    pub opts: HashMap<&'a str, OptArg>,
    pub positionals: HashMap<&'a str, PosArg>,
    pub subcommand: Option<Box<SubCommand<'a>>>
}

impl<'a> ArgMatches<'a> {
    /// Creates a new instance of `ArgMatches`. This ins't called directly, but
    /// through the `.get_matches()` method of `App`
    ///
    /// # Example
    ///
    /// ```no_run
    /// # use clap::{App, Arg};
    /// let matches = App::new("myprog").get_matches();
    /// ```
    pub fn new() -> ArgMatches<'a> {
        ArgMatches {
            // matches_of: name,
            flags: HashMap::new(),
            opts: HashMap::new(),
            positionals: HashMap::new(),
            subcommand: None
        }
    }

    /// Gets the value of a specific option or positional argument (i.e. an argument that takes
    /// an additional value at runtime). If the option wasn't present at runtime
    /// it returns `None`.
    ///
    /// *NOTE:* If getting a value for an option or positional argument that allows multiples,
    /// prefer `values_of()` as `value_of()` will only return the _*first*_ value.
    ///
    /// # Example
    ///
    /// ```no_run
    /// # use clap::{App, Arg};
    /// # let matches = App::new("myapp").arg(Arg::new("output").takes_value(true)).get_matches();
    /// if let Some(o) = matches.value_of("output") {
    ///        println!("Value for output: {}", o);
    /// }
    /// ```
    pub fn value_of<'n>(&self, name: &'n str) -> Option<&str> {
        if let Some(ref opt) = self.opts.get(name) {
            if let Some(ref s) = opt.values.iter().nth(0) {
                return Some(&s[..]);
            }
        }
        if let Some(ref pos) = self.positionals.get(name) {
            if let Some(ref s) = pos.values.iter().nth(0) {
                return Some(&s[..]);
            }
        }
        None
    }

    /// Gets the values of a specific option or positional argument in a vector (i.e. an argument
    /// that takes an additional value at runtime). If the option wasn't present at runtime it
    /// returns `None`
    ///
    /// # Example
    ///
    /// ```no_run
    /// # use clap::{App, Arg};
    /// # let matches = App::new("myapp").arg(Arg::new("output").takes_value(true)).get_matches();
    /// // If the program had option "-c" that took a value and was run
    /// // via "myapp -o some -o other -o file"
    /// // values_of() would return a [&str; 3] ("some", "other", "file")
    /// if let Some(os) = matches.values_of("output") {
    ///        for o in os {
    ///            println!("A value for output: {}", o);
    ///        }
    /// }
    /// ```
    pub fn values_of<'n>(&self, name: &'n str) -> Option<Vec<&str>> {
        if let Some(ref opt) = self.opts.get(name) {
            if opt.values.is_empty() { return None; }

            return Some(opt.values.iter().map(|s| &s[..]).collect::<Vec<_>>());
        }
        if let Some(ref pos) = self.positionals.get(name) {
            if pos.values.is_empty() { return None; }

            return Some(pos.values.iter().map(|s| &s[..]).collect::<Vec<_>>());
        }
        None
    }

    /// Checks if a flag was argument was supplied at runtime. **DOES NOT** work for
    /// option or positional arguments (use `.value_of()` instead)
    ///
    ///
    /// # Example
    ///
    /// ```no_run
    /// # use clap::{App, Arg};
    /// # let matches = App::new("myapp").arg(Arg::new("output").takes_value(true)).get_matches();
    /// if matches.is_present("output") {
    ///        println!("The output argument was used!");
    /// }
    /// ```
    pub fn is_present<'n>(&self, name: &'n str) -> bool {
        if let Some(ref sc) = self.subcommand {
            if sc.name == name { return true; }
        }
        if self.flags.contains_key(name) {return true;}
        if self.opts.contains_key(name) {return true;}
        if self.positionals.contains_key(name) {return true;}
        false
    }

    /// Checks the number of occurrences of an option, flag, or positional argument at runtime.
    /// If an option or flag isn't present it will return `0`, if the option or flag doesn't
    /// allow multiple occurrences, it will return `1` no matter how many times it occurred
    /// (unless it wasn't prsent) at all.
    ///
    ///
    /// # Example
    ///
    /// ```no_run
    /// # use clap::{App, Arg};
    /// # let matches = App::new("myapp").arg(Arg::new("output").takes_value(true)).get_matches();
    /// if matches.occurrences_of("debug") > 1 {
    ///     println!("Debug mode is REALLY on");
    /// } else {
    ///     println!("Debug mode kind of on");
    /// }
    /// ```
    pub fn occurrences_of<'n>(&self, name: &'n str) -> u8 {
        if let Some(ref f) = self.flags.get(name) {
            return f.occurrences;
        }
        if let Some(ref o) = self.opts.get(name) {
            return o.occurrences;
        }
        if let Some(ref p) = self.positionals.get(name) {
            return p.occurrences;
        }
        0
    }

    /// If a subcommand was found, returns the ArgMatches struct associated with it's matches
    ///
    ///
    /// # Example
    ///
    /// ```no_run
    /// # use clap::{App, Arg, SubCommand};
    /// # let app_matches = App::new("myapp").subcommand(SubCommand::new("test")).get_matches();
    /// if let Some(matches) = app_matches.subcommand_matches("test") {
    ///     // Use matches as normal
    /// }
    /// ```
    pub fn subcommand_matches<'n>(&self, name: &'n str) -> Option<&ArgMatches> {
        if let Some( ref sc) = self.subcommand {
            if sc.name != name { return None; }
            return Some(&sc.matches);
        }
        None
    }

    /// If a subcommand was found, returns the name associated with it
    ///
    ///
    /// # Example
    ///
    /// ```no_run
    /// # use clap::{App, Arg, SubCommand};
    /// # let app_matches = App::new("myapp").subcommand(SubCommand::new("test")).get_matches();
    /// match app_matches.subcommand_name() {
    ///     Some("test")   => {}, // test was used
    ///     Some("config") => {}, // config was used
    ///     _              => {}, // Either no subcommand or one not tested for...
    /// }
    /// ```
    pub fn subcommand_name(&self) -> Option<&str> {
        if let Some( ref sc ) = self.subcommand {
            return Some(&sc.name[..]);
        }
        None
    }

    /// If a subcommand was found, returns the name and matches associated with it
    ///
    ///
    /// # Example
    ///
    /// ```no_run
    /// # use clap::{App, Arg, SubCommand};
    /// # let app_matches = App::new("myapp").subcommand(SubCommand::new("test")).get_matches();
    /// match app_matches.subcommand() {
    ///     ("test", Some(matches))   => {}, // test was used
    ///     ("config", Some(matches)) => {}, // config was used
    ///     _                         => {}, // Either no subcommand or one not tested for...
    /// }
    /// ```
    pub fn subcommand(&self) -> (&str, Option<&ArgMatches>) {
        if let Some( ref sc ) = self.subcommand {
            return (&sc.name[..], Some(&sc.matches));
        }
        ("", None)
    }

}<|endoftext|>


<commit_before>use geom::point::Point2D;
use geom::size::Size2D;
use gfx::geometry::{au, px_to_au};
use libc::{c_void};
use font_library::FontLibrary;
use font::Font;
use glyph::Glyph;
use shaper::shape_text;

#[doc="A single, unbroken line of text."]
struct TextRun {
    glyphs: ~[Glyph],
}

impl TextRun {
    fn size() -> Size2D<au> {
        let height = px_to_au(20);
        let pen_start_x = px_to_au(0);
        let pen_start_y = height;
        let pen_start = Point2D(pen_start_x, pen_start_y);
        let pen_end = self.glyphs.foldl(pen_start, |cur, glyph| {
            Point2D(cur.x.add(glyph.pos.offset.x).add(glyph.pos.advance.x),
                    cur.y.add(glyph.pos.offset.y).add(glyph.pos.advance.y))
        });
        return Size2D(pen_end.x, pen_end.y);
    }
}

fn TextRun(font: Font, text: ~str) -> TextRun {
    TextRun {
        glyphs : shape_text(&font, text)
    }
}

fn should_calculate_the_total_size() {
    #[test];
    #[ignore(cfg(target_os = "macos"))];

    let flib = FontLibrary();
    let font = flib.get_test_font();
    let run = TextRun(*font, ~"firecracker");
    let expected = Size2D(px_to_au(84), px_to_au(20));
    assert run.size() == expected;
}
<commit_msg>Precalculate the size of TextRuns<commit_after>use geom::point::Point2D;
use geom::size::Size2D;
use gfx::geometry::{au, px_to_au};
use libc::{c_void};
use font_library::FontLibrary;
use font::Font;
use glyph::Glyph;
use shaper::shape_text;

#[doc="A single, unbroken line of text."]
struct TextRun {
    priv glyphs: ~[Glyph],
    priv size_: Size2D<au>,
}

impl TextRun {
    fn size() -> Size2D<au> { self.size_ }
}

fn TextRun(font: Font, text: ~str) -> TextRun {
    let glyphs = shape_text(&font, text);
    let size = glyph_run_size(glyphs);

    TextRun {
        size_: size,
        glyphs: shape_text(&font, text)
    }
}

fn glyph_run_size(glyphs: &[Glyph]) -> Size2D<au> {
    let height = px_to_au(20);
    let pen_start_x = px_to_au(0);
    let pen_start_y = height;
    let pen_start = Point2D(pen_start_x, pen_start_y);
    let pen_end = glyphs.foldl(pen_start, |cur, glyph| {
        Point2D(cur.x.add(glyph.pos.offset.x).add(glyph.pos.advance.x),
                cur.y.add(glyph.pos.offset.y).add(glyph.pos.advance.y))
    });
    return Size2D(pen_end.x, pen_end.y);
}

fn should_calculate_the_total_size() {
    #[test];
    #[ignore(cfg(target_os = "macos"))];

    let flib = FontLibrary();
    let font = flib.get_test_font();
    let run = TextRun(*font, ~"firecracker");
    let expected = Size2D(px_to_au(84), px_to_au(20));
    assert run.size() == expected;
}
<|endoftext|>


<commit_before>use core::fmt;

use shared::descriptor;
use shared::PrivilegeLevel;

/// Specifies which element to load into a segment from
/// descriptor tables (i.e., is a index to LDT or GDT table
/// with some additional flags).
///
/// See Intel 3a, Section 3.4.2 "Segment Selectors"
bitflags! {
    #[repr(C, packed)]
    pub flags SegmentSelector: u16 {
        /// Requestor Privilege Level
        const RPL_0 = 0b00,
        const RPL_1 = 0b01,
        const RPL_2 = 0b10,
        const RPL_3 = 0b11,

        /// Table Indicator (TI) 0 means GDT is used.
        const TI_GDT = 0 << 2,
        /// Table Indicator (TI) 1 means LDT is used.
        const TI_LDT = 1 << 2,
    }
}

/// Reload code segment register.
/// Note this is special since we can not directly move
/// to %cs. Instead we push the new segment selector
/// and return value on the stack and use lretq
/// to reload cs and continue at 1:.
pub unsafe fn set_cs(sel: SegmentSelector) {

    #[cfg(target_arch="x86")]
    #[inline(always)]
    unsafe fn inner(sel: SegmentSelector) {
        asm!("pushl $0; \
              pushl $$1f; \
              lretl; \
              1:" :: "ri" (sel.bits() as usize) : "rax" "memory");
    }

    #[cfg(target_arch="x86_64")]
    #[inline(always)]
    unsafe fn inner(sel: SegmentSelector) {
        asm!("pushq $0; \
              leaq  1f(%rip), %rax; \
              pushq %rax; \
              lretq; \
              1:" :: "ri" (sel.bits() as usize) : "rax" "memory");
    }

    inner(sel)
}

impl SegmentSelector {
    /// Create a new SegmentSelector
    ///
    /// # Arguments
    ///  * `index` index in GDT or LDT array.
    ///
    pub const fn new(index: u16, rpl: PrivilegeLevel) -> SegmentSelector {
        SegmentSelector { bits: index << 3 | (rpl as u16) }
    }

    pub const fn from_raw(bits: u16) -> SegmentSelector {
        SegmentSelector { bits: bits }
    }
}

impl fmt::Display for SegmentSelector {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let r0 = match self.contains(RPL_0) {
            false => "",
            true => "Ring 0 segment selector.",
        };
        let r1 = match self.contains(RPL_1) {
            false => "",
            true => "Ring 1 segment selector.",
        };
        let r2 = match self.contains(RPL_2) {
            false => "",
            true => "Ring 2 segment selector.",
        };
        let r3 = match self.contains(RPL_3) {
            false => "",
            true => "Ring 3 segment selector.",
        };
        let tbl = match self.contains(TI_LDT) {
            false => "GDT Table",
            true => "LDT Table",
        };

        write!(f,
               "Index {} in {}, {}{}{}{}",
               self.bits >> 3,
               tbl,
               r0,
               r1,
               r2,
               r3)
        // write!(f, "Index")
    }
}

/// Reload stack segment register.
pub unsafe fn load_ss(sel: SegmentSelector) {
    asm!("movw $0, %ss " :: "r" (sel.bits()) : "memory");
}

/// Reload data segment register.
pub unsafe fn load_ds(sel: SegmentSelector) {
    asm!("movw $0, %ds " :: "r" (sel.bits()) : "memory");
}

/// Reload es segment register.
pub unsafe fn load_es(sel: SegmentSelector) {
    asm!("movw $0, %es " :: "r" (sel.bits()) : "memory");
}

/// Reload fs segment register.
pub unsafe fn load_fs(sel: SegmentSelector) {
    asm!("movw $0, %fs " :: "r" (sel.bits()) : "memory");
}

/// Reload gs segment register.
pub unsafe fn load_gs(sel: SegmentSelector) {
    asm!("movw $0, %gs " :: "r" (sel.bits()) : "memory");
}

/// Returns the current value of the code segment register.
pub fn cs() -> SegmentSelector {
    let segment: u16;
    unsafe { asm!("mov %cs, $0" : "=r" (segment) ) };
    SegmentSelector::from_raw(segment)
}

bitflags! {
    /// Data segment types. All are readable.
    ///
    /// See Table 3-1, "Code- and Data-Segment Types"
    pub flags DataAccess: u8 {
        /// Segment is writable
        const DATA_WRITE = 1 << 1,
        /// Segment grows down, for stack
        const DATA_EXPAND_DOWN = 1 << 2,
    }
}

bitflags! {
    /// Code segment types. All are executable.
    ///
    /// See Table 3-1, "Code- and Data-Segment Types"
    pub flags CodeAccess: u8 {
        /// Segment is readable
        const CODE_READ = 1 << 1,
        /// Segment is callable from segment with fewer privileges.
        const CODE_CONFORMING = 1 << 2,
    }
}

/// Umbrella Segment Type.
///
/// See Table 3-1, "Code- and Data-Segment Types"
#[repr(u8)]
pub enum Type {
    Data(DataAccess),
    Code(CodeAccess),
}

impl Type {
    pub fn pack(self) -> u8 {
        match self {
            Type::Data(d) => d.bits | 0b0_000,
            Type::Code(c) => c.bits | 0b1_000,
        }
    }
}

/// Entry for GDT or LDT. Provides size and location of a segment.
///
/// See Intel 3a, Section 3.4.5 "Segment Descriptors", and Section 3.5.2
/// "Segment Descriptor Tables in IA-32e Mode", especially Figure 3-8.
#[derive(Copy, Clone, Debug)]
#[repr(C, packed)]
pub struct SegmentDescriptor {
    limit1: u16,
    base1: u16,
    base2: u8,
    access: descriptor::Flags,
    limit2_flags: Flags,
    base3: u8,
}

/// This is data-structure is a ugly mess thing so we provide some
/// convenience function to program it.
impl SegmentDescriptor {
    pub const NULL: SegmentDescriptor = SegmentDescriptor {
        base1: 0,
        base2: 0,
        base3: 0,
        access: descriptor::Flags::BLANK,
        limit1: 0,
        limit2_flags: Flags::BLANK,
    };

    pub fn new(base: u32, limit: u32,
               ty: Type, accessed: bool, dpl: PrivilegeLevel) -> SegmentDescriptor
    {
        let fine_grained = limit < 0x100000;
        let (limit1, limit2) = if fine_grained {
            ((limit & 0xFFFF) as u16, ((limit & 0xF0000) >> 16) as u8)
        } else {
            if ((limit - 0xFFF) & 0xFFF) > 0 {
                panic!("bad segment limit for GDT entry");
            }
            (((limit & 0xFFFF000) >> 12) as u16, ((limit & 0xF0000000) >> 28) as u8)
        };
        let ty1 = descriptor::Type::SegmentDescriptor {
            ty: ty,
            accessed: accessed
        };
        SegmentDescriptor {
            base1: base as u16,
            base2: ((base as usize & 0xFF0000) >> 16) as u8,
            base3: ((base as usize & 0xFF000000) >> 24) as u8,
            access: descriptor::Flags::from_type(ty1)
                |   descriptor::Flags::from_priv(dpl),
            limit1: limit1,
            limit2_flags: FLAGS_DB
                | if fine_grained { FLAGS_G } else { Flags::empty() }
                | Flags::from_limit2(limit2),
        }
    }
}

bitflags! {
    pub flags Flags: u8 {
        /// Available for use by system software.
        const FLAGS_AVL  = 1 << 4,
        /// 64-bit code segment (IA-32e mode only).
        const FLAGS_L    = 1 << 5,
        /// Default operation size (0 = 16-bit segment, 1 = 32-bit segment).
        const FLAGS_DB   = 1 << 6,
        /// Granularity (0 = limit in bytes, 1 = limt in 4 KiB Pages).
        const FLAGS_G    = 1 << 7,

    }
}

impl Flags {
    pub const BLANK: Flags = Flags { bits: 0 };

    pub fn from_limit2(limit2: u8) -> Flags {
        assert_eq!(limit2 & !0b111, 0);
        Flags { bits: limit2 }
    }
}
<commit_msg>Fix typo.<commit_after>use core::fmt;

use shared::descriptor;
use shared::PrivilegeLevel;

/// Specifies which element to load into a segment from
/// descriptor tables (i.e., is a index to LDT or GDT table
/// with some additional flags).
///
/// See Intel 3a, Section 3.4.2 "Segment Selectors"
bitflags! {
    #[repr(C, packed)]
    pub flags SegmentSelector: u16 {
        /// Requestor Privilege Level
        const RPL_0 = 0b00,
        const RPL_1 = 0b01,
        const RPL_2 = 0b10,
        const RPL_3 = 0b11,

        /// Table Indicator (TI) 0 means GDT is used.
        const TI_GDT = 0 << 2,
        /// Table Indicator (TI) 1 means LDT is used.
        const TI_LDT = 1 << 2,
    }
}

/// Reload code segment register.
/// Note this is special since we can not directly move
/// to %cs. Instead we push the new segment selector
/// and return value on the stack and use lretq
/// to reload cs and continue at 1:.
pub unsafe fn set_cs(sel: SegmentSelector) {

    #[cfg(target_arch="x86")]
    #[inline(always)]
    unsafe fn inner(sel: SegmentSelector) {
        asm!("pushl $0; \
              pushl $$1f; \
              lretl; \
              1:" :: "ri" (sel.bits() as usize) : "rax" "memory");
    }

    #[cfg(target_arch="x86_64")]
    #[inline(always)]
    unsafe fn inner(sel: SegmentSelector) {
        asm!("pushq $0; \
              leaq  1f(%rip), %rax; \
              pushq %rax; \
              lretq; \
              1:" :: "ri" (sel.bits() as usize) : "rax" "memory");
    }

    inner(sel)
}

impl SegmentSelector {
    /// Create a new SegmentSelector
    ///
    /// # Arguments
    ///  * `index` index in GDT or LDT array.
    ///
    pub const fn new(index: u16, rpl: PrivilegeLevel) -> SegmentSelector {
        SegmentSelector { bits: index << 3 | (rpl as u16) }
    }

    pub const fn from_raw(bits: u16) -> SegmentSelector {
        SegmentSelector { bits: bits }
    }
}

impl fmt::Display for SegmentSelector {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let r0 = match self.contains(RPL_0) {
            false => "",
            true => "Ring 0 segment selector.",
        };
        let r1 = match self.contains(RPL_1) {
            false => "",
            true => "Ring 1 segment selector.",
        };
        let r2 = match self.contains(RPL_2) {
            false => "",
            true => "Ring 2 segment selector.",
        };
        let r3 = match self.contains(RPL_3) {
            false => "",
            true => "Ring 3 segment selector.",
        };
        let tbl = match self.contains(TI_LDT) {
            false => "GDT Table",
            true => "LDT Table",
        };

        write!(f,
               "Index {} in {}, {}{}{}{}",
               self.bits >> 3,
               tbl,
               r0,
               r1,
               r2,
               r3)
        // write!(f, "Index")
    }
}

/// Reload stack segment register.
pub unsafe fn load_ss(sel: SegmentSelector) {
    asm!("movw $0, %ss " :: "r" (sel.bits()) : "memory");
}

/// Reload data segment register.
pub unsafe fn load_ds(sel: SegmentSelector) {
    asm!("movw $0, %ds " :: "r" (sel.bits()) : "memory");
}

/// Reload es segment register.
pub unsafe fn load_es(sel: SegmentSelector) {
    asm!("movw $0, %es " :: "r" (sel.bits()) : "memory");
}

/// Reload fs segment register.
pub unsafe fn load_fs(sel: SegmentSelector) {
    asm!("movw $0, %fs " :: "r" (sel.bits()) : "memory");
}

/// Reload gs segment register.
pub unsafe fn load_gs(sel: SegmentSelector) {
    asm!("movw $0, %gs " :: "r" (sel.bits()) : "memory");
}

/// Returns the current value of the code segment register.
pub fn cs() -> SegmentSelector {
    let segment: u16;
    unsafe { asm!("mov %cs, $0" : "=r" (segment) ) };
    SegmentSelector::from_raw(segment)
}

bitflags! {
    /// Data segment types. All are readable.
    ///
    /// See Table 3-1, "Code- and Data-Segment Types"
    pub flags DataAccess: u8 {
        /// Segment is writable
        const DATA_WRITE = 1 << 1,
        /// Segment grows down, for stack
        const DATA_EXPAND_DOWN = 1 << 2,
    }
}

bitflags! {
    /// Code segment types. All are executable.
    ///
    /// See Table 3-1, "Code- and Data-Segment Types"
    pub flags CodeAccess: u8 {
        /// Segment is readable
        const CODE_READ = 1 << 1,
        /// Segment is callable from segment with fewer privileges.
        const CODE_CONFORMING = 1 << 2,
    }
}

/// Umbrella Segment Type.
///
/// See Table 3-1, "Code- and Data-Segment Types"
#[repr(u8)]
pub enum Type {
    Data(DataAccess),
    Code(CodeAccess),
}

impl Type {
    pub fn pack(self) -> u8 {
        match self {
            Type::Data(d) => d.bits | 0b0_000,
            Type::Code(c) => c.bits | 0b1_000,
        }
    }
}

/// Entry for GDT or LDT. Provides size and location of a segment.
///
/// See Intel 3a, Section 3.4.5 "Segment Descriptors", and Section 3.5.2
/// "Segment Descriptor Tables in IA-32e Mode", especially Figure 3-8.
#[derive(Copy, Clone, Debug)]
#[repr(C, packed)]
pub struct SegmentDescriptor {
    limit1: u16,
    base1: u16,
    base2: u8,
    access: descriptor::Flags,
    limit2_flags: Flags,
    base3: u8,
}

/// This is data-structure is a ugly mess thing so we provide some
/// convenience function to program it.
impl SegmentDescriptor {
    pub const NULL: SegmentDescriptor = SegmentDescriptor {
        base1: 0,
        base2: 0,
        base3: 0,
        access: descriptor::Flags::BLANK,
        limit1: 0,
        limit2_flags: Flags::BLANK,
    };

    pub fn new(base: u32, limit: u32,
               ty: Type, accessed: bool, dpl: PrivilegeLevel) -> SegmentDescriptor
    {
        let fine_grained = limit < 0x100000;
        let (limit1, limit2) = if fine_grained {
            ((limit & 0xFFFF) as u16, ((limit & 0xF0000) >> 16) as u8)
        } else {
            if ((limit - 0xFFF) & 0xFFF) > 0 {
                panic!("bad segment limit for GDT entry");
            }
            (((limit & 0xFFFF000) >> 12) as u16, ((limit & 0xF0000000) >> 28) as u8)
        };
        let ty1 = descriptor::Type::SegmentDescriptor {
            ty: ty,
            accessed: accessed
        };
        SegmentDescriptor {
            base1: base as u16,
            base2: ((base as usize & 0xFF0000) >> 16) as u8,
            base3: ((base as usize & 0xFF000000) >> 24) as u8,
            access: descriptor::Flags::from_type(ty1)
                |   descriptor::Flags::from_priv(dpl),
            limit1: limit1,
            limit2_flags: FLAGS_DB
                | if fine_grained { FLAGS_G } else { Flags::empty() }
                | Flags::from_limit2(limit2),
        }
    }
}

bitflags! {
    pub flags Flags: u8 {
        /// Available for use by system software.
        const FLAGS_AVL  = 1 << 4,
        /// 64-bit code segment (IA-32e mode only).
        const FLAGS_L    = 1 << 5,
        /// Default operation size (0 = 16-bit segment, 1 = 32-bit segment).
        const FLAGS_DB   = 1 << 6,
        /// Granularity (0 = limit in bytes, 1 = limit in 4 KiB Pages).
        const FLAGS_G    = 1 << 7,

    }
}

impl Flags {
    pub const BLANK: Flags = Flags { bits: 0 };

    pub fn from_limit2(limit2: u8) -> Flags {
        assert_eq!(limit2 & !0b111, 0);
        Flags { bits: limit2 }
    }
}
<|endoftext|>


<commit_before>use std::sync::Arc;
use itertools::Itertools;

use fall_tree::{AstNode, AstClass, Text};
use fall_tree::search::{child_of_type, child_of_type_exn};
use fall_tree::visitor::{Visitor, NodeVisitor};

use super::{Analysis, DiagnosticSink};
use ::{Expr, CallExpr, SynRule, IDENT, SIMPLE_STRING, RefKind};

#[derive(Debug, Eq, PartialEq, Clone)]
pub enum CallKind<'f> {
    Eof,
    Any,
    Commit,

    Not(Expr<'f>),
    Layer(Expr<'f>, Expr<'f>),
    WithSkip(Expr<'f>, Expr<'f>),

    Enter(u32, Expr<'f>),
    Exit(u32, Expr<'f>),
    IsIn(u32),

    RuleCall(SynRule<'f>, Arc<Vec<(u32, Expr<'f>)>>),
    // TODO: u32 is unclear
    PrevIs(Arc<Vec<usize>>)
}

pub (super) fn resolve<'f>(a: &Analysis<'f>, d: &mut DiagnosticSink, call: CallExpr<'f>) -> Option<CallKind<'f>> {
    let n_args = call.args().count();
    let expect_args = |d: &mut DiagnosticSink, n_expected: usize| {
        if n_expected != n_args {
            d.error(
                call.node(),
                format!("Wrong number of arguments, expected {}, got {}", n_expected, n_args)
            )
        }
    };

    let zero_arg = vec![
        ("any", CallKind::Any),
        ("commit", CallKind::Commit),
        ("eof", CallKind::Eof)
    ];

    for (name, kind) in zero_arg.into_iter() {
        if call.fn_name() == name {
            expect_args(d, 0);
            return Some(kind);
        }
    }

    if call.fn_name() == "not" {
        expect_args(d, 1);
        return call.args().next().map(CallKind::Not);
    }

    let two_arg = vec![
        ("layer", CallKind::Layer as fn(_, _) -> _),
        ("with_skip", CallKind::WithSkip)
    ];

    for (name, kind) in two_arg.into_iter() {
        if call.fn_name() == name {
            expect_args(d, 2);
            return call.args().next_tuple()
                .map(|(a, b)| kind(a, b));
        }
    }

    if call.fn_name() == "is_in" {
        expect_args(d, 1);
        return call.args().next()
            .and_then(|ctx| resolve_context(a, d, ctx))
            .map(CallKind::IsIn);
    }

    let layer_expr = vec![
        ("enter", CallKind::Enter as fn(_, _) -> _),
        ("exit", CallKind::Exit),
    ];

    for (name, kind) in layer_expr.into_iter() {
        if call.fn_name() == name {
            expect_args(d, 2);
            return call.args().next_tuple()
                .and_then(|(ctx, body)| {
                    resolve_context(a, d, ctx).map(|ctx| kind(ctx, body))
                });
        }
    }

    if call.fn_name() == "prev_is" {
        let mut args = Vec::new();
        for arg in call.args() {
            let mut ok = false;
            if let Expr::RefExpr(expr) = arg {
                if let Some(RefKind::RuleReference(rule)) = expr.resolve() {
                    if let Some(ty) = rule.resolve_ty() {
                        args.push(ty);
                        ok = true;
                    }
                }
            }
            if !ok {
                d.error(call.node(), "<prev_is> arguments must be public rules")
            }
        }
        return Some(CallKind::PrevIs(Arc::new(args)));
    }

    if let Some(rule) = a.file.resolve_rule(call.fn_name()) {
        if let Some(parameters) = rule.parameters() {
            let params = parameters.parameters()
                .map(|p| p.idx())
                .zip(call.args())
                .collect();
            return Some(CallKind::RuleCall(rule, Arc::new(params)));
        }
    }

    d.error(
        child_of_type_exn(call.node(), IDENT),
        "Unresolved reference"
    );
    return None;
}

pub fn contexts<'f>(a: &Analysis<'f>) -> Vec<Text<'f>> {
    Visitor(Vec::new())
        .visit::<CallExpr, _>(|contexts, call| {
            if call.fn_name() == "is_in" || call.fn_name() == "enter" || call.fn_name() == "exit" {
                if let Some(ctx) = call.args().next().and_then(context_name) {
                    contexts.push(ctx);
                }
            }
        })
        .walk_recursively_children_first(a.file().node())
}

fn context_name<'f>(ctx: Expr<'f>) -> Option<Text<'f>> {
    child_of_type(ctx.node(), SIMPLE_STRING)
        .map(|n| ::ast_ext::lit_body(n.text()))
}

fn resolve_context(a: &Analysis, d: &mut DiagnosticSink, ctx: Expr) -> Option<u32> {
    if let Some(name) = context_name(ctx) {
        a.contexts().iter()
            .position(|&c| c == name)
            .map(|usize_| usize_ as u32)
    } else {
        d.error(ctx.node(), "Context should be a single quoted string");
        None
    }
}

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

    use fall_tree::search;
    use fall_tree::search::ast;

    use ::test_util::parse_with_caret;

    #[test]
    fn test_resolve_no_args() {
        check_resolved("rule foo { <^eof> }", "Eof");
        check_resolved("rule foo { <^any> }", "Any");
        check_resolved("rule foo { <^commit> }", "Commit");
    }

    #[test]
    fn test_resolve_simple_args() {
        check_resolved("rule foo { <^not a> }", "Not(RefExpr@[16; 17))");
        check_resolved("rule foo { <^with_skip a b> }", "WithSkip(RefExpr@[22; 23), RefExpr@[24; 25))");
        check_resolved("rule foo { <^layer a b> }", "Layer(RefExpr@[18; 19), RefExpr@[20; 21))");
    }

    #[test]
    fn test_resolve_layer() {
        check_resolved("rule foo { <^enter 'ctx' a> }", "Enter(0, RefExpr@[24; 25))");
        check_resolved("rule foo { <^exit  'ctx' a> }", "Exit(0, RefExpr@[24; 25))");

        check_resolved("rule foo { <is_in 'ctx1'> <^enter 'ctx2' a> }", "Enter(1, RefExpr@[40; 41))");
        check_resolved("rule foo { <is_in 'ctx1'> <^exit  'ctx2' a> }", "Exit(1, RefExpr@[40; 41))");

        check_resolved(
            "rule foo { <enter 'ctx1' a> <enter 'ctx2' b> <^is_in 'ctx2'> }",
            "IsIn(1)"
        );

        check(
            r" rule foo { <^is_in foo>}",
            None,
            r#"[(foo, "Context should be a single quoted string")]"#,
        )
    }

    #[test]
    fn test_not() {
        resolve_call("rule foo { <^not bar>}", |c, _| {
            let c = c.unwrap();
            assert_eq!(format!("{:?}", c), "Not(RefExpr@[16; 19))");
        })
    }

    #[test]
    fn test_unresolved_call() {
        check(
            r"rule foo { <^abracadabra>}",
            None,
            r#"[(abracadabra, "Unresolved reference")]"#
        );
    }

    #[test]
    fn wrong_arity() {
        check(
            "rule foo { <^eof foo> }",
            Some(CallKind::Eof),
            r#"[(<eof foo>, "Wrong number of arguments, expected 0, got 1")]"#
        );

        check(
            "rule foo { <^any foo bar> }",
            Some(CallKind::Any),
            r#"[(<any foo bar>, "Wrong number of arguments, expected 0, got 2")]"#
        );

        check(
            "rule foo { <^commit foo bar baz> }",
            Some(CallKind::Commit),
            r#"[(<commit foo bar baz>, "Wrong number of arguments, expected 0, got 3")]"#
        );

        check(
            "rule foo { <^not> }",
            None,
            r#"[(<not>, "Wrong number of arguments, expected 1, got 0")]"#
        );
    }

    #[test]
    fn check_prev_is() {
        //TODO: check for errors
        check_resolved(
            "pub rule foo {} pub rule bar {} rule baz { <^prev_is foo bar> }",
            "PrevIs([1, 2])"
        )
    }

    #[test]
    fn call_custom_rule() {
        //TODO: check number of arguments
        //TODO: analysis based resolve of SynRule
        check_resolved(
            "rule foo { <^bar a b>} rule bar(x, y) { }",
            "RuleCall(SynRule@[22; 40), [(0, RefExpr@[16; 17)), (1, RefExpr@[18; 19))])"
        )
    }

    fn check(text: &str, kind: Option<CallKind>, diagnostics: &str) {
        resolve_call(text, |c, a| {
            assert_eq!(c, kind);
            assert_eq!(a.debug_diagnostics(), diagnostics);
        })
    }

    fn check_resolved(text: &str, kind: &str) {
        resolve_call(text, |c, a| {
            let c = c.unwrap();
            assert_eq!(format!("{:?}", c), kind);
            assert_eq!(a.debug_diagnostics(), "[]");
        })
    }

    fn resolve_call<F: FnOnce(Option<CallKind>, Analysis)>(text: &str, f: F) {
        let (file, caret) = parse_with_caret(&text);
        let call = {
            let leaf = search::find_leaf_at_offset(file.root(), caret)
                .left_biased().unwrap();
            ast::ancestor_exn(leaf)
        };
        let a = Analysis::new(::ast(&file));
        let c = a.resolve_call(call);
        f(c, a)
    }
}

<commit_msg>Reduce code duplication<commit_after>use std::sync::Arc;
use itertools::Itertools;

use fall_tree::{AstNode, AstClass, Text};
use fall_tree::search::{child_of_type, child_of_type_exn};
use fall_tree::visitor::{Visitor, NodeVisitor};

use super::{Analysis, DiagnosticSink};
use ::{Expr, CallExpr, SynRule, IDENT, SIMPLE_STRING, RefKind};

#[derive(Debug, Eq, PartialEq, Clone)]
pub enum CallKind<'f> {
    Eof,
    Any,
    Commit,

    Not(Expr<'f>),
    Layer(Expr<'f>, Expr<'f>),
    WithSkip(Expr<'f>, Expr<'f>),

    Enter(u32, Expr<'f>),
    Exit(u32, Expr<'f>),
    IsIn(u32),

    RuleCall(SynRule<'f>, Arc<Vec<(u32, Expr<'f>)>>),
    // TODO: u32 is unclear
    PrevIs(Arc<Vec<usize>>)
}

pub (super) fn resolve<'f>(a: &Analysis<'f>, d: &mut DiagnosticSink, call: CallExpr<'f>) -> Option<CallKind<'f>> {
    let n_args = call.args().count();
    let expect_args = |d: &mut DiagnosticSink, n_expected: usize| {
        if n_expected != n_args {
            d.error(
                call.node(),
                format!("Wrong number of arguments, expected {}, got {}", n_expected, n_args)
            )
        }
    };

    let zero_arg = vec![
        ("any", CallKind::Any),
        ("commit", CallKind::Commit),
        ("eof", CallKind::Eof)
    ];
    for (name, kind) in zero_arg.into_iter() {
        if call.fn_name() == name {
            expect_args(d, 0);
            return Some(kind);
        }
    }

    let one_arg: Vec<(_, fn(&Analysis<'f>, &mut DiagnosticSink, Expr<'f>) -> Option<CallKind<'f>>)> = vec![
        ("not", |_, _, arg| Some(CallKind::Not(arg))),
        ("is_in", |a, d, arg| resolve_context(a, d, arg).map(CallKind::IsIn))
    ];
    for (name, kind) in one_arg.into_iter() {
        if call.fn_name() == name {
            expect_args(d, 1);
            return call.args().next().and_then(|arg| kind(a,d, arg))
        }
    }

    let two_arg: Vec<(_, fn(&Analysis<'f>, &mut DiagnosticSink, Expr<'f>, Expr<'f>) -> Option<CallKind<'f>>)> = vec![
        ("layer", |_, _, arg1, arg2 | {
            Some(CallKind::Layer(arg1, arg2))
        }),
        ("with_skip", |_, _, arg1, arg2 | {
            Some(CallKind::WithSkip(arg1, arg2))
        }),
        ("enter", |a, d, arg1, arg2| {
            resolve_context(a, d, arg1).map(|ctx| CallKind::Enter(ctx, arg2))
        }),
        ("exit", |a, d, arg1, arg2| {
            resolve_context(a, d, arg1).map(|ctx| CallKind::Exit(ctx, arg2))
        }),
    ];
    for (name, kind) in two_arg.into_iter() {
        if call.fn_name() == name {
            expect_args(d, 2);
            return call.args().next_tuple()
                .and_then(|(arg1, arg2)| kind(a, d,arg1, arg2));
        }
    }

    if call.fn_name() == "prev_is" {
        let mut args = Vec::new();
        for arg in call.args() {
            let mut ok = false;
            if let Expr::RefExpr(expr) = arg {
                if let Some(RefKind::RuleReference(rule)) = expr.resolve() {
                    if let Some(ty) = rule.resolve_ty() {
                        args.push(ty);
                        ok = true;
                    }
                }
            }
            if !ok {
                d.error(call.node(), "<prev_is> arguments must be public rules")
            }
        }
        return Some(CallKind::PrevIs(Arc::new(args)));
    }

    if let Some(rule) = a.file.resolve_rule(call.fn_name()) {
        if let Some(parameters) = rule.parameters() {
            let params = parameters.parameters()
                .map(|p| p.idx())
                .zip(call.args())
                .collect();
            return Some(CallKind::RuleCall(rule, Arc::new(params)));
        }
    }

    d.error(
        child_of_type_exn(call.node(), IDENT),
        "Unresolved reference"
    );
    return None;
}

pub fn contexts<'f>(a: &Analysis<'f>) -> Vec<Text<'f>> {
    Visitor(Vec::new())
        .visit::<CallExpr, _>(|contexts, call| {
            if call.fn_name() == "is_in" || call.fn_name() == "enter" || call.fn_name() == "exit" {
                if let Some(ctx) = call.args().next().and_then(context_name) {
                    contexts.push(ctx);
                }
            }
        })
        .walk_recursively_children_first(a.file().node())
}

fn context_name<'f>(ctx: Expr<'f>) -> Option<Text<'f>> {
    child_of_type(ctx.node(), SIMPLE_STRING)
        .map(|n| ::ast_ext::lit_body(n.text()))
}

fn resolve_context(a: &Analysis, d: &mut DiagnosticSink, ctx: Expr) -> Option<u32> {
    if let Some(name) = context_name(ctx) {
        a.contexts().iter()
            .position(|&c| c == name)
            .map(|usize_| usize_ as u32)
    } else {
        d.error(ctx.node(), "Context should be a single quoted string");
        None
    }
}

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

    use fall_tree::search;
    use fall_tree::search::ast;

    use ::test_util::parse_with_caret;

    #[test]
    fn test_resolve_no_args() {
        check_resolved("rule foo { <^eof> }", "Eof");
        check_resolved("rule foo { <^any> }", "Any");
        check_resolved("rule foo { <^commit> }", "Commit");
    }

    #[test]
    fn test_resolve_simple_args() {
        check_resolved("rule foo { <^not a> }", "Not(RefExpr@[16; 17))");
        check_resolved("rule foo { <^with_skip a b> }", "WithSkip(RefExpr@[22; 23), RefExpr@[24; 25))");
        check_resolved("rule foo { <^layer a b> }", "Layer(RefExpr@[18; 19), RefExpr@[20; 21))");
    }

    #[test]
    fn test_resolve_layer() {
        check_resolved("rule foo { <^enter 'ctx' a> }", "Enter(0, RefExpr@[24; 25))");
        check_resolved("rule foo { <^exit  'ctx' a> }", "Exit(0, RefExpr@[24; 25))");

        check_resolved("rule foo { <is_in 'ctx1'> <^enter 'ctx2' a> }", "Enter(1, RefExpr@[40; 41))");
        check_resolved("rule foo { <is_in 'ctx1'> <^exit  'ctx2' a> }", "Exit(1, RefExpr@[40; 41))");

        check_resolved(
            "rule foo { <enter 'ctx1' a> <enter 'ctx2' b> <^is_in 'ctx2'> }",
            "IsIn(1)"
        );

        check(
            r" rule foo { <^is_in foo>}",
            None,
            r#"[(foo, "Context should be a single quoted string")]"#,
        )
    }

    #[test]
    fn test_not() {
        resolve_call("rule foo { <^not bar>}", |c, _| {
            let c = c.unwrap();
            assert_eq!(format!("{:?}", c), "Not(RefExpr@[16; 19))");
        })
    }

    #[test]
    fn test_unresolved_call() {
        check(
            r"rule foo { <^abracadabra>}",
            None,
            r#"[(abracadabra, "Unresolved reference")]"#
        );
    }

    #[test]
    fn wrong_arity() {
        check(
            "rule foo { <^eof foo> }",
            Some(CallKind::Eof),
            r#"[(<eof foo>, "Wrong number of arguments, expected 0, got 1")]"#
        );

        check(
            "rule foo { <^any foo bar> }",
            Some(CallKind::Any),
            r#"[(<any foo bar>, "Wrong number of arguments, expected 0, got 2")]"#
        );

        check(
            "rule foo { <^commit foo bar baz> }",
            Some(CallKind::Commit),
            r#"[(<commit foo bar baz>, "Wrong number of arguments, expected 0, got 3")]"#
        );

        check(
            "rule foo { <^not> }",
            None,
            r#"[(<not>, "Wrong number of arguments, expected 1, got 0")]"#
        );
    }

    #[test]
    fn check_prev_is() {
        //TODO: check for errors
        check_resolved(
            "pub rule foo {} pub rule bar {} rule baz { <^prev_is foo bar> }",
            "PrevIs([1, 2])"
        )
    }

    #[test]
    fn call_custom_rule() {
        //TODO: check number of arguments
        //TODO: analysis based resolve of SynRule
        check_resolved(
            "rule foo { <^bar a b>} rule bar(x, y) { }",
            "RuleCall(SynRule@[22; 40), [(0, RefExpr@[16; 17)), (1, RefExpr@[18; 19))])"
        )
    }

    fn check(text: &str, kind: Option<CallKind>, diagnostics: &str) {
        resolve_call(text, |c, a| {
            assert_eq!(c, kind);
            assert_eq!(a.debug_diagnostics(), diagnostics);
        })
    }

    fn check_resolved(text: &str, kind: &str) {
        resolve_call(text, |c, a| {
            let c = c.unwrap();
            assert_eq!(format!("{:?}", c), kind);
            assert_eq!(a.debug_diagnostics(), "[]");
        })
    }

    fn resolve_call<F: FnOnce(Option<CallKind>, Analysis)>(text: &str, f: F) {
        let (file, caret) = parse_with_caret(&text);
        let call = {
            let leaf = search::find_leaf_at_offset(file.root(), caret)
                .left_biased().unwrap();
            ast::ancestor_exn(leaf)
        };
        let a = Analysis::new(::ast(&file));
        let c = a.resolve_call(call);
        f(c, a)
    }
}

<|endoftext|>


<commit_before>use super::ValidatorRecord;

#[derive(Debug, Clone, PartialEq)]
pub struct ChainConfig {
    // Old, potentially outdated constants
    pub cycle_length: u8,
    pub deposit_size_gwei: u64,
    pub shard_count: u16,
    pub min_committee_size: u64,
    pub max_validator_churn_quotient: u64,
    pub genesis_time: u64,
    pub slot_duration_millis: u64,
    pub initial_validators: Vec<ValidatorRecord>,

    // New constants
    pub epoch_length: u64,
    pub min_attestation_inclusion_delay: u64,
}

/*
 * Presently this is just some arbitrary time in Sept 2018.
 */
const TEST_GENESIS_TIME: u64 = 1_537_488_655;

impl ChainConfig {
    pub fn standard() -> Self {
        Self {
            cycle_length: 64,
            deposit_size_gwei: 32 * (10 ^ 9),
            shard_count: 1024,
            min_committee_size: 128,
            max_validator_churn_quotient: 32,
            genesis_time: TEST_GENESIS_TIME,
            slot_duration_millis: 16 * 1000,
            initial_validators: vec![],

            // New
            epoch_length: 64,
            min_attestation_inclusion_delay: 4,
        }
    }

    pub fn validate(&self) -> bool {
        // criteria that ensure the config is valid

        // shard_count / cycle_length > 0 otherwise validator delegation
        // will fail.
        if self.shard_count / u16::from(self.cycle_length) == 0 {
            return false;
        }

        true
    }

    #[cfg(test)]
    pub fn super_fast_tests() -> Self {
        Self {
            cycle_length: 2,
            deposit_size_gwei: 32 * (10 ^ 9),
            shard_count: 2,
            min_committee_size: 2,
            max_validator_churn_quotient: 32,
            genesis_time: TEST_GENESIS_TIME, // arbitrary
            slot_duration_millis: 16 * 1000,
            initial_validators: vec![],

            // New constants
            epoch_length: 64,
            min_attestation_inclusion_delay: 4,
        }
    }
}
<commit_msg>chain config TODO<commit_after>use super::ValidatorRecord;

#[derive(Debug, Clone, PartialEq)]
pub struct ChainConfig {
    // Old, potentially outdated constants
    pub cycle_length: u8,
    pub deposit_size_gwei: u64,
    pub shard_count: u16,
    pub min_committee_size: u64,
    pub max_validator_churn_quotient: u64,
    pub genesis_time: u64,
    pub slot_duration_millis: u64,
    // TODO: Come back to this
    pub initial_validators: Vec<ValidatorRecord>,

    // New constants
    pub epoch_length: u64,
    pub min_attestation_inclusion_delay: u64,
}

/*
 * Presently this is just some arbitrary time in Sept 2018.
 */
const TEST_GENESIS_TIME: u64 = 1_537_488_655;

impl ChainConfig {
    pub fn standard() -> Self {
        Self {
            cycle_length: 64,
            deposit_size_gwei: 32 * (10 ^ 9),
            shard_count: 1024,
            min_committee_size: 128,
            max_validator_churn_quotient: 32,
            genesis_time: TEST_GENESIS_TIME,
            slot_duration_millis: 16 * 1000,
            initial_validators: vec![],

            // New
            epoch_length: 64,
            min_attestation_inclusion_delay: 4,
        }
    }

    pub fn validate(&self) -> bool {
        // criteria that ensure the config is valid

        // shard_count / cycle_length > 0 otherwise validator delegation
        // will fail.
        if self.shard_count / u16::from(self.cycle_length) == 0 {
            return false;
        }

        true
    }

    #[cfg(test)]
    pub fn super_fast_tests() -> Self {
        Self {
            cycle_length: 2,
            deposit_size_gwei: 32 * (10 ^ 9),
            shard_count: 2,
            min_committee_size: 2,
            max_validator_churn_quotient: 32,
            genesis_time: TEST_GENESIS_TIME, // arbitrary
            slot_duration_millis: 16 * 1000,
            initial_validators: vec![],

            // New constants
            epoch_length: 64,
            min_attestation_inclusion_delay: 4,
        }
    }
}
<|endoftext|>


<commit_before>// src/controllers/accounts_controller.rs

/// Accounts Controller

// Import
// External
use ::nickel::{JsonBody, Request};
use ::bson::{Bson};
use ::bson::oid::ObjectId;
// Utilities
use ::common::api_result::ApiResult;
use ::common::config::Config;
use ::common::data_access::ServerData;
use ::common::session as Session;
// Models
use ::models::account_model::{AccountModel, OutAccountModel};
// DAO
use ::dao::dao_manager::DAOManager;

#[derive(Clone)]
pub struct AccountsController{
    dao_manager: DAOManager,
    config: Config
}

impl AccountsController{

    pub fn new(dao_manager: DAOManager, config: Config) -> AccountsController{
        AccountsController{
            dao_manager: dao_manager,
            config: config
        }
    }

    /// Create Account
    ///
    /// # Arguments
    /// &self
    /// req - nickel::Request
    /// mm_id - String Money Map ID
    ///
    /// # Returns
    /// `ApiResult<OutAccountModel, AccountModel>` - ApiResult including the created account
    pub fn create(&self, req: &mut Request<ServerData>, mm_id: String) -> ApiResult<OutAccountModel, AccountModel>{

        let user_id = match Session::get_session_id(req){
            Ok(id) => id,
            Err(e) => {
                error!("{}",e.get_message().to_string());
                return ApiResult::Failure{msg:"Unable to retrieve session data."};
            }
        };

        // START Retrieve DAO ---------------------------------------------------------------------
        match self.dao_manager.get_money_map_dao(){
            Ok(mm_dao) => {
                match self.dao_manager.get_account_dao(){
                    Ok(account_dao) => {
                        // END Retrieve DAO -------------------------------------------------------

                        match ObjectId::with_string(&mm_id){
                            Ok(mm_obj_id) => {
                                match ObjectId::with_string(&user_id){
                                    Ok(user_obj_id) => {

                                        let filter = doc!{
                                            "_id" => (mm_obj_id.clone()),
                                            "users.user_id" => user_obj_id,
                                            "deleted" => {
                                                "$ne" => true
                                            }
                                        };
                                        match mm_dao.find_one(Some(filter), None){
                                            Some(_) => {

                                                // Parse body to AccountModel
                                                match req.json_as::<AccountModel>(){
                                                    Ok(account) => {

                                                        // Validate
                                                        let validation_result = account.validate_new();
                                                        if validation_result.is_valid(){
                                                            // Save Account
                                                            match account_dao.create(mm_obj_id, &account){
                                                                Ok(new_account) => {

                                                                    ApiResult::Success{result:OutAccountModel::new(new_account)}
                                                                },
                                                                Err(e) => {
                                                                    error!("{}",e);
                                                                    ApiResult::Failure{msg:"Unable to create account"}
                                                                }
                                                            }
                                                        }else{
                                                            ApiResult::Invalid{validation:validation_result, request:account}
                                                        }

                                                    },
                                                    Err(e) => {
                                                        error!("{}",e);
                                                        ApiResult::Failure{msg:"Invalid format. Unable to parse data."}
                                                    }
                                                }
                                            },
                                            None => {
                                                ApiResult::Failure{msg:"Unable to find money map."}
                                            }
                                        }
                                    },
                                    Err(e) => {
                                        error!("{}", e);
                                        ApiResult::Failure{msg:"Failed to find money map. Invalid user ID."}
                                    }
                                }
                            },
                            Err(e) => {
                                error!("{}", e);
                                ApiResult::Failure{msg:"Failed to find money map. Invalid ID."}
                            }
                        }

                        // START Retrieve DAO Error Handling --------------------------------------
                    },
                    Err(e) => {
                        error!("{}",e.get_message().to_string());
                        ApiResult::Failure{msg:"Unable to interact with database"}
                    }
                }
            },
            Err(e) => {
                error!("{}",e.get_message().to_string());
                ApiResult::Failure{msg:"Unable to interact with database"}
            }
        }
        // END Retrieve DAO Error Handling --------------------------------------------------------
    }// end create

    /// Retrieve all money map accounts
    ///
    /// # Arguments
    /// &self
    /// req - nickel::Request
    /// mm_id - String Money Map ID
    ///
    /// # Returns
    /// `ApiResult<Vec<MoneyMapModel>>` - ApiResult including a vector of money maps
    pub fn find(&self, req: &mut Request<ServerData>, mm_id: String) -> ApiResult<Vec<OutAccountModel>, ()>{

        let user_id = match Session::get_session_id(req){
            Ok(id) => id,
            Err(e) => {
                error!("{}",e.get_message().to_string());
                return ApiResult::Failure{msg:"Unable to retrieve session data."};
            }
        };

        // START Retrieve DAO ---------------------------------------------------------------------
        match self.dao_manager.get_account_dao(){
            Ok(account_dao) => {
                // END Retrieve DAO ---------------------------------------------------------------

                match ObjectId::with_string(&mm_id){
                    Ok(mm_obj_id) => {
                        match ObjectId::with_string(&user_id){
                            Ok(user_obj_id) => {

                                // Get list of accounts for money map
                                match account_dao.find(user_obj_id, mm_obj_id){
                                    Some(accounts) => {
                                        ApiResult::Success{
                                            result:accounts.into_iter().map(|x| OutAccountModel::new(x)).collect()
                                        }
                                    },
                                    None => {
                                        ApiResult::Failure{msg:"Unable to find money map."}
                                    }
                                }
                            },
                            Err(e) => {
                                error!("{}", e);
                                ApiResult::Failure{msg:"Failed to find money map. Invalid user ID."}
                            }
                        }
                    },
                    Err(e) => {
                        error!("{}", e);
                        ApiResult::Failure{msg:"Failed to find money map. Invalid ID."}
                    }
                }
                // START Retrieve DAO Error Handling ----------------------------------------------
            },
            Err(e) => {
                error!("{}",e.get_message().to_string());
                ApiResult::Failure{msg:"Unable to interact with database"}
            }
        }
        // END Retrieve DAO Error Handling --------------------------------------------------------
    }// end find_all

    /// Modify Account
    ///
    /// # Arguments
    /// &self
    /// req - nickel::Request
    /// mm_id - String Money Map ID
    ///
    /// # Returns
    /// `ApiResult<AccountModel, AccountModel>` - ApiResult including the modified Account
    pub fn modify(&self, req: &mut Request<ServerData>, mm_id: String) -> ApiResult<OutAccountModel, AccountModel>{

        let user_id = match Session::get_session_id(req){
            Ok(id) => id,
            Err(e) => {
                error!("{}",e.get_message().to_string());
                return ApiResult::Failure{msg:"Unable to retrieve session data."};
            }
        };

        // START Retrieve DAO ---------------------------------------------------------------------
        match self.dao_manager.get_account_dao(){
            Ok(account_dao) => {
                // END Retrieve DAO ---------------------------------------------------------------

                match ObjectId::with_string(&user_id){
                    Ok(user_obj_id) => {
                        match ObjectId::with_string(&mm_id){
                            Ok(mm_obj_id) => {

                                // Parse body to AccountModel
                                match req.json_as::<AccountModel>(){
                                    Ok(account) => {

                                        //Validate
                                        let validation_result = account.validate_existing();
                                        if validation_result.is_valid(){
                                            //Save the account
                                            match account_dao.update(mm_obj_id, user_obj_id, &account){
                                                Ok(updated_account) => {
                                                    ApiResult::Success{result:OutAccountModel::new(updated_account)}
                                                },
                                                Err(e) => {
                                                    ApiResult::Failure{msg:e.get_message()}
                                                }
                                            }
                                        }else{
                                            ApiResult::Invalid{validation:validation_result, request:account}
                                        }

                                    },
                                    Err(e) => {
                                        error!("{}",e);
                                        ApiResult::Failure{msg:"Invalid format. Unable to parse data."}
                                    }
                                }
                            },
                            Err(e) => {
                                error!("{}", e);
                                ApiResult::Failure{msg:"Failed to find money map. Invalid money map ID."}
                            }
                        }
                    },
                    Err(e) => {
                        error!("{}", e);
                        ApiResult::Failure{msg:"Failed to find money map. Invalid user ID."}
                    }
                }
                // START Retrieve DAO Error Handling ----------------------------------------------
            },
            Err(e) => {
                error!("{}",e.get_message().to_string());
                ApiResult::Failure{msg:"Unable to interact with database"}
            }
        }
        // END Retrieve DAO Error Handling --------------------------------------------------------
    }// end modify

    /// Delete an Account
    ///
    /// # Arguments
    /// &self
    /// req - &nickel::Request
    /// mm_id - String Money Map ID
    /// acc_id - String Account ID
    ///
    /// # Returns
    /// `ApiResult<String>` - ApiResult
    pub fn delete(&self, req: &Request<ServerData>, mm_id: String, acc_id: String) -> ApiResult<String, ()>{

        let user_id = match Session::get_session_id(req){
            Ok(id) => id,
            Err(e) => {
                error!("{}",e.get_message().to_string());
                return ApiResult::Failure{msg:"Unable to retrieve session data."};
            }
        };

        match self.dao_manager.get_account_dao(){
            Ok(dao) => {

                match ObjectId::with_string(&user_id){
                    Ok(user_obj_id) => {
                        match ObjectId::with_string(&mm_id){
                            Ok(mm_obj_id) => {
                                match ObjectId::with_string(&acc_id){
                                    Ok(acc_obj_id) => {

                                        match dao.delete(user_obj_id, mm_obj_id, acc_obj_id){
                                            Ok(result) => {
                                                if result.modified_count > 0 {
                                                    ApiResult::Success{result:"Successfully deleted account".to_string()}
                                                }else if result.acknowledged && result.matched_count == 0{
                                                    ApiResult::Failure{msg:"Unable to delete account"}
                                                }else{
                                                    ApiResult::Failure{msg:"Unable to delete account"}
                                                }
                                            },
                                            Err(e) => {
                                                error!("{}",e);
                                                ApiResult::Failure{msg:"Malformed ID"}
                                            }
                                        }
                                    },
                                    Err(e) => {
                                        error!("{}", e);
                                        ApiResult::Failure{msg:"Failed to delete account. Invalid account ID."}
                                    }
                                }
                            },
                            Err(e) => {
                                error!("{}", e);
                                ApiResult::Failure{msg:"Failed to delete account. Invalid money map ID."}
                            }
                        }
                    },
                    Err(e) => {
                        error!("{}", e);
                        ApiResult::Failure{msg:"Failed to delete account. Invalid user ID."}
                    }
                }
            },
            Err(e) => {
                error!("{}",e.get_message().to_string());
                ApiResult::Failure{msg:"Unable to interact with database"}
            }
        }
    }// end delete

}
<commit_msg>Fix can't find account for deletion message<commit_after>// src/controllers/accounts_controller.rs

/// Accounts Controller

// Import
// External
use ::nickel::{JsonBody, Request};
use ::bson::{Bson};
use ::bson::oid::ObjectId;
// Utilities
use ::common::api_result::ApiResult;
use ::common::config::Config;
use ::common::data_access::ServerData;
use ::common::session as Session;
// Models
use ::models::account_model::{AccountModel, OutAccountModel};
// DAO
use ::dao::dao_manager::DAOManager;

#[derive(Clone)]
pub struct AccountsController{
    dao_manager: DAOManager,
    config: Config
}

impl AccountsController{

    pub fn new(dao_manager: DAOManager, config: Config) -> AccountsController{
        AccountsController{
            dao_manager: dao_manager,
            config: config
        }
    }

    /// Create Account
    ///
    /// # Arguments
    /// &self
    /// req - nickel::Request
    /// mm_id - String Money Map ID
    ///
    /// # Returns
    /// `ApiResult<OutAccountModel, AccountModel>` - ApiResult including the created account
    pub fn create(&self, req: &mut Request<ServerData>, mm_id: String) -> ApiResult<OutAccountModel, AccountModel>{

        let user_id = match Session::get_session_id(req){
            Ok(id) => id,
            Err(e) => {
                error!("{}",e.get_message().to_string());
                return ApiResult::Failure{msg:"Unable to retrieve session data."};
            }
        };

        // START Retrieve DAO ---------------------------------------------------------------------
        match self.dao_manager.get_money_map_dao(){
            Ok(mm_dao) => {
                match self.dao_manager.get_account_dao(){
                    Ok(account_dao) => {
                        // END Retrieve DAO -------------------------------------------------------

                        match ObjectId::with_string(&mm_id){
                            Ok(mm_obj_id) => {
                                match ObjectId::with_string(&user_id){
                                    Ok(user_obj_id) => {

                                        let filter = doc!{
                                            "_id" => (mm_obj_id.clone()),
                                            "users.user_id" => user_obj_id,
                                            "deleted" => {
                                                "$ne" => true
                                            }
                                        };
                                        match mm_dao.find_one(Some(filter), None){
                                            Some(_) => {

                                                // Parse body to AccountModel
                                                match req.json_as::<AccountModel>(){
                                                    Ok(account) => {

                                                        // Validate
                                                        let validation_result = account.validate_new();
                                                        if validation_result.is_valid(){
                                                            // Save Account
                                                            match account_dao.create(mm_obj_id, &account){
                                                                Ok(new_account) => {

                                                                    ApiResult::Success{result:OutAccountModel::new(new_account)}
                                                                },
                                                                Err(e) => {
                                                                    error!("{}",e);
                                                                    ApiResult::Failure{msg:"Unable to create account"}
                                                                }
                                                            }
                                                        }else{
                                                            ApiResult::Invalid{validation:validation_result, request:account}
                                                        }

                                                    },
                                                    Err(e) => {
                                                        error!("{}",e);
                                                        ApiResult::Failure{msg:"Invalid format. Unable to parse data."}
                                                    }
                                                }
                                            },
                                            None => {
                                                ApiResult::Failure{msg:"Unable to find money map."}
                                            }
                                        }
                                    },
                                    Err(e) => {
                                        error!("{}", e);
                                        ApiResult::Failure{msg:"Failed to find money map. Invalid user ID."}
                                    }
                                }
                            },
                            Err(e) => {
                                error!("{}", e);
                                ApiResult::Failure{msg:"Failed to find money map. Invalid ID."}
                            }
                        }

                        // START Retrieve DAO Error Handling --------------------------------------
                    },
                    Err(e) => {
                        error!("{}",e.get_message().to_string());
                        ApiResult::Failure{msg:"Unable to interact with database"}
                    }
                }
            },
            Err(e) => {
                error!("{}",e.get_message().to_string());
                ApiResult::Failure{msg:"Unable to interact with database"}
            }
        }
        // END Retrieve DAO Error Handling --------------------------------------------------------
    }// end create

    /// Retrieve all money map accounts
    ///
    /// # Arguments
    /// &self
    /// req - nickel::Request
    /// mm_id - String Money Map ID
    ///
    /// # Returns
    /// `ApiResult<Vec<MoneyMapModel>>` - ApiResult including a vector of money maps
    pub fn find(&self, req: &mut Request<ServerData>, mm_id: String) -> ApiResult<Vec<OutAccountModel>, ()>{

        let user_id = match Session::get_session_id(req){
            Ok(id) => id,
            Err(e) => {
                error!("{}",e.get_message().to_string());
                return ApiResult::Failure{msg:"Unable to retrieve session data."};
            }
        };

        // START Retrieve DAO ---------------------------------------------------------------------
        match self.dao_manager.get_account_dao(){
            Ok(account_dao) => {
                // END Retrieve DAO ---------------------------------------------------------------

                match ObjectId::with_string(&mm_id){
                    Ok(mm_obj_id) => {
                        match ObjectId::with_string(&user_id){
                            Ok(user_obj_id) => {

                                // Get list of accounts for money map
                                match account_dao.find(user_obj_id, mm_obj_id){
                                    Some(accounts) => {
                                        ApiResult::Success{
                                            result:accounts.into_iter().map(|x| OutAccountModel::new(x)).collect()
                                        }
                                    },
                                    None => {
                                        ApiResult::Failure{msg:"Unable to find money map."}
                                    }
                                }
                            },
                            Err(e) => {
                                error!("{}", e);
                                ApiResult::Failure{msg:"Failed to find money map. Invalid user ID."}
                            }
                        }
                    },
                    Err(e) => {
                        error!("{}", e);
                        ApiResult::Failure{msg:"Failed to find money map. Invalid ID."}
                    }
                }
                // START Retrieve DAO Error Handling ----------------------------------------------
            },
            Err(e) => {
                error!("{}",e.get_message().to_string());
                ApiResult::Failure{msg:"Unable to interact with database"}
            }
        }
        // END Retrieve DAO Error Handling --------------------------------------------------------
    }// end find_all

    /// Modify Account
    ///
    /// # Arguments
    /// &self
    /// req - nickel::Request
    /// mm_id - String Money Map ID
    ///
    /// # Returns
    /// `ApiResult<AccountModel, AccountModel>` - ApiResult including the modified Account
    pub fn modify(&self, req: &mut Request<ServerData>, mm_id: String) -> ApiResult<OutAccountModel, AccountModel>{

        let user_id = match Session::get_session_id(req){
            Ok(id) => id,
            Err(e) => {
                error!("{}",e.get_message().to_string());
                return ApiResult::Failure{msg:"Unable to retrieve session data."};
            }
        };

        // START Retrieve DAO ---------------------------------------------------------------------
        match self.dao_manager.get_account_dao(){
            Ok(account_dao) => {
                // END Retrieve DAO ---------------------------------------------------------------

                match ObjectId::with_string(&user_id){
                    Ok(user_obj_id) => {
                        match ObjectId::with_string(&mm_id){
                            Ok(mm_obj_id) => {

                                // Parse body to AccountModel
                                match req.json_as::<AccountModel>(){
                                    Ok(account) => {

                                        //Validate
                                        let validation_result = account.validate_existing();
                                        if validation_result.is_valid(){
                                            //Save the account
                                            match account_dao.update(mm_obj_id, user_obj_id, &account){
                                                Ok(updated_account) => {
                                                    ApiResult::Success{result:OutAccountModel::new(updated_account)}
                                                },
                                                Err(e) => {
                                                    ApiResult::Failure{msg:e.get_message()}
                                                }
                                            }
                                        }else{
                                            ApiResult::Invalid{validation:validation_result, request:account}
                                        }

                                    },
                                    Err(e) => {
                                        error!("{}",e);
                                        ApiResult::Failure{msg:"Invalid format. Unable to parse data."}
                                    }
                                }
                            },
                            Err(e) => {
                                error!("{}", e);
                                ApiResult::Failure{msg:"Failed to find money map. Invalid money map ID."}
                            }
                        }
                    },
                    Err(e) => {
                        error!("{}", e);
                        ApiResult::Failure{msg:"Failed to find money map. Invalid user ID."}
                    }
                }
                // START Retrieve DAO Error Handling ----------------------------------------------
            },
            Err(e) => {
                error!("{}",e.get_message().to_string());
                ApiResult::Failure{msg:"Unable to interact with database"}
            }
        }
        // END Retrieve DAO Error Handling --------------------------------------------------------
    }// end modify

    /// Delete an Account
    ///
    /// # Arguments
    /// &self
    /// req - &nickel::Request
    /// mm_id - String Money Map ID
    /// acc_id - String Account ID
    ///
    /// # Returns
    /// `ApiResult<String>` - ApiResult
    pub fn delete(&self, req: &Request<ServerData>, mm_id: String, acc_id: String) -> ApiResult<String, ()>{

        let user_id = match Session::get_session_id(req){
            Ok(id) => id,
            Err(e) => {
                error!("{}",e.get_message().to_string());
                return ApiResult::Failure{msg:"Unable to retrieve session data."};
            }
        };

        match self.dao_manager.get_account_dao(){
            Ok(dao) => {

                match ObjectId::with_string(&user_id){
                    Ok(user_obj_id) => {
                        match ObjectId::with_string(&mm_id){
                            Ok(mm_obj_id) => {
                                match ObjectId::with_string(&acc_id){
                                    Ok(acc_obj_id) => {

                                        match dao.delete(user_obj_id, mm_obj_id, acc_obj_id){
                                            Ok(result) => {
                                                if result.modified_count > 0 {
                                                    ApiResult::Success{result:"Successfully deleted account".to_string()}
                                                }else if result.acknowledged && result.matched_count == 0{
                                                    ApiResult::Failure{msg:"Unable to find account"}
                                                }else{
                                                    ApiResult::Failure{msg:"Unable to delete account"}
                                                }
                                            },
                                            Err(e) => {
                                                error!("{}",e);
                                                ApiResult::Failure{msg:"Malformed ID"}
                                            }
                                        }
                                    },
                                    Err(e) => {
                                        error!("{}", e);
                                        ApiResult::Failure{msg:"Failed to delete account. Invalid account ID."}
                                    }
                                }
                            },
                            Err(e) => {
                                error!("{}", e);
                                ApiResult::Failure{msg:"Failed to delete account. Invalid money map ID."}
                            }
                        }
                    },
                    Err(e) => {
                        error!("{}", e);
                        ApiResult::Failure{msg:"Failed to delete account. Invalid user ID."}
                    }
                }
            },
            Err(e) => {
                error!("{}",e.get_message().to_string());
                ApiResult::Failure{msg:"Unable to interact with database"}
            }
        }
    }// end delete

}
<|endoftext|>