<commit_before>#![crate_name = "uu_install"]

/*
 * This file is part of the uutils coreutils package.
 *
 * (c) Ben Eills <ben@beneills.com>
 *
 * For the full copyright and license information, please view the LICENSE file
 * that was distributed with this source code.
 */

extern crate getopts;
extern crate libc;

mod mode;

#[macro_use]
extern crate uucore;

use std::fs;
use std::io::Write;
use std::path::{Path, PathBuf};
use std::result::Result;

static NAME: &'static str = "install";
static SUMMARY: &'static str = "Copy SOURCE to DEST or multiple SOURCE(s) to the existing
 DIRECTORY, while setting permission modes and owner/group";
static LONG_HELP: &'static str = "";

const DEFAULT_MODE: u32 = 755;

#[allow(dead_code)]
pub struct Behaviour {
    main_function: MainFunction,
    specified_mode: Option<u32>,
    suffix: String,
    verbose: bool
}

#[derive(Clone, Eq, PartialEq)]
pub enum MainFunction {
    /// Create directories
    Directory,
    /// Install files to locations (primary functionality)
    Standard
}

impl Behaviour {
    /// Determine the mode for chmod after copy.
    pub fn mode(&self) -> u32 {
        match self.specified_mode {
            Some(x) => x,
            None => DEFAULT_MODE
        }
    }
}

/// Main install utility function, called from main.rs.
///
/// Returns a program return code.
///
pub fn uumain(args: Vec<String>) -> i32 {
    let matches = parse_opts(args);

    if let Err(s) = check_unimplemented(&matches) {
        show_error!("Unimplemented feature: {}", s);
        return 2;
    }

    let behaviour = match behaviour(&matches) {
        Ok(x) => x,
        Err(ret) => {
            return ret;
        }
    };

    let paths: Vec<PathBuf> = {
        fn string_to_path<'a>(s: &'a String) -> &'a Path {
            Path::new(s)
        };
        let to_owned = |p: &Path| p.to_owned();
        let arguments = matches.free.iter().map(string_to_path);

        arguments.map(to_owned).collect()
    };

    match behaviour.main_function {
        MainFunction::Directory => {
            directory(&paths[..], behaviour)
        },
        MainFunction::Standard => {
            standard(&paths[..], behaviour)
        }
    }
}

/// Build a specification of the command line.
///
/// Returns a getopts::Options struct.
///
fn parse_opts(args: Vec<String>) -> getopts::Matches {
    let syntax = format!("SOURCE DEST
 {} SOURCE... DIRECTORY", NAME);
     new_coreopts!(&syntax, SUMMARY, LONG_HELP)
    // TODO implement flag
        .optflagopt("",  "backup", "(unimplemented) make a backup of each existing destination\n \
                                    file", "CONTROL")
    // TODO implement flag
        .optflag("b", "", "(unimplemented) like --backup but does not accept an argument")
    // TODO implement flag
        .optflag("C", "compare", "(unimplemented) compare each pair of source and destination\n \
                                  files, and in some cases, do not modify the destination at all")
        .optflag("d", "directory", "treat all arguments as directory names\n \
                                    create all components of the specified directories")
    // TODO implement flag
        .optflag("D", "", "(unimplemented) create all leading components of DEST except the\n \
                           last, then copy SOURCE to DEST")
    // TODO implement flag
        .optflagopt("g", "group", "(unimplemented) set group ownership, instead of process'\n \
                                   current group", "GROUP")
        .optflagopt("m", "mode", "set permission mode (as in chmod), instead\n \
                                  of rwxr-xr-x", "MODE")
    // TODO implement flag
        .optflagopt("o", "owner", "(unimplemented) set ownership (super-user only)",
                    "OWNER")
    // TODO implement flag
        .optflag("p", "preserve-timestamps", "(unimplemented) apply access/modification times\n \
                                              of SOURCE files to corresponding destination files")
    // TODO implement flag
        .optflag("s", "strip", "(unimplemented) strip symbol tables")
    // TODO implement flag
        .optflagopt("", "strip-program", "(unimplemented) program used to strip binaries",
                    "PROGRAM")
    // TODO implement flag
        .optopt("S", "suffix", "(unimplemented) override the usual backup suffix", "SUFFIX")
    // TODO implement flag
        .optopt("t", "target-directory", "(unimplemented) move all SOURCE arguments into\n \
                                          DIRECTORY", "DIRECTORY")
    // TODO implement flag
        .optflag("T", "no-target-directory", "(unimplemented) treat DEST as a normal file")
    // TODO implement flag
        .optflag("v", "verbose", "(unimplemented) explain what is being done")
    // TODO implement flag
        .optflag("P", "preserve-context", "(unimplemented) preserve security context")
    // TODO implement flag
        .optflagopt("Z", "context", "(unimplemented) set security context of files and\n \
                                     directories", "CONTEXT")
        .parse(args)
}

/// Check for unimplemented command line arguments.
///
/// Either return the degenerate Ok value, or an Err with string.
///
/// # Errors
///
/// Error datum is a string of the unimplemented argument.
///
fn check_unimplemented(matches: &getopts::Matches) -> Result<(), &str> {
    if matches.opt_present("backup") {
        Err("--backup")
    } else if matches.opt_present("b") {
        Err("-b")
    } else if matches.opt_present("compare") {
        Err("--compare, -C")
    } else if matches.opt_present("D") {
        Err("-D")
    } else if matches.opt_present("group") {
        Err("--group, -g")
    } else if matches.opt_present("owner") {
        Err("--owner, -o")
    } else if matches.opt_present("preserve-timestamps") {
        Err("--preserve-timestamps, -p")
    } else if matches.opt_present("strip") {
        Err("--strip, -s")
    } else if matches.opt_present("strip-program") {
        Err("--strip-program")
    } else if matches.opt_present("suffix") {
        Err("--suffix, -S")
    } else if matches.opt_present("target-directory") {
        Err("--target-directory, -t")
    } else if matches.opt_present("no-target-directory") {
        Err("--no-target-directory, -T")
    } else if matches.opt_present("verbose") {
        Err("--verbose, -v")
    } else if matches.opt_present("preserve-context") {
        Err("--preserve-context, -P")
    } else if matches.opt_present("context") {
        Err("--context, -Z")
    } else {
        Ok(())
    }
}

/// Determine behaviour, given command line arguments.
///
/// If successful, returns a filled-out Behaviour struct.
///
/// # Errors
///
/// In event of failure, returns an integer intended as a program return code.
///
fn behaviour(matches: &getopts::Matches) -> Result<Behaviour, i32> {
    let main_function = if matches.opt_present("directory") {
        MainFunction::Directory
    } else {
        MainFunction::Standard
    };

    let considering_dir: bool = MainFunction::Directory == main_function;

    let specified_mode: Option<u32> = if matches.opt_present("mode") {
        match matches.opt_str("mode") {
            Some(x) => {
                match mode::parse(&x[..], considering_dir) {
                    Ok(y) => Some(y),
                    Err(err) => {
                        show_error!("Invalid mode string: {}", err);
                        return Err(1);
                    }
                }
            },
            None => {
                show_error!("option '--mode' requires an argument\n \
                            Try '{} --help' for more information.", NAME);
                return Err(1);
            }
        }
    } else {
        None
    };

    let backup_suffix = if matches.opt_present("suffix") {
        match matches.opt_str("suffix") {
            Some(x) => x,
            None => {
                show_error!("option '--suffix' requires an argument\n\
                            Try '{} --help' for more information.", NAME);
                return Err(1);
            }
        }
    } else {
        "~".to_owned()
    };

    Ok(Behaviour {
        main_function: main_function,
        specified_mode: specified_mode,
        suffix: backup_suffix,
        verbose: matches.opt_present("v"),
    })
}

/// Creates directories.
///
/// GNU man pages describe this functionality as creating 'all components of
/// the specified directories'.
///
/// Returns an integer intended as a program return code.
///
fn directory(paths: &[PathBuf], b: Behaviour) -> i32 {
    if paths.len() < 1 {
        println!("{} with -d requires at least one argument.", NAME);
        1
    } else {
        let mut all_successful = true;

        for directory in paths.iter() {
            let path = directory.as_path();

            if path.exists() {
                show_info!("cannot create directory '{}': File exists", path.display());
                all_successful = false;
            }

            if let Err(e) = fs::create_dir(directory) {
                show_info!("{}: {}", path.display(), e.to_string());
                all_successful = false;
            }

            if mode::chmod(&path, b.mode()).is_err() {
                all_successful = false;
            }

            if b.verbose {
                show_info!("created directory '{}'", path.display());
            }
        }
        if all_successful { 0 } else { 1 }
    }
}

/// Perform an install, given a list of paths and behaviour.
///
/// Returns an integer intended as a program return code.
///
fn standard(paths: &[PathBuf], b: Behaviour) -> i32 {
    if paths.len() < 2 {
        println!("{} requires at least 2 arguments.", NAME);
        1
    } else {
        let sources = &paths[0..paths.len() - 1];
        let target_directory = &paths[paths.len() - 1];

        copy_files_into_dir(sources, target_directory, &b)
    }
}

/// Copy some files into a directory.
///
/// Prints verbose information and error messages.
/// Returns an integer intended as a program return code.
///
/// # Parameters
///
/// _files_ must all exist as non-directories.
/// _target_dir_ must be a directory.
///
fn copy_files_into_dir(files: &[PathBuf], target_dir: &PathBuf, b: &Behaviour) -> i32 {
    if !target_dir.is_dir() {
        show_error!("target ‘{}’ is not a directory", target_dir.display());
        return 1;
    }

    let mut all_successful = true;
    for sourcepath in files.iter() {
        let targetpath = match sourcepath.as_os_str().to_str() {
            Some(name) => target_dir.join(name),
            None => {
                show_error!("cannot stat ‘{}’: No such file or directory",
                            sourcepath.display());

                all_successful = false;
                continue;
            }
        };

        if copy(sourcepath, &targetpath, b).is_err() {
            all_successful = false;
        }
    };
    if all_successful { 0 } else { 1 }
}

/// Copy one file to a new location, changing metadata.
///
/// # Parameters
///
/// _from_ must exist as a non-directory.
/// _to_ must be a non-existent file, whose parent directory exists.
///
/// # Errors
///
/// If the copy system call fails, we print a verbose error and return an empty error value.
///
fn copy(from: &PathBuf, to: &PathBuf, b: &Behaviour) -> Result<(), ()> {
    let io_result = fs::copy(from, to);

    if let Err(err) = io_result {
        show_error!("install: cannot install ‘{}’ to ‘{}’: {}",
                    from.display(), to.display(), err);
        return Err(());
    }

    if mode::chmod(&to, b.mode()).is_err() {
        return Err(());
    }

    if b.verbose {
        print!("‘{}’ -> ‘{}’", from.display(), to.display());
    }

    Ok(())
}
<commit_msg>install: Fix verbose mode<commit_after>#![crate_name = "uu_install"]

/*
 * This file is part of the uutils coreutils package.
 *
 * (c) Ben Eills <ben@beneills.com>
 *
 * For the full copyright and license information, please view the LICENSE file
 * that was distributed with this source code.
 */

extern crate getopts;
extern crate libc;

mod mode;

#[macro_use]
extern crate uucore;

use std::fs;
use std::io::Write;
use std::path::{Path, PathBuf};
use std::result::Result;

static NAME: &'static str = "install";
static SUMMARY: &'static str = "Copy SOURCE to DEST or multiple SOURCE(s) to the existing
 DIRECTORY, while setting permission modes and owner/group";
static LONG_HELP: &'static str = "";

const DEFAULT_MODE: u32 = 755;

#[allow(dead_code)]
pub struct Behaviour {
    main_function: MainFunction,
    specified_mode: Option<u32>,
    suffix: String,
    verbose: bool
}

#[derive(Clone, Eq, PartialEq)]
pub enum MainFunction {
    /// Create directories
    Directory,
    /// Install files to locations (primary functionality)
    Standard
}

impl Behaviour {
    /// Determine the mode for chmod after copy.
    pub fn mode(&self) -> u32 {
        match self.specified_mode {
            Some(x) => x,
            None => DEFAULT_MODE
        }
    }
}

/// Main install utility function, called from main.rs.
///
/// Returns a program return code.
///
pub fn uumain(args: Vec<String>) -> i32 {
    let matches = parse_opts(args);

    if let Err(s) = check_unimplemented(&matches) {
        show_error!("Unimplemented feature: {}", s);
        return 2;
    }

    let behaviour = match behaviour(&matches) {
        Ok(x) => x,
        Err(ret) => {
            return ret;
        }
    };

    let paths: Vec<PathBuf> = {
        fn string_to_path<'a>(s: &'a String) -> &'a Path {
            Path::new(s)
        };
        let to_owned = |p: &Path| p.to_owned();
        let arguments = matches.free.iter().map(string_to_path);

        arguments.map(to_owned).collect()
    };

    match behaviour.main_function {
        MainFunction::Directory => {
            directory(&paths[..], behaviour)
        },
        MainFunction::Standard => {
            standard(&paths[..], behaviour)
        }
    }
}

/// Build a specification of the command line.
///
/// Returns a getopts::Options struct.
///
fn parse_opts(args: Vec<String>) -> getopts::Matches {
    let syntax = format!("SOURCE DEST
 {} SOURCE... DIRECTORY", NAME);
     new_coreopts!(&syntax, SUMMARY, LONG_HELP)
    // TODO implement flag
        .optflagopt("",  "backup", "(unimplemented) make a backup of each existing destination\n \
                                    file", "CONTROL")
    // TODO implement flag
        .optflag("b", "", "(unimplemented) like --backup but does not accept an argument")
    // TODO implement flag
        .optflag("C", "compare", "(unimplemented) compare each pair of source and destination\n \
                                  files, and in some cases, do not modify the destination at all")
        .optflag("d", "directory", "treat all arguments as directory names\n \
                                    create all components of the specified directories")
    // TODO implement flag
        .optflag("D", "", "(unimplemented) create all leading components of DEST except the\n \
                           last, then copy SOURCE to DEST")
    // TODO implement flag
        .optflagopt("g", "group", "(unimplemented) set group ownership, instead of process'\n \
                                   current group", "GROUP")
        .optflagopt("m", "mode", "set permission mode (as in chmod), instead\n \
                                  of rwxr-xr-x", "MODE")
    // TODO implement flag
        .optflagopt("o", "owner", "(unimplemented) set ownership (super-user only)",
                    "OWNER")
    // TODO implement flag
        .optflag("p", "preserve-timestamps", "(unimplemented) apply access/modification times\n \
                                              of SOURCE files to corresponding destination files")
    // TODO implement flag
        .optflag("s", "strip", "(unimplemented) strip symbol tables")
    // TODO implement flag
        .optflagopt("", "strip-program", "(unimplemented) program used to strip binaries",
                    "PROGRAM")
    // TODO implement flag
        .optopt("S", "suffix", "(unimplemented) override the usual backup suffix", "SUFFIX")
    // TODO implement flag
        .optopt("t", "target-directory", "(unimplemented) move all SOURCE arguments into\n \
                                          DIRECTORY", "DIRECTORY")
    // TODO implement flag
        .optflag("T", "no-target-directory", "(unimplemented) treat DEST as a normal file")
        .optflag("v", "verbose", "explain what is being done")
    // TODO implement flag
        .optflag("P", "preserve-context", "(unimplemented) preserve security context")
    // TODO implement flag
        .optflagopt("Z", "context", "(unimplemented) set security context of files and\n \
                                     directories", "CONTEXT")
        .parse(args)
}

/// Check for unimplemented command line arguments.
///
/// Either return the degenerate Ok value, or an Err with string.
///
/// # Errors
///
/// Error datum is a string of the unimplemented argument.
///
fn check_unimplemented(matches: &getopts::Matches) -> Result<(), &str> {
    if matches.opt_present("backup") {
        Err("--backup")
    } else if matches.opt_present("b") {
        Err("-b")
    } else if matches.opt_present("compare") {
        Err("--compare, -C")
    } else if matches.opt_present("D") {
        Err("-D")
    } else if matches.opt_present("group") {
        Err("--group, -g")
    } else if matches.opt_present("owner") {
        Err("--owner, -o")
    } else if matches.opt_present("preserve-timestamps") {
        Err("--preserve-timestamps, -p")
    } else if matches.opt_present("strip") {
        Err("--strip, -s")
    } else if matches.opt_present("strip-program") {
        Err("--strip-program")
    } else if matches.opt_present("suffix") {
        Err("--suffix, -S")
    } else if matches.opt_present("target-directory") {
        Err("--target-directory, -t")
    } else if matches.opt_present("no-target-directory") {
        Err("--no-target-directory, -T")
    } else if matches.opt_present("preserve-context") {
        Err("--preserve-context, -P")
    } else if matches.opt_present("context") {
        Err("--context, -Z")
    } else {
        Ok(())
    }
}

/// Determine behaviour, given command line arguments.
///
/// If successful, returns a filled-out Behaviour struct.
///
/// # Errors
///
/// In event of failure, returns an integer intended as a program return code.
///
fn behaviour(matches: &getopts::Matches) -> Result<Behaviour, i32> {
    let main_function = if matches.opt_present("directory") {
        MainFunction::Directory
    } else {
        MainFunction::Standard
    };

    let considering_dir: bool = MainFunction::Directory == main_function;

    let specified_mode: Option<u32> = if matches.opt_present("mode") {
        match matches.opt_str("mode") {
            Some(x) => {
                match mode::parse(&x[..], considering_dir) {
                    Ok(y) => Some(y),
                    Err(err) => {
                        show_error!("Invalid mode string: {}", err);
                        return Err(1);
                    }
                }
            },
            None => {
                show_error!("option '--mode' requires an argument\n \
                            Try '{} --help' for more information.", NAME);
                return Err(1);
            }
        }
    } else {
        None
    };

    let backup_suffix = if matches.opt_present("suffix") {
        match matches.opt_str("suffix") {
            Some(x) => x,
            None => {
                show_error!("option '--suffix' requires an argument\n\
                            Try '{} --help' for more information.", NAME);
                return Err(1);
            }
        }
    } else {
        "~".to_owned()
    };

    Ok(Behaviour {
        main_function: main_function,
        specified_mode: specified_mode,
        suffix: backup_suffix,
        verbose: matches.opt_present("v"),
    })
}

/// Creates directories.
///
/// GNU man pages describe this functionality as creating 'all components of
/// the specified directories'.
///
/// Returns an integer intended as a program return code.
///
fn directory(paths: &[PathBuf], b: Behaviour) -> i32 {
    if paths.len() < 1 {
        println!("{} with -d requires at least one argument.", NAME);
        1
    } else {
        let mut all_successful = true;

        for directory in paths.iter() {
            let path = directory.as_path();

            if path.exists() {
                show_info!("cannot create directory '{}': File exists", path.display());
                all_successful = false;
            }

            if let Err(e) = fs::create_dir(directory) {
                show_info!("{}: {}", path.display(), e.to_string());
                all_successful = false;
            }

            if mode::chmod(&path, b.mode()).is_err() {
                all_successful = false;
            }

            if b.verbose {
                show_info!("created directory '{}'", path.display());
            }
        }
        if all_successful { 0 } else { 1 }
    }
}

/// Perform an install, given a list of paths and behaviour.
///
/// Returns an integer intended as a program return code.
///
fn standard(paths: &[PathBuf], b: Behaviour) -> i32 {
    if paths.len() < 2 {
        println!("{} requires at least 2 arguments.", NAME);
        1
    } else {
        let sources = &paths[0..paths.len() - 1];
        let target_directory = &paths[paths.len() - 1];

        copy_files_into_dir(sources, target_directory, &b)
    }
}

/// Copy some files into a directory.
///
/// Prints verbose information and error messages.
/// Returns an integer intended as a program return code.
///
/// # Parameters
///
/// _files_ must all exist as non-directories.
/// _target_dir_ must be a directory.
///
fn copy_files_into_dir(files: &[PathBuf], target_dir: &PathBuf, b: &Behaviour) -> i32 {
    if !target_dir.is_dir() {
        show_error!("target ‘{}’ is not a directory", target_dir.display());
        return 1;
    }

    let mut all_successful = true;
    for sourcepath in files.iter() {
        let targetpath = match sourcepath.as_os_str().to_str() {
            Some(name) => target_dir.join(name),
            None => {
                show_error!("cannot stat ‘{}’: No such file or directory",
                            sourcepath.display());

                all_successful = false;
                continue;
            }
        };

        if copy(sourcepath, &targetpath, b).is_err() {
            all_successful = false;
        }
    };
    if all_successful { 0 } else { 1 }
}

/// Copy one file to a new location, changing metadata.
///
/// # Parameters
///
/// _from_ must exist as a non-directory.
/// _to_ must be a non-existent file, whose parent directory exists.
///
/// # Errors
///
/// If the copy system call fails, we print a verbose error and return an empty error value.
///
fn copy(from: &PathBuf, to: &PathBuf, b: &Behaviour) -> Result<(), ()> {
    let io_result = fs::copy(from, to);

    if let Err(err) = io_result {
        show_error!("install: cannot install ‘{}’ to ‘{}’: {}",
                    from.display(), to.display(), err);
        return Err(());
    }

    if mode::chmod(&to, b.mode()).is_err() {
        return Err(());
    }

    if b.verbose {
        show_info!("'{}' -> '{}'", from.display(), to.display());
    }

    Ok(())
}
<|endoftext|>


<commit_before>use super::plumbing::*;
use super::*;
use std::sync::atomic::{AtomicBool, Ordering};

/// `WhileSome` is an iterator that yields the `Some` elements of an iterator,
/// halting as soon as any `None` is produced.
///
/// This struct is created by the [`while_some()`] method on [`ParallelIterator`]
///
/// [`while_some()`]: trait.ParallelIterator.html#method.while_some
/// [`ParallelIterator`]: trait.ParallelIterator.html
#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
#[derive(Debug, Clone)]
pub struct WhileSome<I: ParallelIterator> {
    base: I,
}

/// Create a new `WhileSome` iterator.
///
/// NB: a free fn because it is NOT part of the end-user API.
pub fn new<I>(base: I) -> WhileSome<I>
where
    I: ParallelIterator,
{
    WhileSome { base: base }
}

impl<I, T> ParallelIterator for WhileSome<I>
where
    I: ParallelIterator<Item = Option<T>>,
    T: Send,
{
    type Item = T;

    fn drive_unindexed<C>(self, consumer: C) -> C::Result
    where
        C: UnindexedConsumer<Self::Item>,
    {
        let full = AtomicBool::new(false);
        let consumer1 = WhileSomeConsumer {
            base: consumer,
            full: &full,
        };
        self.base.drive_unindexed(consumer1)
    }
}

/// ////////////////////////////////////////////////////////////////////////
/// Consumer implementation

struct WhileSomeConsumer<'f, C> {
    base: C,
    full: &'f AtomicBool,
}

impl<'f, T, C> Consumer<Option<T>> for WhileSomeConsumer<'f, C>
where
    C: Consumer<T>,
    T: Send,
{
    type Folder = WhileSomeFolder<'f, C::Folder>;
    type Reducer = C::Reducer;
    type Result = C::Result;

    fn split_at(self, index: usize) -> (Self, Self, Self::Reducer) {
        let (left, right, reducer) = self.base.split_at(index);
        (
            WhileSomeConsumer { base: left, ..self },
            WhileSomeConsumer {
                base: right,
                ..self
            },
            reducer,
        )
    }

    fn into_folder(self) -> Self::Folder {
        WhileSomeFolder {
            base: self.base.into_folder(),
            full: self.full,
        }
    }

    fn full(&self) -> bool {
        self.full.load(Ordering::Relaxed) || self.base.full()
    }
}

impl<'f, T, C> UnindexedConsumer<Option<T>> for WhileSomeConsumer<'f, C>
where
    C: UnindexedConsumer<T>,
    T: Send,
{
    fn split_off_left(&self) -> Self {
        WhileSomeConsumer {
            base: self.base.split_off_left(),
            ..*self
        }
    }

    fn to_reducer(&self) -> Self::Reducer {
        self.base.to_reducer()
    }
}

struct WhileSomeFolder<'f, C> {
    base: C,
    full: &'f AtomicBool,
}

impl<'f, T, C> Folder<Option<T>> for WhileSomeFolder<'f, C>
where
    C: Folder<T>,
{
    type Result = C::Result;

    fn consume(mut self, item: Option<T>) -> Self {
        match item {
            Some(item) => self.base = self.base.consume(item),
            None => self.full.store(true, Ordering::Relaxed),
        }
        self
    }

    fn complete(self) -> C::Result {
        self.base.complete()
    }

    fn full(&self) -> bool {
        self.full.load(Ordering::Relaxed) || self.base.full()
    }
}
<commit_msg>Specialize `consume_iter` for `WhileSomeFolder`<commit_after>use super::plumbing::*;
use super::*;
use std::sync::atomic::{AtomicBool, Ordering};

/// `WhileSome` is an iterator that yields the `Some` elements of an iterator,
/// halting as soon as any `None` is produced.
///
/// This struct is created by the [`while_some()`] method on [`ParallelIterator`]
///
/// [`while_some()`]: trait.ParallelIterator.html#method.while_some
/// [`ParallelIterator`]: trait.ParallelIterator.html
#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
#[derive(Debug, Clone)]
pub struct WhileSome<I: ParallelIterator> {
    base: I,
}

/// Create a new `WhileSome` iterator.
///
/// NB: a free fn because it is NOT part of the end-user API.
pub fn new<I>(base: I) -> WhileSome<I>
where
    I: ParallelIterator,
{
    WhileSome { base: base }
}

impl<I, T> ParallelIterator for WhileSome<I>
where
    I: ParallelIterator<Item = Option<T>>,
    T: Send,
{
    type Item = T;

    fn drive_unindexed<C>(self, consumer: C) -> C::Result
    where
        C: UnindexedConsumer<Self::Item>,
    {
        let full = AtomicBool::new(false);
        let consumer1 = WhileSomeConsumer {
            base: consumer,
            full: &full,
        };
        self.base.drive_unindexed(consumer1)
    }
}

/// ////////////////////////////////////////////////////////////////////////
/// Consumer implementation

struct WhileSomeConsumer<'f, C> {
    base: C,
    full: &'f AtomicBool,
}

impl<'f, T, C> Consumer<Option<T>> for WhileSomeConsumer<'f, C>
where
    C: Consumer<T>,
    T: Send,
{
    type Folder = WhileSomeFolder<'f, C::Folder>;
    type Reducer = C::Reducer;
    type Result = C::Result;

    fn split_at(self, index: usize) -> (Self, Self, Self::Reducer) {
        let (left, right, reducer) = self.base.split_at(index);
        (
            WhileSomeConsumer { base: left, ..self },
            WhileSomeConsumer {
                base: right,
                ..self
            },
            reducer,
        )
    }

    fn into_folder(self) -> Self::Folder {
        WhileSomeFolder {
            base: self.base.into_folder(),
            full: self.full,
        }
    }

    fn full(&self) -> bool {
        self.full.load(Ordering::Relaxed) || self.base.full()
    }
}

impl<'f, T, C> UnindexedConsumer<Option<T>> for WhileSomeConsumer<'f, C>
where
    C: UnindexedConsumer<T>,
    T: Send,
{
    fn split_off_left(&self) -> Self {
        WhileSomeConsumer {
            base: self.base.split_off_left(),
            ..*self
        }
    }

    fn to_reducer(&self) -> Self::Reducer {
        self.base.to_reducer()
    }
}

struct WhileSomeFolder<'f, C> {
    base: C,
    full: &'f AtomicBool,
}

impl<'f, T, C> Folder<Option<T>> for WhileSomeFolder<'f, C>
where
    C: Folder<T>,
{
    type Result = C::Result;

    fn consume(mut self, item: Option<T>) -> Self {
        match item {
            Some(item) => self.base = self.base.consume(item),
            None => self.full.store(true, Ordering::Relaxed),
        }
        self
    }

    fn consume_iter<I>(mut self, iter: I) -> Self
    where I: IntoIterator<Item = Option<T>>
    {
        let full = self.full;
        self.base = self.base.consume_iter(
            iter.into_iter()
                .take_while(|x| {
                    match *x {
                        Some(_) => !full.load(Ordering::Relaxed),
                        None => {
                            full.store(true, Ordering::Relaxed);
                            false
                        }
                    }
                })
                .map(|x| x.unwrap())
        );
        self
    }

    fn complete(self) -> C::Result {
        self.base.complete()
    }

    fn full(&self) -> bool {
        self.full.load(Ordering::Relaxed) || self.base.full()
    }
}
<|endoftext|>


<commit_before>extern crate sql;

pub use sql::lexer::Lexer;
pub use sql::lexer::Token;

describe! lexer_test {

    it "create lexer" {
        Lexer::new("some line here");
    }

    it "emptyline" {
        let mut lexer = Lexer::new("");

        assert_eq!(lexer.next_lexem(), None);
    }

    it "word token" {
        let mut lexer = Lexer::new("iNseRt");

        assert_eq!(lexer.next_lexem(), Some(Token::Word("insert".to_string())));
    }

    it "left parenthesis" {
        let mut lexer = Lexer::new("(");

        assert_eq!(lexer.next_lexem(), Some(Token::LeftParenthesis));
    }

    it "right parenthesis" {
        let mut lexer = Lexer::new(")");

        assert_eq!(lexer.next_lexem(), Some(Token::RightParenthesis));
    }

    it "semicolon" {
        let mut lexer = Lexer::new(";");

        assert_eq!(lexer.next_lexem(), Some(Token::SemiColon));
    }

    it "single quote" {
        let mut lexer = Lexer::new("'");

        assert_eq!(lexer.next_lexem(), Some(Token::SingleQuote));
    }

    it "insert query" {
        let mut lexer = Lexer::new("insert into tab1 values (1 , '1');");

        assert_eq!(lexer.next_lexem(), Some(Token::Word("insert".to_string())));
        assert_eq!(lexer.next_lexem(), Some(Token::Word("into".to_string())));
        assert_eq!(lexer.next_lexem(), Some(Token::Word("tab1".to_string())));
        assert_eq!(lexer.next_lexem(), Some(Token::Word("values".to_string())));
        assert_eq!(lexer.next_lexem(), Some(Token::LeftParenthesis));
        assert_eq!(lexer.next_lexem(), Some(Token::Word("1".to_string())));
        assert_eq!(lexer.next_lexem(), Some(Token::Colon));
        assert_eq!(lexer.next_lexem(), Some(Token::SingleQuote));
        assert_eq!(lexer.next_lexem(), Some(Token::Word("1".to_string())));
        assert_eq!(lexer.next_lexem(), Some(Token::SingleQuote));
        assert_eq!(lexer.next_lexem(), Some(Token::RightParenthesis));
        assert_eq!(lexer.next_lexem(), Some(Token::SemiColon));
    }

    it "insert query with column sequence" {
        let mut lexer = Lexer::new("insert into tab1 (col_1 , col2) values(1, '1');");

        assert_eq!(lexer.next_lexem(), Some(Token::Word("insert".to_string())));
        assert_eq!(lexer.next_lexem(), Some(Token::Word("into".to_string())));
        assert_eq!(lexer.next_lexem(), Some(Token::Word("tab1".to_string())));
        assert_eq!(lexer.next_lexem(), Some(Token::LeftParenthesis));
        assert_eq!(lexer.next_lexem(), Some(Token::Word("col_1".to_string())));
        assert_eq!(lexer.next_lexem(), Some(Token::Colon));
        assert_eq!(lexer.next_lexem(), Some(Token::Word("col2".to_string())));
        assert_eq!(lexer.next_lexem(), Some(Token::RightParenthesis));
        assert_eq!(lexer.next_lexem(), Some(Token::Word("values".to_string())));
        assert_eq!(lexer.next_lexem(), Some(Token::LeftParenthesis));
        assert_eq!(lexer.next_lexem(), Some(Token::Word("1".to_string())));
        assert_eq!(lexer.next_lexem(), Some(Token::Colon));
        assert_eq!(lexer.next_lexem(), Some(Token::SingleQuote));
        assert_eq!(lexer.next_lexem(), Some(Token::Word("1".to_string())));
        assert_eq!(lexer.next_lexem(), Some(Token::SingleQuote));
        assert_eq!(lexer.next_lexem(), Some(Token::RightParenthesis));
        assert_eq!(lexer.next_lexem(), Some(Token::SemiColon));
    }

    it "escaping by double single qout" {
        let mut lexer = Lexer::new("insert into tab1\n(col_1\t, col2 ) values (1, 'ab''s');");

        assert_eq!(lexer.next_lexem(), Some(Token::Word("insert".to_string())));
        assert_eq!(lexer.next_lexem(), Some(Token::Word("into".to_string())));
        assert_eq!(lexer.next_lexem(), Some(Token::Word("tab1".to_string())));
        assert_eq!(lexer.next_lexem(), Some(Token::LeftParenthesis));
        assert_eq!(lexer.next_lexem(), Some(Token::Word("col_1".to_string())));
        assert_eq!(lexer.next_lexem(), Some(Token::Colon));
        assert_eq!(lexer.next_lexem(), Some(Token::Word("col2".to_string())));
        assert_eq!(lexer.next_lexem(), Some(Token::RightParenthesis));
        assert_eq!(lexer.next_lexem(), Some(Token::Word("values".to_string())));
        assert_eq!(lexer.next_lexem(), Some(Token::LeftParenthesis));
        assert_eq!(lexer.next_lexem(), Some(Token::Word("1".to_string())));
        assert_eq!(lexer.next_lexem(), Some(Token::Colon));
        assert_eq!(lexer.next_lexem(), Some(Token::SingleQuote));
        assert_eq!(lexer.next_lexem(), Some(Token::Word("ab's".to_string())));
        assert_eq!(lexer.next_lexem(), Some(Token::SingleQuote));
        assert_eq!(lexer.next_lexem(), Some(Token::RightParenthesis));
        assert_eq!(lexer.next_lexem(), Some(Token::SemiColon));
    }

    it "line with comments" {
        let mut lexer = Lexer::new("insert into -- coment here finished -> \n tab1");

        assert_eq!(lexer.next_lexem(), Some(Token::Word("insert".to_string())));
        assert_eq!(lexer.next_lexem(), Some(Token::Word("into".to_string())));
        assert_eq!(lexer.next_lexem(), Some(Token::Word("tab1".to_string())));
        assert_eq!(lexer.next_lexem(), None);
        assert_eq!(lexer.next_lexem(), None);
    }

    it "insert query with escaped single quote in the begining" {
        let mut lexer = Lexer::new("insert into tab1 values ('''abs');");

        assert_eq!(lexer.next_lexem(), Some(Token::Word("insert".to_string())));
        assert_eq!(lexer.next_lexem(), Some(Token::Word("into".to_string())));
        assert_eq!(lexer.next_lexem(), Some(Token::Word("tab1".to_string())));
        assert_eq!(lexer.next_lexem(), Some(Token::Word("values".to_string())));
        assert_eq!(lexer.next_lexem(), Some(Token::LeftParenthesis));
        assert_eq!(lexer.next_lexem(), Some(Token::SingleQuote));
        assert_eq!(lexer.next_lexem(), Some(Token::Word("'abs".to_string())));
        assert_eq!(lexer.next_lexem(), Some(Token::SingleQuote));
        assert_eq!(lexer.next_lexem(), Some(Token::RightParenthesis));
        assert_eq!(lexer.next_lexem(), Some(Token::SemiColon));
    }

}
<commit_msg>test refactoring: new lines<commit_after>extern crate sql;

pub use sql::lexer::Lexer;
pub use sql::lexer::Token::*;

describe! lexer_test {

    it "create lexer" {
        Lexer::new("some line here");
    }

    it "emptyline" {
        let mut lexer = Lexer::new("");

        assert_eq!(lexer.next_lexem(), None);
    }

    it "word token" {
        let mut lexer = Lexer::new("iNseRt");

        assert_eq!(lexer.next_lexem(), Some(Word("insert".to_string())));
        assert_eq!(lexer.next_lexem(), None);
    }

    it "left parenthesis" {
        let mut lexer = Lexer::new("(");

        assert_eq!(lexer.next_lexem(), Some(LeftParenthesis));
        assert_eq!(lexer.next_lexem(), None);
    }

    it "right parenthesis" {
        let mut lexer = Lexer::new(")");

        assert_eq!(lexer.next_lexem(), Some(RightParenthesis));
        assert_eq!(lexer.next_lexem(), None);
    }

    it "semicolon" {
        let mut lexer = Lexer::new(";");

        assert_eq!(lexer.next_lexem(), Some(SemiColon));
        assert_eq!(lexer.next_lexem(), None);
    }

    it "single quote" {
        let mut lexer = Lexer::new("'");

        assert_eq!(lexer.next_lexem(), Some(SingleQuote));
        assert_eq!(lexer.next_lexem(), None);
    }

    it "new lines between words" {
        let mut lexer = Lexer::new("one\n\n\n\ntwo\n\n\nthree");

        assert_eq!(lexer.next_lexem(), Some(Word("one".to_string())));
        assert_eq!(lexer.next_lexem(), Some(Word("two".to_string())));
        assert_eq!(lexer.next_lexem(), Some(Word("three".to_string())));
        assert_eq!(lexer.next_lexem(), None);
    }
}
<|endoftext|>


<commit_before>use desync::scheduler::*;

use super::timeout::*;

use std::thread;
use std::time::*;
use std::sync::mpsc::*;

use futures::channel::oneshot;

#[test]
fn schedule_future() {
    timeout(|| {
        use futures::executor;

        let queue       = queue();
        let future      = future(&queue, move || async {
            thread::sleep(Duration::from_millis(100));
            42
        });

        executor::block_on(async {
            assert!(future.await.unwrap() == 42);
        });
    }, 500);
}

#[test]
fn schedule_future_with_no_threads_of_our_own() {
    timeout(|| {
        use futures::executor;

        let scheduler   = Scheduler::new();

        // Even with 0 threads, futures should still run (by draining on the current thread as for sync actions)
        scheduler.set_max_threads(0);
        scheduler.despawn_threads_if_overloaded();

        let queue       = queue();
        let future      = scheduler.future(&queue, move || async {
            thread::sleep(Duration::from_millis(100));
            42
        });

        executor::block_on(async {
            assert!(future.await.unwrap() == 42);
        });
    }, 500);
}

#[test]
fn wait_for_future() {
    timeout(|| {
        use futures::executor;

        // We use a oneshot as our future, and a mpsc channel to track progress
        let (tx, rx)                = channel();
        let (future_tx, future_rx)  = oneshot::channel();

        let scheduler   = scheduler();
        let queue       = queue();

        // Start by sending '1' from an async
        let tx2 = tx.clone();
        desync(&queue, move || { tx2.send(1).unwrap(); });

        // Then send the value sent via our oneshot using a future
        let tx2 = tx.clone();
        let future = scheduler.after(&queue, future_rx,
            move |val| val.map(move |val| { tx2.send(val).unwrap(); 4 }));

        // Then send '3'
        let tx2 = tx.clone();
        desync(&queue, move || { tx2.send(3).unwrap(); });

        // '1' should be available, but we should otherwise be blocked on the future
        assert!(rx.recv().unwrap() == 1);
        assert!(rx.recv_timeout(Duration::from_millis(100)).is_err());

        // Send '2' to the future
        future_tx.send(2).unwrap();

        executor::block_on(async {
            // Future should resolve to 4
            assert!(future.await.unwrap() == Ok(4));

            // Should receive the '2' from the future, then 3
            assert!(rx.recv_timeout(Duration::from_millis(100)).unwrap() == 2);
            assert!(rx.recv().unwrap() == 3);
        });
    }, 500);
}

#[test]
fn future_waits_for_us() {
    timeout(|| {
        use futures::executor;

        // We use a oneshot as our future, and a mpsc channel to track progress
        let (tx, rx)                = channel();
        let (future_tx, future_rx)  = oneshot::channel();

        let scheduler   = scheduler();
        let queue       = queue();

        // Start by sending '1' from an async
        let tx2 = tx.clone();
        desync(&queue, move || { thread::sleep(Duration::from_millis(100)); tx2.send(1).unwrap(); });

        // Then send the value sent via our oneshot using a future
        let tx2 = tx.clone();
        let future = scheduler.after(&queue, future_rx,
            move |val| val.map(move |val| { tx2.send(val).unwrap(); 4 }));

        // Then send '3'
        let tx2 = tx.clone();
        desync(&queue, move || { tx2.send(3).unwrap(); });

        // Send '2' to the future
        future_tx.send(2).unwrap();

        executor::block_on(async {
            // Future should resolve to 4
            assert!(future.await.unwrap() == Ok(4));

            // '1' should be available first
            assert!(rx.recv().unwrap() == 1);

            // Should receive the '2' from the future, then 3
            assert!(rx.recv_timeout(Duration::from_millis(100)).unwrap() == 2);
            assert!(rx.recv().unwrap() == 3);
        });
    }, 500);
}
<commit_msg>Add a test that should test out our new future (it's failing but seems to not be actually getting far enough?)<commit_after>use desync::scheduler::*;

use super::timeout::*;

use std::thread;
use std::time::*;
use std::sync::mpsc::*;

use futures::channel::oneshot;

#[test]
fn schedule_future() {
    timeout(|| {
        use futures::executor;

        let queue       = queue();
        let future      = future(&queue, move || async {
            thread::sleep(Duration::from_millis(100));
            42
        });

        executor::block_on(async {
            assert!(future.await.unwrap() == 42);
        });
    }, 500);
}

#[test]
fn schedule_future_with_no_scheduler_threads() {
    timeout(|| {
        use futures::executor;

        let scheduler   = Scheduler::new();

        // Even with 0 threads, futures should still run (by draining on the current thread as for sync actions)
        scheduler.set_max_threads(0);
        scheduler.despawn_threads_if_overloaded();

        let queue       = queue();
        let future      = scheduler.future(&queue, move || async {
            thread::sleep(Duration::from_millis(100));
            42
        });

        executor::block_on(async {
            assert!(future.await.unwrap() == 42);
        });
    }, 500);
}

#[test]
fn wake_future_with_no_scheduler_threads() {
    timeout(|| {
        use futures::executor;

        let (tx, rx)    = oneshot::channel::<i32>();
        let scheduler   = Scheduler::new();

        // Even with 0 threads, futures should still run (by draining on the current thread as for sync actions)
        scheduler.set_max_threads(0);
        scheduler.despawn_threads_if_overloaded();

        // Schedule a future that will block until we send a value
        let queue       = queue();
        let future      = scheduler.future(&queue, move || async {
            rx.await.expect("Receive result")
        });

        // Schedule a thread that will send a value
        thread::spawn(move || {
            // Wait for a bit before sending the result so the future should block
            thread::sleep(Duration::from_millis(100));

            tx.send(42).expect("Send")
        });

        executor::block_on(async {
            assert!(future.await.expect("result") == 42);
        });
    }, 500);
}

#[test]
fn wait_for_future() {
    timeout(|| {
        use futures::executor;

        // We use a oneshot as our future, and a mpsc channel to track progress
        let (tx, rx)                = channel();
        let (future_tx, future_rx)  = oneshot::channel();

        let scheduler   = scheduler();
        let queue       = queue();

        // Start by sending '1' from an async
        let tx2 = tx.clone();
        desync(&queue, move || { tx2.send(1).unwrap(); });

        // Then send the value sent via our oneshot using a future
        let tx2 = tx.clone();
        let future = scheduler.after(&queue, future_rx,
            move |val| val.map(move |val| { tx2.send(val).unwrap(); 4 }));

        // Then send '3'
        let tx2 = tx.clone();
        desync(&queue, move || { tx2.send(3).unwrap(); });

        // '1' should be available, but we should otherwise be blocked on the future
        assert!(rx.recv().unwrap() == 1);
        assert!(rx.recv_timeout(Duration::from_millis(100)).is_err());

        // Send '2' to the future
        future_tx.send(2).unwrap();

        executor::block_on(async {
            // Future should resolve to 4
            assert!(future.await.unwrap() == Ok(4));

            // Should receive the '2' from the future, then 3
            assert!(rx.recv_timeout(Duration::from_millis(100)).unwrap() == 2);
            assert!(rx.recv().unwrap() == 3);
        });
    }, 500);
}

#[test]
fn future_waits_for_us() {
    timeout(|| {
        use futures::executor;

        // We use a oneshot as our future, and a mpsc channel to track progress
        let (tx, rx)                = channel();
        let (future_tx, future_rx)  = oneshot::channel();

        let scheduler   = scheduler();
        let queue       = queue();

        // Start by sending '1' from an async
        let tx2 = tx.clone();
        desync(&queue, move || { thread::sleep(Duration::from_millis(100)); tx2.send(1).unwrap(); });

        // Then send the value sent via our oneshot using a future
        let tx2 = tx.clone();
        let future = scheduler.after(&queue, future_rx,
            move |val| val.map(move |val| { tx2.send(val).unwrap(); 4 }));

        // Then send '3'
        let tx2 = tx.clone();
        desync(&queue, move || { tx2.send(3).unwrap(); });

        // Send '2' to the future
        future_tx.send(2).unwrap();

        executor::block_on(async {
            // Future should resolve to 4
            assert!(future.await.unwrap() == Ok(4));

            // '1' should be available first
            assert!(rx.recv().unwrap() == 1);

            // Should receive the '2' from the future, then 3
            assert!(rx.recv_timeout(Duration::from_millis(100)).unwrap() == 2);
            assert!(rx.recv().unwrap() == 3);
        });
    }, 500);
}
<|endoftext|>


<commit_before>use orbtk::prelude::*;
use orbtk::theme::DEFAULT_THEME_CSS;

use std::cell::Cell;

static DARK_EXT: &'static str = include_str!("../res/calculator-dark.css");

#[cfg(feature = "light-theme")]
static LIGHT_EXT: &'static str = include_str!("../res/calculator-light.css");

#[cfg(not(feature = "light-theme"))]
fn get_theme() -> ThemeValue {
    ThemeValue::create_from_css(DEFAULT_THEME_CSS)
        .extension_css(DARK_EXT)
        .build()
}

#[cfg(feature = "light-theme")]
fn get_theme() -> ThemeValue {
    ThemeValue::create()
        .extension_css(DARK_EXT)
        .extension_css(LIGHT_EXT)
        .build()
}

#[derive(Debug, Copy, Clone)]
enum Action {
    Digit(char),
    Operator(char),
}

#[derive(Default)]
pub struct MainViewState {
    input: RefCell<String>,
    operator: Cell<Option<char>>,
    left_side: Cell<Option<f64>>,
    right_side: Cell<Option<f64>>,
    action: Cell<Option<Action>>,
}

impl MainViewState {
    fn action(&self, action: impl Into<Option<Action>>) {
        self.action.set(action.into());
    }

    fn calculate(&self, context: &mut Context) {
        let mut result = 0.0;
        if let Some(operator) = self.operator.get() {
            if let Some(left_side) = self.left_side.get() {
                if let Some(right_side) = self.right_side.get() {
                    match operator {
                        '+' => {
                            result = left_side + right_side;
                        }
                        '-' => {
                            result = left_side - right_side;
                        }
                        '*' => {
                            result = left_side * right_side;
                        }
                        '/' => {
                            result = left_side / right_side;
                        }
                        _ => {}
                    }
                }
            }
        }

        *context.widget().get_mut::<String16>("text") = String16::from(result.to_string());
        self.left_side.set(Some(result));
        self.right_side.set(None);
    }
}

impl State for MainViewState {
    fn update(&self, context: &mut Context) {
        if let Some(action) = self.action.get() {
            match action {
                Action::Digit(digit) => {
                    self.input.borrow_mut().push(digit);
                    context
                        .child_by_id("input")
                        .unwrap()
                        .get_mut::<String16>("text")
                        .push(digit);
                }
                Action::Operator(operator) => match operator {
                    'C' => {
                        self.input.borrow_mut().clear();
                        self.left_side.set(None);
                        self.operator.set(None);
                        self.right_side.set(None);
                        context.widget().get_mut::<String16>("text").clear();
                        context
                            .child_by_id("input")
                            .unwrap()
                            .get_mut::<String16>("text")
                            .clear()
                    }
                    '=' => {
                        self.right_side
                            .set(Some(self.input.borrow().parse().unwrap_or(0.0)));
                        self.calculate(context);
                        self.input.borrow_mut().clear();
                        self.left_side.set(None);
                        self.operator.set(None);
                        self.right_side.set(None);
                        context
                            .child_by_id("input")
                            .unwrap()
                            .get_mut::<String16>("text")
                            .clear()
                    }
                    _ => {
                        if self.input.borrow().is_empty() {
                            return;
                        }
                        if self.left_side.get().is_none() {
                            self.left_side
                                .set(Some(self.input.borrow().parse().unwrap_or(0.0)));
                        } else {
                            self.right_side
                                .set(Some(self.input.borrow().parse().unwrap_or(0.0)));
                            self.calculate(context);
                        }

                        context
                            .child_by_id("input")
                            .unwrap()
                            .get_mut::<String16>("text")
                            .push(operator);
                        self.input.borrow_mut().clear();
                        self.operator.set(Some(operator));
                    }
                },
            }

            self.action.set(None);
        }
    }
}

fn get_button_selector(primary: bool) -> Selector {
    let selector = Selector::from("button");

    if primary {
        selector.class("primary")
    } else {
        selector
    }
}

fn generate_digit_button(
    context: &mut BuildContext,
    state: &Rc<MainViewState>,
    sight: char,
    primary: bool,
    column: usize,
    column_span: usize,
    row: usize,
) -> Entity {
    let state = state.clone();

    Button::create()
        .min_size(48.0, 48.0)
        .text(sight.to_string())
        .selector(get_button_selector(primary))
        .on_click(move |_| -> bool {
            state.action(Action::Digit(sight));
            true
        })
        .attach(Grid::column(column))
        .attach(Grid::row(row))
        .attach(Grid::column_span(column_span))
        .build(context)
}

fn generate_operation_button(
    context: &mut BuildContext,
    state: &Rc<MainViewState>,
    sight: char,
    primary: bool,
    column: usize,
    column_span: usize,
    row: usize,
) -> Entity {
    let state = state.clone();
    Button::create()
        .min_size(48.0, 48.0)
        .text(sight.to_string())
        .selector(get_button_selector(primary).class("square"))
        .on_click(move |_| -> bool {
            state.action(Action::Operator(sight));
            true
        })
        .attach(Grid::column(column))
        .attach(Grid::column_span(column_span))
        .attach(Grid::row(row))
        .build(context)
}

widget!(MainView<MainViewState> {
    text: String16
});

impl Template for MainView {
    fn template(self, id: Entity, context: &mut BuildContext) -> Self {
        let state = self.clone_state();

        self.name("MainView")
            .width(212.0)
            .height(336.0)
            .text("")
            .child(
                Grid::create()
                    .rows(Rows::create().row(72.0).row("*").build())
                    .child(
                        Container::create()
                            .padding(8.0)
                            .selector(Selector::from("container").class("header"))
                            .attach(Grid::row(0))
                            .child(
                                Grid::create()
                                    .child(
                                        ScrollViewer::create()
                                            .scroll_viewer_mode(("custom", "disabled"))
                                            .child(
                                                TextBlock::create()
                                                    .width(0.0)
                                                    .height(14.0)
                                                    .text("")
                                                    .selector(
                                                        Selector::from("text-block").id("input"),
                                                    )
                                                    .vertical_alignment("start")
                                                    .build(context),
                                            )
                                            .build(context),
                                    )
                                    .child(
                                        TextBlock::create()
                                            .selector(Selector::from("text-block"))
                                            .text(id)
                                            .vertical_alignment("end")
                                            .horizontal_alignment("end")
                                            .build(context),
                                    )
                                    .build(context),
                            )
                            .build(context),
                    )
                    .child(
                        Container::create()
                            .selector(Selector::from("container").class("content"))
                            .padding(8.0)
                            .attach(Grid::row(1))
                            .child(
                                Grid::create()
                                    .columns(
                                        Columns::create()
                                            .column(48.0)
                                            .column(4.0)
                                            .column(48.0)
                                            .column(4.0)
                                            .column(48.0)
                                            .column(4.0)
                                            .column(48.0)
                                            .build(),
                                    )
                                    .rows(
                                        Rows::create()
                                            .row(48.0)
                                            .row(4.0)
                                            .row(48.0)
                                            .row(4.0)
                                            .row(48.0)
                                            .row(4.0)
                                            .row(48.0)
                                            .row(4.0)
                                            .row(48.0)
                                            .build(),
                                    )
                                    // row 0
                                    .child(generate_operation_button(
                                        context, &state, 'C', false, 0, 5, 0,
                                    ))
                                    .child(generate_operation_button(
                                        context, &state, '/', true, 6, 3, 0,
                                    ))
                                    // row 2
                                    .child(generate_digit_button(
                                        context, &state, '7', false, 0, 1, 2,
                                    ))
                                    .child(generate_digit_button(
                                        context, &state, '8', false, 2, 1, 2,
                                    ))
                                    .child(generate_digit_button(
                                        context, &state, '9', false, 4, 1, 2,
                                    ))
                                    .child(generate_operation_button(
                                        context, &state, '*', true, 6, 1, 2,
                                    ))
                                    // row 4
                                    .child(generate_digit_button(
                                        context, &state, '4', false, 0, 1, 4,
                                    ))
                                    .child(generate_digit_button(
                                        context, &state, '5', false, 2, 1, 4,
                                    ))
                                    .child(generate_digit_button(
                                        context, &state, '6', false, 4, 1, 4,
                                    ))
                                    .child(generate_operation_button(
                                        context, &state, '-', true, 6, 1, 4,
                                    ))
                                    // row 6
                                    .child(generate_digit_button(
                                        context, &state, '1', false, 0, 1, 6,
                                    ))
                                    .child(generate_digit_button(
                                        context, &state, '2', false, 2, 1, 6,
                                    ))
                                    .child(generate_digit_button(
                                        context, &state, '3', false, 4, 1, 6,
                                    ))
                                    .child(generate_operation_button(
                                        context, &state, '+', true, 6, 1, 6,
                                    ))
                                    // row 8
                                    .child(generate_digit_button(
                                        context, &state, '0', false, 0, 3, 8,
                                    ))
                                    .child(generate_digit_button(
                                        context, &state, '.', false, 4, 1, 8,
                                    ))
                                    .child(generate_operation_button(
                                        context, &state, '=', true, 6, 1, 8,
                                    ))
                                    .build(context),
                            )
                            .build(context),
                    )
                    .build(context),
            )
    }
}

fn main() {
    Application::new()
        .window(|ctx| {
            Window::create()
                .title("OrbTk - Calculator example")
                .position((100.0, 100.0))
                .size(212.0, 336.0)
                .theme(get_theme())
                .child(MainView::create().build(ctx))
                .build(ctx)
        })
        .run();
}
<commit_msg>Small code improvement.<commit_after>use orbtk::prelude::*;
use orbtk::theme::DEFAULT_THEME_CSS;

use std::cell::Cell;

static DARK_EXT: &'static str = include_str!("../res/calculator-dark.css");

#[cfg(feature = "light-theme")]
static LIGHT_EXT: &'static str = include_str!("../res/calculator-light.css");

#[cfg(not(feature = "light-theme"))]
fn get_theme() -> ThemeValue {
    ThemeValue::create_from_css(DEFAULT_THEME_CSS)
        .extension_css(DARK_EXT)
        .build()
}

#[cfg(feature = "light-theme")]
fn get_theme() -> ThemeValue {
    ThemeValue::create()
        .extension_css(DARK_EXT)
        .extension_css(LIGHT_EXT)
        .build()
}

#[derive(Debug, Copy, Clone)]
enum Action {
    Digit(char),
    Operator(char),
}

#[derive(Default)]
pub struct MainViewState {
    input: RefCell<String>,
    operator: Cell<Option<char>>,
    left_side: Cell<Option<f64>>,
    right_side: Cell<Option<f64>>,
    action: Cell<Option<Action>>,
}

impl MainViewState {
    fn action(&self, action: impl Into<Option<Action>>) {
        self.action.set(action.into());
    }

    fn calculate(&self, context: &mut Context) {
        let mut result = 0.0;
        if let Some(operator) = self.operator.get() {
            if let Some(left_side) = self.left_side.get() {
                if let Some(right_side) = self.right_side.get() {
                    match operator {
                        '+' => {
                            result = left_side + right_side;
                        }
                        '-' => {
                            result = left_side - right_side;
                        }
                        '*' => {
                            result = left_side * right_side;
                        }
                        '/' => {
                            result = left_side / right_side;
                        }
                        _ => {}
                    }
                }
            }
        }

        context.widget().set("text", String16::from(result.to_string()));
        self.left_side.set(Some(result));
        self.right_side.set(None);
    }
}

impl State for MainViewState {
    fn update(&self, context: &mut Context) {
        if let Some(action) = self.action.get() {
            match action {
                Action::Digit(digit) => {
                    self.input.borrow_mut().push(digit);
                    context
                        .child_by_id("input")
                        .unwrap()
                        .get_mut::<String16>("text")
                        .push(digit);
                }
                Action::Operator(operator) => match operator {
                    'C' => {
                        self.input.borrow_mut().clear();
                        self.left_side.set(None);
                        self.operator.set(None);
                        self.right_side.set(None);
                        context.widget().get_mut::<String16>("text").clear();
                        context
                            .child_by_id("input")
                            .unwrap()
                            .get_mut::<String16>("text")
                            .clear()
                    }
                    '=' => {
                        self.right_side
                            .set(Some(self.input.borrow().parse().unwrap_or(0.0)));
                        self.calculate(context);
                        self.input.borrow_mut().clear();
                        self.left_side.set(None);
                        self.operator.set(None);
                        self.right_side.set(None);
                        context
                            .child_by_id("input")
                            .unwrap()
                            .get_mut::<String16>("text")
                            .clear()
                    }
                    _ => {
                        if self.input.borrow().is_empty() {
                            return;
                        }
                        if self.left_side.get().is_none() {
                            self.left_side
                                .set(Some(self.input.borrow().parse().unwrap_or(0.0)));
                        } else {
                            self.right_side
                                .set(Some(self.input.borrow().parse().unwrap_or(0.0)));
                            self.calculate(context);
                        }

                        context
                            .child_by_id("input")
                            .unwrap()
                            .get_mut::<String16>("text")
                            .push(operator);
                        self.input.borrow_mut().clear();
                        self.operator.set(Some(operator));
                    }
                },
            }

            self.action.set(None);
        }
    }
}

fn get_button_selector(primary: bool) -> Selector {
    let selector = Selector::from("button");

    if primary {
        selector.class("primary")
    } else {
        selector
    }
}

fn generate_digit_button(
    context: &mut BuildContext,
    state: &Rc<MainViewState>,
    sight: char,
    primary: bool,
    column: usize,
    column_span: usize,
    row: usize,
) -> Entity {
    let state = state.clone();

    Button::create()
        .min_size(48.0, 48.0)
        .text(sight.to_string())
        .selector(get_button_selector(primary))
        .on_click(move |_| -> bool {
            state.action(Action::Digit(sight));
            true
        })
        .attach(Grid::column(column))
        .attach(Grid::row(row))
        .attach(Grid::column_span(column_span))
        .build(context)
}

fn generate_operation_button(
    context: &mut BuildContext,
    state: &Rc<MainViewState>,
    sight: char,
    primary: bool,
    column: usize,
    column_span: usize,
    row: usize,
) -> Entity {
    let state = state.clone();
    Button::create()
        .min_size(48.0, 48.0)
        .text(sight.to_string())
        .selector(get_button_selector(primary).class("square"))
        .on_click(move |_| -> bool {
            state.action(Action::Operator(sight));
            true
        })
        .attach(Grid::column(column))
        .attach(Grid::column_span(column_span))
        .attach(Grid::row(row))
        .build(context)
}

widget!(MainView<MainViewState> {
    text: String16
});

impl Template for MainView {
    fn template(self, id: Entity, context: &mut BuildContext) -> Self {
        let state = self.clone_state();

        self.name("MainView")
            .width(212.0)
            .height(336.0)
            .text("")
            .child(
                Grid::create()
                    .rows(Rows::create().row(72.0).row("*").build())
                    .child(
                        Container::create()
                            .padding(8.0)
                            .selector(Selector::from("container").class("header"))
                            .attach(Grid::row(0))
                            .child(
                                Grid::create()
                                    .child(
                                        ScrollViewer::create()
                                            .scroll_viewer_mode(("custom", "disabled"))
                                            .child(
                                                TextBlock::create()
                                                    .width(0.0)
                                                    .height(14.0)
                                                    .text("")
                                                    .selector(
                                                        Selector::from("text-block").id("input"),
                                                    )
                                                    .vertical_alignment("start")
                                                    .build(context),
                                            )
                                            .build(context),
                                    )
                                    .child(
                                        TextBlock::create()
                                            .selector(Selector::from("text-block"))
                                            .text(id)
                                            .vertical_alignment("end")
                                            .horizontal_alignment("end")
                                            .build(context),
                                    )
                                    .build(context),
                            )
                            .build(context),
                    )
                    .child(
                        Container::create()
                            .selector(Selector::from("container").class("content"))
                            .padding(8.0)
                            .attach(Grid::row(1))
                            .child(
                                Grid::create()
                                    .columns(
                                        Columns::create()
                                            .column(48.0)
                                            .column(4.0)
                                            .column(48.0)
                                            .column(4.0)
                                            .column(48.0)
                                            .column(4.0)
                                            .column(48.0)
                                            .build(),
                                    )
                                    .rows(
                                        Rows::create()
                                            .row(48.0)
                                            .row(4.0)
                                            .row(48.0)
                                            .row(4.0)
                                            .row(48.0)
                                            .row(4.0)
                                            .row(48.0)
                                            .row(4.0)
                                            .row(48.0)
                                            .build(),
                                    )
                                    // row 0
                                    .child(generate_operation_button(
                                        context, &state, 'C', false, 0, 5, 0,
                                    ))
                                    .child(generate_operation_button(
                                        context, &state, '/', true, 6, 3, 0,
                                    ))
                                    // row 2
                                    .child(generate_digit_button(
                                        context, &state, '7', false, 0, 1, 2,
                                    ))
                                    .child(generate_digit_button(
                                        context, &state, '8', false, 2, 1, 2,
                                    ))
                                    .child(generate_digit_button(
                                        context, &state, '9', false, 4, 1, 2,
                                    ))
                                    .child(generate_operation_button(
                                        context, &state, '*', true, 6, 1, 2,
                                    ))
                                    // row 4
                                    .child(generate_digit_button(
                                        context, &state, '4', false, 0, 1, 4,
                                    ))
                                    .child(generate_digit_button(
                                        context, &state, '5', false, 2, 1, 4,
                                    ))
                                    .child(generate_digit_button(
                                        context, &state, '6', false, 4, 1, 4,
                                    ))
                                    .child(generate_operation_button(
                                        context, &state, '-', true, 6, 1, 4,
                                    ))
                                    // row 6
                                    .child(generate_digit_button(
                                        context, &state, '1', false, 0, 1, 6,
                                    ))
                                    .child(generate_digit_button(
                                        context, &state, '2', false, 2, 1, 6,
                                    ))
                                    .child(generate_digit_button(
                                        context, &state, '3', false, 4, 1, 6,
                                    ))
                                    .child(generate_operation_button(
                                        context, &state, '+', true, 6, 1, 6,
                                    ))
                                    // row 8
                                    .child(generate_digit_button(
                                        context, &state, '0', false, 0, 3, 8,
                                    ))
                                    .child(generate_digit_button(
                                        context, &state, '.', false, 4, 1, 8,
                                    ))
                                    .child(generate_operation_button(
                                        context, &state, '=', true, 6, 1, 8,
                                    ))
                                    .build(context),
                            )
                            .build(context),
                    )
                    .build(context),
            )
    }
}

fn main() {
    Application::new()
        .window(|ctx| {
            Window::create()
                .title("OrbTk - Calculator example")
                .position((100.0, 100.0))
                .size(212.0, 336.0)
                .theme(get_theme())
                .child(MainView::create().build(ctx))
                .build(ctx)
        })
        .run();
}
<|endoftext|>


<commit_before>use std::fmt;
use std::fmt::{Display, Debug, Formatter};
use std::str::FromStr;

#[derive(Debug, Clone, Copy, Eq, PartialEq)]
pub struct Posn {
    pub offset: u32,
    pub line: u32,
    pub column: u32
}

impl Posn {
    pub fn origin() -> Posn {
        Posn {
            offset: 0,
            line: 0,
            column: 0
        }
    }
}

#[derive(Debug, Clone, Copy, Eq, PartialEq)]
pub struct Span {
    pub start: Posn,
    pub end: Posn
}

pub trait Track {
    fn location(&self) -> Option;
    fn track(&self, other: U) -> Tracked {
        Tracked {
            location: self.location(),
            value: other
        }
    }
}

impl Track for Posn {
    fn location(&self) -> Option {
        Some(Span {
            start: *self,
            end: *self
        })
    }
}

impl Track for Span {
    fn location(&self) -> Option {
        Some(*self)
    }
}

impl<T> Track for Option<T>
  where T: Track
{
    fn location(&self) -> Option {
        match self {
            &Some(ref x) => x.location(),
            &None        => None
        }
    }
}

#[derive(PartialEq, Eq)]
pub struct Tracked<T> {
    pub location: Option,
    pub value: T
}

impl<T: Debug> Debug for Tracked<T> {
    fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
        fmt.debug_struct("Tracked")
            .field("value", &self.value)
            .finish()
    }
}

impl<T: Display> Display for Tracked<T> {
    fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
        self.value.fmt(fmt)
    }
}

impl<T: FromStr> FromStr for Tracked<T> {
    type Err = ();

    fn from_str(s: &str) -> Result<Tracked<T>, ()> {
        match T::from_str(s) {
            Ok(v)  => Ok(v.tracked(None)),
            Err(_) => Err(())
        }
    }
}

pub trait IntoTracked {
    fn tracked(self, Option) -> Tracked<Self>;
    //fn tracked<T: Track>(self, T) -> Tracked<Self>;
}

impl<T> IntoTracked for T {
    fn tracked(self, location: Option) -> Tracked<T> {
        Tracked { value: self, location: location }
    }
    // fn tracked(self, track: U) -> Tracked<T> {
    //     Tracked { value: self, location: track.location() }
    // }
}

pub trait Untrack {
    fn untrack(&mut self);
}

impl<T> Untrack for Tracked<T>
  where T: Untrack
{
    fn untrack(&mut self) {
        self.location = None;
        self.value.untrack();
    }
}

impl<T> Untrack for Box<T>
  where T: Untrack
{
    fn untrack(&mut self) {
        (**self).untrack();
    }
}

impl<T> Untrack for Option<T>
  where T: Untrack
{
    fn untrack(&mut self) {
        match *self {
            Some(ref mut x) => { x.untrack(); }
            None => { }
        }
    }
}

impl<T> Untrack for Vec<T>
  where T: Untrack
{
    fn untrack(&mut self) {
        for x in self {
            x.untrack();
        }
    }
}

impl<T> Tracked<T> {
    pub fn map(self, op: F) -> Tracked
      where F: FnOnce(T) -> U
    {
        let Tracked { location, value } = self;
        Tracked { location: location, value: op(value) }
    }

    pub fn map_self(self, op: F) -> Tracked
      where F: FnOnce(Tracked<T>) -> U
    {
        let location = self.location;
        Tracked { location: location, value: op(self) }

    }
}

impl<T> Track for Tracked<T> {
    fn location(&self) -> Option {
        self.location
    }
}

pub fn span<T, U>(left: &T, right: &U) -> Option
  where T: Track,
        U: Track
{
    match (left.location(), right.location()) {
        (Some(l), Some(r)) => Some(Span { start: l.start, end: r.end }),
        _ => None
    }
}
<commit_msg>IntoTracked needs a Sized bound to return Self<commit_after>use std::fmt;
use std::fmt::{Display, Debug, Formatter};
use std::str::FromStr;

#[derive(Debug, Clone, Copy, Eq, PartialEq)]
pub struct Posn {
    pub offset: u32,
    pub line: u32,
    pub column: u32
}

impl Posn {
    pub fn origin() -> Posn {
        Posn {
            offset: 0,
            line: 0,
            column: 0
        }
    }
}

#[derive(Debug, Clone, Copy, Eq, PartialEq)]
pub struct Span {
    pub start: Posn,
    pub end: Posn
}

pub trait Track {
    fn location(&self) -> Option;
    fn track(&self, other: U) -> Tracked {
        Tracked {
            location: self.location(),
            value: other
        }
    }
}

impl Track for Posn {
    fn location(&self) -> Option {
        Some(Span {
            start: *self,
            end: *self
        })
    }
}

impl Track for Span {
    fn location(&self) -> Option {
        Some(*self)
    }
}

impl<T> Track for Option<T>
  where T: Track
{
    fn location(&self) -> Option {
        match self {
            &Some(ref x) => x.location(),
            &None        => None
        }
    }
}

#[derive(PartialEq, Eq)]
pub struct Tracked<T> {
    pub location: Option,
    pub value: T
}

impl<T: Debug> Debug for Tracked<T> {
    fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
        fmt.debug_struct("Tracked")
            .field("value", &self.value)
            .finish()
    }
}

impl<T: Display> Display for Tracked<T> {
    fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
        self.value.fmt(fmt)
    }
}

impl<T: FromStr> FromStr for Tracked<T> {
    type Err = ();

    fn from_str(s: &str) -> Result<Tracked<T>, ()> {
        match T::from_str(s) {
            Ok(v)  => Ok(v.tracked(None)),
            Err(_) => Err(())
        }
    }
}

pub trait IntoTracked: Sized {
    fn tracked(self, location: Option) -> Tracked<Self>;
    //fn tracked<T: Track>(self, T) -> Tracked<Self>;
}

impl<T> IntoTracked for T {
    fn tracked(self, location: Option) -> Tracked<T> {
        Tracked { value: self, location: location }
    }
    // fn tracked(self, track: U) -> Tracked<T> {
    //     Tracked { value: self, location: track.location() }
    // }
}

pub trait Untrack {
    fn untrack(&mut self);
}

impl<T> Untrack for Tracked<T>
  where T: Untrack
{
    fn untrack(&mut self) {
        self.location = None;
        self.value.untrack();
    }
}

impl<T> Untrack for Box<T>
  where T: Untrack
{
    fn untrack(&mut self) {
        (**self).untrack();
    }
}

impl<T> Untrack for Option<T>
  where T: Untrack
{
    fn untrack(&mut self) {
        match *self {
            Some(ref mut x) => { x.untrack(); }
            None => { }
        }
    }
}

impl<T> Untrack for Vec<T>
  where T: Untrack
{
    fn untrack(&mut self) {
        for x in self {
            x.untrack();
        }
    }
}

impl<T> Tracked<T> {
    pub fn map(self, op: F) -> Tracked
      where F: FnOnce(T) -> U
    {
        let Tracked { location, value } = self;
        Tracked { location: location, value: op(value) }
    }

    pub fn map_self(self, op: F) -> Tracked
      where F: FnOnce(Tracked<T>) -> U
    {
        let location = self.location;
        Tracked { location: location, value: op(self) }

    }
}

impl<T> Track for Tracked<T> {
    fn location(&self) -> Option {
        self.location
    }
}

pub fn span<T, U>(left: &T, right: &U) -> Option
  where T: Track,
        U: Track
{
    match (left.location(), right.location()) {
        (Some(l), Some(r)) => Some(Span { start: l.start, end: r.end }),
        _ => None
    }
}
<|endoftext|>