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

//! Tidy check to ensure that unstable features are all in order
//!
//! This check will ensure properties like:
//!
//! * All stability attributes look reasonably well formed
//! * The set of library features is disjoint from the set of language features
//! * Library features have at most one stability level
//! * Library features have at most one `since` value
//! * All unstable lang features have tests to ensure they are actually unstable

use std::collections::HashMap;
use std::fmt;
use std::fs::File;
use std::io::prelude::*;
use std::path::Path;

#[derive(Debug, PartialEq, Clone)]
pub enum Status {
    Stable,
    Removed,
    Unstable,
}

impl fmt::Display for Status {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let as_str = match *self {
            Status::Stable => "stable",
            Status::Unstable => "unstable",
            Status::Removed => "removed",
        };
        fmt::Display::fmt(as_str, f)
    }
}

#[derive(Debug, Clone)]
pub struct Feature {
    pub level: Status,
    pub since: String,
    pub has_gate_test: bool,
    pub tracking_issue: Option<u32>,
}

impl Feature {
    fn check_match(&self, other: &Feature)-> Result<(), Vec<&'static str>> {
        let mut mismatches = Vec::new();
        if self.level != other.level {
            mismatches.push("stability level");
        }
        if self.level == Status::Stable || other.level == Status::Stable {
            // As long as a feature is unstable, the since field tracks
            // when the given part of the feature has been implemented.
            // Mismatches are tolerable as features evolve and functionality
            // gets added.
            // Once a feature is stable, the since field tracks the first version
            // it was part of the stable distribution, and mismatches are disallowed.
            if self.since != other.since {
                mismatches.push("since");
            }
        }
        if self.tracking_issue != other.tracking_issue {
            mismatches.push("tracking issue");
        }
        if mismatches.is_empty() {
            Ok(())
        } else {
            Err(mismatches)
        }
    }
}

pub type Features = HashMap<String, Feature>;

pub fn check(path: &Path, bad: &mut bool, quiet: bool) {
    let mut features = collect_lang_features(path);
    assert!(!features.is_empty());

    let lib_features = get_and_check_lib_features(path, bad, &features);
    assert!(!lib_features.is_empty());

    let mut contents = String::new();

    super::walk_many(&[&path.join("test/compile-fail"),
                       &path.join("test/compile-fail-fulldeps"),
                       &path.join("test/parse-fail"),],
                     &mut |path| super::filter_dirs(path),
                     &mut |file| {
        let filename = file.file_name().unwrap().to_string_lossy();
        if !filename.ends_with(".rs") || filename == "features.rs" ||
           filename == "diagnostic_list.rs" {
            return;
        }

        let filen_underscore = filename.replace("-","_").replace(".rs","");
        let filename_is_gate_test = test_filen_gate(&filen_underscore, &mut features);

        contents.truncate(0);
        t!(t!(File::open(&file), &file).read_to_string(&mut contents));

        for (i, line) in contents.lines().enumerate() {
            let mut err = |msg: &str| {
                tidy_error!(bad, "{}:{}: {}", file.display(), i + 1, msg);
            };

            let gate_test_str = "gate-test-";

            if !line.contains(gate_test_str) {
                continue;
            }

            let feature_name = match line.find(gate_test_str) {
                Some(i) => {
                    &line[i+gate_test_str.len()..line[i+1..].find(' ').unwrap_or(line.len())]
                },
                None => continue,
            };
            match features.get_mut(feature_name) {
                Some(f) => {
                    if filename_is_gate_test {
                        err(&format!("The file is already marked as gate test \
                                      through its name, no need for a \
                                      'gate-test-{}' comment",
                                     feature_name));
                    }
                    f.has_gate_test = true;
                }
                None => {
                    err(&format!("gate-test test found referencing a nonexistent feature '{}'",
                                 feature_name));
                }
            }
        }
    });

    // Only check the number of lang features.
    // Obligatory testing for library features is dumb.
    let gate_untested = features.iter()
                                .filter(|&(_, f)| f.level == Status::Unstable)
                                .filter(|&(_, f)| !f.has_gate_test)
                                .collect::<Vec<_>>();

    for &(name, _) in gate_untested.iter() {
        println!("Expected a gate test for the feature '{}'.", name);
        println!("Hint: create a file named 'feature-gate-{}.rs' in the compile-fail\
                \n      test suite, with its failures due to missing usage of\
                \n      #![feature({})].", name, name);
        println!("Hint: If you already have such a test and don't want to rename it,\
                \n      you can also add a // gate-test-{} line to the test file.",
                 name);
    }

    if gate_untested.len() > 0 {
        tidy_error!(bad, "Found {} features without a gate test.", gate_untested.len());
    }

    if *bad {
        return;
    }
    if quiet {
        println!("* {} features", features.len());
        return;
    }

    let mut lines = Vec::new();
    for (name, feature) in features.iter() {
        lines.push(format!("{:<32} {:<8} {:<12} {:<8}",
                           name,
                           "lang",
                           feature.level,
                           feature.since));
    }
    for (name, feature) in lib_features {
        lines.push(format!("{:<32} {:<8} {:<12} {:<8}",
                           name,
                           "lib",
                           feature.level,
                           feature.since));
    }

    lines.sort();
    for line in lines {
        println!("* {}", line);
    }
}

fn find_attr_val<'a>(line: &'a str, attr: &str) -> Option<&'a str> {
    line.find(attr)
        .and_then(|i| line[i..].find('"').map(|j| i + j + 1))
        .and_then(|i| line[i..].find('"').map(|j| (i, i + j)))
        .map(|(i, j)| &line[i..j])
}

fn test_filen_gate(filen_underscore: &str, features: &mut Features) -> bool {
    if filen_underscore.starts_with("feature_gate") {
        for (n, f) in features.iter_mut() {
            if filen_underscore == format!("feature_gate_{}", n) {
                f.has_gate_test = true;
                return true;
            }
        }
    }
    return false;
}

pub fn collect_lang_features(base_src_path: &Path) -> Features {
    let mut contents = String::new();
    let path = base_src_path.join("libsyntax/feature_gate.rs");
    t!(t!(File::open(path)).read_to_string(&mut contents));

    contents.lines()
        .filter_map(|line| {
            let mut parts = line.trim().split(",");
            let level = match parts.next().map(|l| l.trim().trim_left_matches('(')) {
                Some("active") => Status::Unstable,
                Some("removed") => Status::Removed,
                Some("accepted") => Status::Stable,
                _ => return None,
            };
            let name = parts.next().unwrap().trim();
            let since = parts.next().unwrap().trim().trim_matches('"');
            let issue_str = parts.next().unwrap().trim();
            let tracking_issue = if issue_str.starts_with("None") {
                None
            } else {
                let s = issue_str.split("(").nth(1).unwrap().split(")").nth(0).unwrap();
                Some(s.parse().unwrap())
            };
            Some((name.to_owned(),
                Feature {
                    level,
                    since: since.to_owned(),
                    has_gate_test: false,
                    tracking_issue,
                }))
        })
        .collect()
}

pub fn collect_lib_features(base_src_path: &Path) -> Features {
    let mut lib_features = Features::new();

    // This library feature is defined in the `compiler_builtins` crate, which
    // has been moved out-of-tree. Now it can no longer be auto-discovered by
    // `tidy`, because we need to filter out its (submodule) directory. Manually
    // add it to the set of known library features so we can still generate docs.
    lib_features.insert("compiler_builtins_lib".to_owned(), Feature {
        level: Status::Unstable,
        since: "".to_owned(),
        has_gate_test: false,
        tracking_issue: None,
    });

    map_lib_features(base_src_path,
                     &mut |res, _, _| {
        match res {
            Ok((name, feature)) => {
                if lib_features.get(name).is_some() {
                    return;
                }
                lib_features.insert(name.to_owned(), feature);
            },
            Err(_) => (),
        }
    });
   lib_features
}

fn get_and_check_lib_features(base_src_path: &Path,
                              bad: &mut bool,
                              lang_features: &Features) -> Features {
    let mut lib_features = Features::new();
    map_lib_features(base_src_path,
                     &mut |res, file, line| {
            match res {
                Ok((name, f)) => {
                    let mut check_features = |f: &Feature, list: &Features, display: &str| {
                        if let Some(ref s) = list.get(name) {
                            if let Err(m) = (&f).check_match(s) {
                                tidy_error!(bad,
                                            "{}:{}: mismatches to {} in: {:?}",
                                            file.display(),
                                            line,
                                            display,
                                            &m);
                            }
                        }
                    };
                    check_features(&f, &lang_features, "corresponding lang feature");
                    check_features(&f, &lib_features, "previous");
                    lib_features.insert(name.to_owned(), f);
                },
                Err(msg) => {
                    tidy_error!(bad, "{}:{}: {}", file.display(), line, msg);
                },
            }

    });
    lib_features
}

fn map_lib_features(base_src_path: &Path,
                    mf: &mut FnMut(Result<(&str, Feature), &str>, &Path, usize)) {
    let mut contents = String::new();
    super::walk(base_src_path,
                &mut |path| super::filter_dirs(path) || path.ends_with("src/test"),
                &mut |file| {
        let filename = file.file_name().unwrap().to_string_lossy();
        if !filename.ends_with(".rs") || filename == "features.rs" ||
           filename == "diagnostic_list.rs" {
            return;
        }

        contents.truncate(0);
        t!(t!(File::open(&file), &file).read_to_string(&mut contents));

        let mut becoming_feature: Option<(String, Feature)> = None;
        for (i, line) in contents.lines().enumerate() {
            macro_rules! err {
                ($msg:expr) => {{
                    mf(Err($msg), file, i + 1);
                    continue;
                }};
            };
            if let Some((ref name, ref mut f)) = becoming_feature {
                if f.tracking_issue.is_none() {
                    f.tracking_issue = find_attr_val(line, "issue")
                    .map(|s| s.parse().unwrap());
                }
                if line.ends_with("]") {
                    mf(Ok((name, f.clone())), file, i + 1);
                } else if !line.ends_with(",") && !line.ends_with("\\") {
                    // We need to bail here because we might have missed the
                    // end of a stability attribute above because the "]"
                    // might not have been at the end of the line.
                    // We could then get into the very unfortunate situation that
                    // we continue parsing the file assuming the current stability
                    // attribute has not ended, and ignoring possible feature
                    // attributes in the process.
                    err!("malformed stability attribute");
                } else {
                    continue;
                }
            }
            becoming_feature = None;
            let level = if line.contains("[unstable(") {
                Status::Unstable
            } else if line.contains("[stable(") {
                Status::Stable
            } else {
                continue;
            };
            let feature_name = match find_attr_val(line, "feature") {
                Some(name) => name,
                None => err!("malformed stability attribute"),
            };
            let since = match find_attr_val(line, "since") {
                Some(name) => name,
                None if level == Status::Stable => {
                    err!("malformed stability attribute");
                }
                None => "None",
            };
            let tracking_issue = find_attr_val(line, "issue").map(|s| s.parse().unwrap());

            let feature = Feature {
                level,
                since: since.to_owned(),
                has_gate_test: false,
                tracking_issue,
            };
            if line.contains("]") {
                mf(Ok((feature_name, feature)), file, i + 1);
            } else {
                becoming_feature = Some((feature_name.to_owned(), feature));
            }
        }
    });
}
<commit_msg>Rollup merge of #45671 - est31:master, r=alexcrichton<commit_after>// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! Tidy check to ensure that unstable features are all in order
//!
//! This check will ensure properties like:
//!
//! * All stability attributes look reasonably well formed
//! * The set of library features is disjoint from the set of language features
//! * Library features have at most one stability level
//! * Library features have at most one `since` value
//! * All unstable lang features have tests to ensure they are actually unstable

use std::collections::HashMap;
use std::fmt;
use std::fs::File;
use std::io::prelude::*;
use std::path::Path;

#[derive(Debug, PartialEq, Clone)]
pub enum Status {
    Stable,
    Removed,
    Unstable,
}

impl fmt::Display for Status {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let as_str = match *self {
            Status::Stable => "stable",
            Status::Unstable => "unstable",
            Status::Removed => "removed",
        };
        fmt::Display::fmt(as_str, f)
    }
}

#[derive(Debug, Clone)]
pub struct Feature {
    pub level: Status,
    pub since: String,
    pub has_gate_test: bool,
    pub tracking_issue: Option<u32>,
}

impl Feature {
    fn check_match(&self, other: &Feature)-> Result<(), Vec<&'static str>> {
        let mut mismatches = Vec::new();
        if self.level != other.level {
            mismatches.push("stability level");
        }
        if self.level == Status::Stable || other.level == Status::Stable {
            // As long as a feature is unstable, the since field tracks
            // when the given part of the feature has been implemented.
            // Mismatches are tolerable as features evolve and functionality
            // gets added.
            // Once a feature is stable, the since field tracks the first version
            // it was part of the stable distribution, and mismatches are disallowed.
            if self.since != other.since {
                mismatches.push("since");
            }
        }
        if self.tracking_issue != other.tracking_issue {
            mismatches.push("tracking issue");
        }
        if mismatches.is_empty() {
            Ok(())
        } else {
            Err(mismatches)
        }
    }
}

pub type Features = HashMap<String, Feature>;

pub fn check(path: &Path, bad: &mut bool, quiet: bool) {
    let mut features = collect_lang_features(path);
    assert!(!features.is_empty());

    let lib_features = get_and_check_lib_features(path, bad, &features);
    assert!(!lib_features.is_empty());

    let mut contents = String::new();

    super::walk_many(&[&path.join("test/compile-fail"),
                       &path.join("test/compile-fail-fulldeps"),
                       &path.join("test/parse-fail"),],
                     &mut |path| super::filter_dirs(path),
                     &mut |file| {
        let filename = file.file_name().unwrap().to_string_lossy();
        if !filename.ends_with(".rs") || filename == "features.rs" ||
           filename == "diagnostic_list.rs" {
            return;
        }

        let filen_underscore = filename.replace("-","_").replace(".rs","");
        let filename_is_gate_test = test_filen_gate(&filen_underscore, &mut features);

        contents.truncate(0);
        t!(t!(File::open(&file), &file).read_to_string(&mut contents));

        for (i, line) in contents.lines().enumerate() {
            let mut err = |msg: &str| {
                tidy_error!(bad, "{}:{}: {}", file.display(), i + 1, msg);
            };

            let gate_test_str = "gate-test-";

            if !line.contains(gate_test_str) {
                continue;
            }

            let feature_name = match line.find(gate_test_str) {
                Some(i) => {
                    &line[i+gate_test_str.len()..line[i+1..].find(' ').unwrap_or(line.len())]
                },
                None => continue,
            };
            match features.get_mut(feature_name) {
                Some(f) => {
                    if filename_is_gate_test {
                        err(&format!("The file is already marked as gate test \
                                      through its name, no need for a \
                                      'gate-test-{}' comment",
                                     feature_name));
                    }
                    f.has_gate_test = true;
                }
                None => {
                    err(&format!("gate-test test found referencing a nonexistent feature '{}'",
                                 feature_name));
                }
            }
        }
    });

    // Only check the number of lang features.
    // Obligatory testing for library features is dumb.
    let gate_untested = features.iter()
                                .filter(|&(_, f)| f.level == Status::Unstable)
                                .filter(|&(_, f)| !f.has_gate_test)
                                .collect::<Vec<_>>();

    for &(name, _) in gate_untested.iter() {
        println!("Expected a gate test for the feature '{}'.", name);
        println!("Hint: create a file named 'feature-gate-{}.rs' in the compile-fail\
                \n      test suite, with its failures due to missing usage of\
                \n      #![feature({})].", name, name);
        println!("Hint: If you already have such a test and don't want to rename it,\
                \n      you can also add a // gate-test-{} line to the test file.",
                 name);
    }

    if gate_untested.len() > 0 {
        tidy_error!(bad, "Found {} features without a gate test.", gate_untested.len());
    }

    if *bad {
        return;
    }
    if quiet {
        println!("* {} features", features.len());
        return;
    }

    let mut lines = Vec::new();
    for (name, feature) in features.iter() {
        lines.push(format!("{:<32} {:<8} {:<12} {:<8}",
                           name,
                           "lang",
                           feature.level,
                           feature.since));
    }
    for (name, feature) in lib_features {
        lines.push(format!("{:<32} {:<8} {:<12} {:<8}",
                           name,
                           "lib",
                           feature.level,
                           feature.since));
    }

    lines.sort();
    for line in lines {
        println!("* {}", line);
    }
}

fn find_attr_val<'a>(line: &'a str, attr: &str) -> Option<&'a str> {
    line.find(attr)
        .and_then(|i| line[i..].find('"').map(|j| i + j + 1))
        .and_then(|i| line[i..].find('"').map(|j| (i, i + j)))
        .map(|(i, j)| &line[i..j])
}

fn test_filen_gate(filen_underscore: &str, features: &mut Features) -> bool {
    if filen_underscore.starts_with("feature_gate") {
        for (n, f) in features.iter_mut() {
            if filen_underscore == format!("feature_gate_{}", n) {
                f.has_gate_test = true;
                return true;
            }
        }
    }
    return false;
}

pub fn collect_lang_features(base_src_path: &Path) -> Features {
    let mut contents = String::new();
    let path = base_src_path.join("libsyntax/feature_gate.rs");
    t!(t!(File::open(path)).read_to_string(&mut contents));

    contents.lines()
        .filter_map(|line| {
            let mut parts = line.trim().split(",");
            let level = match parts.next().map(|l| l.trim().trim_left_matches('(')) {
                Some("active") => Status::Unstable,
                Some("removed") => Status::Removed,
                Some("accepted") => Status::Stable,
                _ => return None,
            };
            let name = parts.next().unwrap().trim();
            let since = parts.next().unwrap().trim().trim_matches('"');
            let issue_str = parts.next().unwrap().trim();
            let tracking_issue = if issue_str.starts_with("None") {
                None
            } else {
                let s = issue_str.split("(").nth(1).unwrap().split(")").nth(0).unwrap();
                Some(s.parse().unwrap())
            };
            Some((name.to_owned(),
                Feature {
                    level,
                    since: since.to_owned(),
                    has_gate_test: false,
                    tracking_issue,
                }))
        })
        .collect()
}

pub fn collect_lib_features(base_src_path: &Path) -> Features {
    let mut lib_features = Features::new();

    // This library feature is defined in the `compiler_builtins` crate, which
    // has been moved out-of-tree. Now it can no longer be auto-discovered by
    // `tidy`, because we need to filter out its (submodule) directory. Manually
    // add it to the set of known library features so we can still generate docs.
    lib_features.insert("compiler_builtins_lib".to_owned(), Feature {
        level: Status::Unstable,
        since: "".to_owned(),
        has_gate_test: false,
        tracking_issue: None,
    });

    map_lib_features(base_src_path,
                     &mut |res, _, _| {
        match res {
            Ok((name, feature)) => {
                if lib_features.get(name).is_some() {
                    return;
                }
                lib_features.insert(name.to_owned(), feature);
            },
            Err(_) => (),
        }
    });
   lib_features
}

fn get_and_check_lib_features(base_src_path: &Path,
                              bad: &mut bool,
                              lang_features: &Features) -> Features {
    let mut lib_features = Features::new();
    map_lib_features(base_src_path,
                     &mut |res, file, line| {
            match res {
                Ok((name, f)) => {
                    let mut check_features = |f: &Feature, list: &Features, display: &str| {
                        if let Some(ref s) = list.get(name) {
                            if let Err(m) = (&f).check_match(s) {
                                tidy_error!(bad,
                                            "{}:{}: mismatches to {} in: {:?}",
                                            file.display(),
                                            line,
                                            display,
                                            &m);
                            }
                        }
                    };
                    check_features(&f, &lang_features, "corresponding lang feature");
                    check_features(&f, &lib_features, "previous");
                    lib_features.insert(name.to_owned(), f);
                },
                Err(msg) => {
                    tidy_error!(bad, "{}:{}: {}", file.display(), line, msg);
                },
            }

    });
    lib_features
}

fn map_lib_features(base_src_path: &Path,
                    mf: &mut FnMut(Result<(&str, Feature), &str>, &Path, usize)) {
    let mut contents = String::new();
    super::walk(base_src_path,
                &mut |path| super::filter_dirs(path) || path.ends_with("src/test"),
                &mut |file| {
        let filename = file.file_name().unwrap().to_string_lossy();
        if !filename.ends_with(".rs") || filename == "features.rs" ||
           filename == "diagnostic_list.rs" {
            return;
        }

        contents.truncate(0);
        t!(t!(File::open(&file), &file).read_to_string(&mut contents));

        let mut becoming_feature: Option<(String, Feature)> = None;
        for (i, line) in contents.lines().enumerate() {
            macro_rules! err {
                ($msg:expr) => {{
                    mf(Err($msg), file, i + 1);
                    continue;
                }};
            };
            if let Some((ref name, ref mut f)) = becoming_feature {
                if f.tracking_issue.is_none() {
                    f.tracking_issue = find_attr_val(line, "issue")
                    .map(|s| s.parse().unwrap());
                }
                if line.ends_with("]") {
                    mf(Ok((name, f.clone())), file, i + 1);
                } else if !line.ends_with(",") && !line.ends_with("\\") {
                    // We need to bail here because we might have missed the
                    // end of a stability attribute above because the "]"
                    // might not have been at the end of the line.
                    // We could then get into the very unfortunate situation that
                    // we continue parsing the file assuming the current stability
                    // attribute has not ended, and ignoring possible feature
                    // attributes in the process.
                    err!("malformed stability attribute");
                } else {
                    continue;
                }
            }
            becoming_feature = None;
            if line.contains("rustc_const_unstable(") {
                // const fn features are handled specially
                let feature_name = match find_attr_val(line, "feature") {
                    Some(name) => name,
                    None => err!("malformed stability attribute"),
                };
                let feature = Feature {
                    level: Status::Unstable,
                    since: "None".to_owned(),
                    has_gate_test: false,
                    // Whether there is a common tracking issue
                    // for these feature gates remains an open question
                    // https://github.com/rust-lang/rust/issues/24111#issuecomment-340283184
                    // But we take 24111 otherwise they will be shown as
                    // "internal to the compiler" which they are not.
                    tracking_issue: Some(24111),
                };
                mf(Ok((feature_name, feature)), file, i + 1);
                continue;
            }
            let level = if line.contains("[unstable(") {
                Status::Unstable
            } else if line.contains("[stable(") {
                Status::Stable
            } else {
                continue;
            };
            let feature_name = match find_attr_val(line, "feature") {
                Some(name) => name,
                None => err!("malformed stability attribute"),
            };
            let since = match find_attr_val(line, "since") {
                Some(name) => name,
                None if level == Status::Stable => {
                    err!("malformed stability attribute");
                }
                None => "None",
            };
            let tracking_issue = find_attr_val(line, "issue").map(|s| s.parse().unwrap());

            let feature = Feature {
                level,
                since: since.to_owned(),
                has_gate_test: false,
                tracking_issue,
            };
            if line.contains("]") {
                mf(Ok((feature_name, feature)), file, i + 1);
            } else {
                becoming_feature = Some((feature_name.to_owned(), feature));
            }
        }
    });
}
<|endoftext|>


<commit_before><commit_msg>Rename tcp feature tu tcp_extras<commit_after><|endoftext|>


<commit_before><commit_msg>error<commit_after><|endoftext|>


<commit_before><commit_msg>thing<commit_after><|endoftext|>


<commit_before>struct Point {
    x: f64,
    y: f64,
}

// Implementation block, all `Point` methods go in here
impl Point {
    // This is a static method
    // Static methods don't need to be called by an instance
    // These methods are generally used as constructors
    fn origin() -> Point {
        Point { x: 0.0, y: 0.0 }
    }

    // Another static method, that takes two arguments
    fn new(x: f64, y: f64) -> Point {
        Point { x: x, y: y }
    }
}

struct Rectangle {
    p1: Point,
    p2: Point,
}

impl Rectangle {
    // This is an instance method
    // `&self` is sugar for `self: &Self`, where `Self` is the type of the
    // caller object. In this case `Self` = `Rectangle`
    fn area(&self) -> f64 {
        // `self` gives access to the struct fields via the dot operator
        let Point { x: x1, y: y1 } = self.p1;
        let Point { x: x2, y: y2 } = self.p2;

        // `abs` is a `f64` method that returns the absolute value of the
        // caller
        ((x1 - x2) * (y1 - y2)).abs()
    }

    fn perimeter(&self) -> f64 {
        let Point { x: x1, y: y1 } = self.p1;
        let Point { x: x2, y: y2 } = self.p2;

        2.0 * (x1 - x2).abs() + 2.0 * (y1 - y2).abs()
    }

    // This method requires the caller object to be mutable
    // `&mut self` desugars to `self: &mut Self`
    fn translate(&mut self, x: f64, y: f64) {
        self.p1.x += x;
        self.p2.x += x;

        self.p1.y += y;
        self.p2.y += y;
    }
}

// `Pair` owns resources: two heap allocated integers
struct Pair(Box<i32>, Box<i32>);

impl Pair {
    // This method "consumes" the resources of the caller object
    // `self` desugars to `self: Self`
    fn destroy(self) {
        // Destructure `self`
        let Pair(first, second) = self;

        println!("Destroying Pair({}, {})", first, second);

        // `first` and `second` go out of scope and get freed
    }
}

fn main() {
    let rectangle = Rectangle {
        // Static methods are called using double colons
        p1: Point::origin(),
        p2: Point::new(3.0, 4.0),
    };

    // Instance method are called using the dot operator
    // Note that the first argument `&self` is implicitly passed, i.e.
    // `rectangle.perimeter()` === `perimeter(&rectangle)`
    println!("Rectangle perimeter: {}", rectangle.perimeter());
    println!("Rectangle area: {}", rectangle.area());

    let mut square = Rectangle {
        p1: Point::origin(),
        p2: Point::new(1.0, 1.0),
    };

    // Error! `rectangle` is immutable, but this method requires a mutable
    // object
    //rectangle.translate(1.0, 0.0);
    // TODO ^ Try uncommenting this line

    // Ok, mutable object can call mutable methods
    square.translate(1.0, 1.0);

    let pair = Pair(Box::new(1), Box::new(2));

    pair.destroy();

    // Error! Previous `destroy` call "consumed" `pair`
    //pair.destroy();
    // TODO ^ Try uncommenting this line
}
<commit_msg>Update methods perimeter expression<commit_after>struct Point {
    x: f64,
    y: f64,
}

// Implementation block, all `Point` methods go in here
impl Point {
    // This is a static method
    // Static methods don't need to be called by an instance
    // These methods are generally used as constructors
    fn origin() -> Point {
        Point { x: 0.0, y: 0.0 }
    }

    // Another static method, that takes two arguments
    fn new(x: f64, y: f64) -> Point {
        Point { x: x, y: y }
    }
}

struct Rectangle {
    p1: Point,
    p2: Point,
}

impl Rectangle {
    // This is an instance method
    // `&self` is sugar for `self: &Self`, where `Self` is the type of the
    // caller object. In this case `Self` = `Rectangle`
    fn area(&self) -> f64 {
        // `self` gives access to the struct fields via the dot operator
        let Point { x: x1, y: y1 } = self.p1;
        let Point { x: x2, y: y2 } = self.p2;

        // `abs` is a `f64` method that returns the absolute value of the
        // caller
        ((x1 - x2) * (y1 - y2)).abs()
    }

    fn perimeter(&self) -> f64 {
        let Point { x: x1, y: y1 } = self.p1;
        let Point { x: x2, y: y2 } = self.p2;

        2.0 * ((x1 - x2).abs() + (y1 - y2).abs())
    }

    // This method requires the caller object to be mutable
    // `&mut self` desugars to `self: &mut Self`
    fn translate(&mut self, x: f64, y: f64) {
        self.p1.x += x;
        self.p2.x += x;

        self.p1.y += y;
        self.p2.y += y;
    }
}

// `Pair` owns resources: two heap allocated integers
struct Pair(Box<i32>, Box<i32>);

impl Pair {
    // This method "consumes" the resources of the caller object
    // `self` desugars to `self: Self`
    fn destroy(self) {
        // Destructure `self`
        let Pair(first, second) = self;

        println!("Destroying Pair({}, {})", first, second);

        // `first` and `second` go out of scope and get freed
    }
}

fn main() {
    let rectangle = Rectangle {
        // Static methods are called using double colons
        p1: Point::origin(),
        p2: Point::new(3.0, 4.0),
    };

    // Instance method are called using the dot operator
    // Note that the first argument `&self` is implicitly passed, i.e.
    // `rectangle.perimeter()` === `perimeter(&rectangle)`
    println!("Rectangle perimeter: {}", rectangle.perimeter());
    println!("Rectangle area: {}", rectangle.area());

    let mut square = Rectangle {
        p1: Point::origin(),
        p2: Point::new(1.0, 1.0),
    };

    // Error! `rectangle` is immutable, but this method requires a mutable
    // object
    //rectangle.translate(1.0, 0.0);
    // TODO ^ Try uncommenting this line

    // Ok, mutable object can call mutable methods
    square.translate(1.0, 1.0);

    let pair = Pair(Box::new(1), Box::new(2));

    pair.destroy();

    // Error! Previous `destroy` call "consumed" `pair`
    //pair.destroy();
    // TODO ^ Try uncommenting this line
}
<|endoftext|>


<commit_before><commit_msg>Update main.rs<commit_after><|endoftext|>


<commit_before><commit_msg>Connect to PostgreSQL and create tables<commit_after><|endoftext|>


<commit_before><commit_msg>Added new reset timestamp and enable / disable io port commands<commit_after><|endoftext|>


<commit_before>extern crate rusqlite;

use rusqlite::Connection;

#[derive(Debug)]
struct Person {
    id: i32,
    name: String,
    data: Option<Vec<u8>>
}

fn main() {
    let conn = Connection::open_in_memory().unwrap();

    conn.execute("CREATE TABLE person (
                  id              INTEGER PRIMARY KEY,
                  name            TEXT NOT NULL,
                  data            BLOB
                  )", &[]).unwrap();
    let me = Person {
        id: 0,
        name: "Steven".to_string(),
        data: None
    };
    conn.execute("INSERT INTO person (name, time_created, data)
                  VALUES (?1, ?2, ?3)",
                 &[&me.name, &me.data]).unwrap();

    let mut stmt = conn.prepare("SELECT id, name, time_created, data FROM person").unwrap();
    let person_iter = stmt.query_map(&[], |row| {
        Person {
            id: row.get(0),
            name: row.get(1),
            data: row.get(2)
        }
    }).unwrap();

    for person in person_iter {
        println!("Found person {:?}", person.unwrap());
    }
}<commit_msg>* Removed experiments code from main.rs<commit_after>pub fn main() {
    println!("Implement me!");
}<|endoftext|>


<commit_before><commit_msg>get it all working (roughly)<commit_after><|endoftext|>


<commit_before><commit_msg>:hammer: Fix typo<commit_after><|endoftext|>


<commit_before><commit_msg>Sets the default port to 8080 instead of 80<commit_after><|endoftext|>


<commit_before><commit_msg>stat: almost done<commit_after>#![crate_name = "uu_stat"]

// This file is part of the uutils coreutils package.
//
// (c) Jian Zeng <anonymousknight96@gmail.com>
//
// For the full copyright and license information, please view the LICENSE file
// that was distributed with this source code.
//

extern crate users;

extern crate getopts;
use getopts::Options;

#[macro_use]
mod fsext;
use fsext::*;

#[macro_use]
extern crate uucore;

use std::{fs, iter, cmp};
use std::io::Write;
use std::borrow::Cow;
// use std::error::Error;
use std::os::unix::fs::{FileTypeExt, MetadataExt};

#[cfg(test)]
mod test_stat;

macro_rules! check_bound {
    ($str: ident, $bound:expr, $beg: expr, $end: expr) => (
        if $end >= $bound {
            return Err(format!("‘{}’: invalid directive", &$str[$beg..$end]));
        }

    )
}
macro_rules! fill_string {
    ($str: ident, $c: expr, $cnt: expr) => (
        iter::repeat($c).take($cnt).map(|c| $str.push(c)).all(|_| true)
    )
}

macro_rules! extend_digits {
    ($str: ident, $min: expr) => (
        if $min > $str.len() {
            let mut pad = String::with_capacity($min);
            fill_string!(pad, '0', $min - $str.len());
            pad.push_str($str);
            pad.into()
        } else {
            $str.into()
        }
    )
}

macro_rules! pad_and_print {
    ($result: ident, $str: ident, $left: expr, $width: expr, $padding: expr) => (
        if $str.len() < $width {
            if $left {
                $result.push_str($str.as_ref());
                fill_string!($result, $padding, $width - $str.len());
            } else {
                fill_string!($result, $padding, $width - $str.len());
                $result.push_str($str.as_ref());
            }
        } else {
            $result.push_str($str.as_ref());
        }
        print!("{}", $result);
    )
}
macro_rules! print_adjusted {
    ($str: ident, $left: expr, $width: expr, $padding: expr) => (
        let field_width = cmp::max($width, $str.len());
        let mut result = String::with_capacity(field_width);
        pad_and_print!(result, $str, $left, field_width, $padding);
    );
    ($str: ident, $left: expr, $need_prefix: expr, $prefix: expr, $width: expr, $padding: expr) => (
        let mut field_width = cmp::max($width, $str.len());
        let mut result = String::with_capacity(field_width + $prefix.len());
        if $need_prefix {
            result.push_str($prefix);
            field_width -= $prefix.len();
        }
        pad_and_print!(result, $str, $left, field_width, $padding);
    )
}

static NAME: &'static str = "stat";
static VERSION: &'static str = env!("CARGO_PKG_VERSION");

pub const F_ALTER: u8 = 0b1;
pub const F_ZERO: u8 = 0b10;
pub const F_LEFT: u8 = 0b100;
pub const F_SPACE: u8 = 0b1000;
pub const F_SIGN: u8 = 0b10000;
// unused at present
pub const F_GROUP: u8 = 0b100000;

#[derive(Debug, PartialEq)]
pub enum OutputType {
    Str,
    Integer,
    Unsigned,
    UnsignedHex,
    UnsignedOct,
    Unknown,
}

#[derive(Debug, PartialEq)]
pub enum Token {
    Char(char),
    Directive {
        flag: u8,
        width: usize,
        precision: i32,
        format: char,
    },
}

trait ScanNum {
    /// Return (F, offset)
    fn scan_num<F>(&self) -> Option<(F, usize)> where F: std::str::FromStr;
}

impl ScanNum for str {
    fn scan_num<F>(&self) -> Option<(F, usize)>
        where F: std::str::FromStr
    {
        let mut chars = self.chars();
        let mut i = 0;
        while let Some(c) = chars.next() {
            match c {
                '-' | '+' | '0'...'9' => i += 1,
                _ => break,
            }
        }
        if i > 0 {
            F::from_str(&self[..i]).ok().map(|x| (x, i))
        } else {
            None
        }
    }
}

pub struct Stater {
    follow: bool,
    showfs: bool,
    from_user: bool,
    files: Vec<String>,
    default_tokens: Vec<Token>,
    default_dev_tokens: Vec<Token>,
}

fn print_it(arg: &str, otype: OutputType, flag: u8, width: usize, precision: i32) {

    // If the precision is given as just '.', the precision is taken to be zero.
    // A negative precision is taken as if the precision were omitted.
    // This gives the minimum number of digits to appear for d, i, o, u, x, and X conversions,
    // the maximum number of characters to be printed from a string for s and S conversions.

    // #
    // The value should be converted to an "alternate form".
    // For o conversions, the first character of the output string  is made  zero  (by  prefixing  a 0 if it was not zero already).
    // For x and X conversions, a nonzero result has the string "0x" (or "0X" for X conversions) prepended to it.

    // 0
    // The value should be zero padded.
    // For d, i, o, u, x, X, a, A, e, E, f, F, g, and G conversions, the converted value is padded on the left with zeros rather than blanks.
    // If the 0 and - flags both appear, the 0 flag is ignored.
    // If a precision  is  given with a numeric conversion (d, i, o, u, x, and X), the 0 flag is ignored.
    // For other conversions, the behavior is undefined.

    // -
    // The converted value is to be left adjusted on the field boundary.  (The default is right justification.)
    // The  converted  value  is padded on the right with blanks, rather than on the left with blanks or zeros.
    // A - overrides a 0 if both are given.

    // ' ' (a space)
    // A blank should be left before a positive number (or empty string) produced by a signed conversion.

    // +
    // A sign (+ or -) should always be placed before a number produced by a signed conversion.
    // By default, a sign  is  used only for negative numbers.
    // A + overrides a space if both are used.

    if otype == OutputType::Unknown {
        return print!("?");
    }

    let left_align = has!(flag, F_LEFT);
    let padding_char = if has!(flag, F_ZERO) && !left_align && precision == -1 {
        '0'
    } else {
        ' '
    };

    let has_sign = has!(flag, F_SIGN) || has!(flag, F_SPACE);

    let should_alter = has!(flag, F_ALTER);
    let prefix = match otype {
        OutputType::UnsignedOct => "0",
        OutputType::UnsignedHex => "0x",
        OutputType::Integer => {
            if has!(flag, F_SIGN) {
                "+"
            } else {
                " "
            }
        }
        _ => "",
    };

    match otype {
        OutputType::Str => {
            let limit = cmp::min(precision, arg.len() as i32);
            let s: &str = if limit >= 0 {
                &arg[..limit as usize]
            } else {
                arg
            };
            print_adjusted!(s, left_align, width, ' ');
        }
        OutputType::Integer => {
            let min_digits = cmp::max(precision, arg.len() as i32) as usize;
            let extended: Cow<str> = extend_digits!(arg, min_digits);
            print_adjusted!(extended, left_align, has_sign, prefix, width, padding_char);
        }
        OutputType::Unsigned => {
            let min_digits = cmp::max(precision, arg.len() as i32) as usize;
            let extended: Cow<str> = extend_digits!(arg, min_digits);
            print_adjusted!(extended, left_align, width, padding_char);
        }
        OutputType::UnsignedOct => {
            let min_digits = cmp::max(precision, arg.len() as i32) as usize;
            let extended: Cow<str> = extend_digits!(arg, min_digits);
            print_adjusted!(extended,
                            left_align,
                            should_alter,
                            prefix,
                            width,
                            padding_char);
        }
        OutputType::UnsignedHex => {
            let min_digits = cmp::max(precision, arg.len() as i32) as usize;
            let extended: Cow<str> = extend_digits!(arg, min_digits);
            print_adjusted!(extended,
                            left_align,
                            should_alter,
                            prefix,
                            width,
                            padding_char);
        }
        _ => unreachable!(),
    }
}

impl Stater {
    pub fn generate_tokens(fmtstr: &str, use_printf: bool) -> Result<Vec<Token>, String> {

        let mut tokens = Vec::new();
        let bound = fmtstr.len();
        let chars = fmtstr.chars().collect::<Vec<char>>();

        let mut i = 0_usize;
        while i < bound {

            match chars[i] {
                '%' => {
                    let old = i;

                    i += 1;
                    if i >= bound {
                        tokens.push(Token::Char('%'));
                        continue;
                    }
                    if chars[i] == '%' {
                        tokens.push(Token::Char('%'));
                        i += 1;
                        continue;
                    }

                    let mut flag: u8 = 0;

                    while i < bound {
                        match chars[i] {
                            '#' => flag |= F_ALTER,
                            '0' => flag |= F_ZERO,
                            '-' => flag |= F_LEFT,
                            ' ' => flag |= F_SPACE,
                            '+' => flag |= F_SIGN,
                            //'\'' => flag |= F_GROUP,
                            '\'' => unimplemented!(),
                            'I' => unimplemented!(),
                            _ => break,
                        }
                        i += 1;
                    }
                    check_bound!(fmtstr, bound, old, i);

                    let mut width = 0_usize;
                    let mut precision = -1_i32;
                    let mut j = i;

                    match fmtstr[j..].scan_num::<usize>() {
                        Some((field_width, offset)) => {
                            width = field_width;
                            j += offset;
                        }
                        None => (),
                    }
                    check_bound!(fmtstr, bound, old, j);

                    if chars[j] == '.' {
                        j += 1;
                        check_bound!(fmtstr, bound, old, j);

                        match fmtstr[j..].scan_num::<i32>() {
                            Some((prec, offset)) => {
                                if prec >= 0 {
                                    precision = prec;
                                }
                                j += offset;
                            }
                            None => precision = 0,
                        }
                        check_bound!(fmtstr, bound, old, j);
                    }

                    i = j;
                    tokens.push(Token::Directive {
                        width: width,
                        flag: flag,
                        precision: precision,
                        format: chars[i],
                    })

                }
                '\\' => {
                    if !use_printf {
                        tokens.push(Token::Char('\\'));
                    } else {
                        i += 1;
                        if i >= bound {
                            show_warning!("backslash at end of format");
                            tokens.push(Token::Char('\\'));
                            continue;
                        }
                        match chars[i] {
                            'x' => {
                                // TODO: parse character
                            }
                            '0'...'7' => {
                                // TODO: parse character
                            }
                            '"' => tokens.push(Token::Char('"')),
                            '\\' => tokens.push(Token::Char('\\')),
                            'a' => tokens.push(Token::Char('\x07')),
                            'b' => tokens.push(Token::Char('\x08')),
                            'e' => tokens.push(Token::Char('\x1B')),
                            'f' => tokens.push(Token::Char('\x0c')),
                            'n' => tokens.push(Token::Char('\n')),
                            'r' => tokens.push(Token::Char('\r')),
                            'v' => tokens.push(Token::Char('\x0b')),
                            c => {
                                show_warning!("unrecognized escape '\\{}'", c);
                                tokens.push(Token::Char(c));
                            }
                        }
                    }
                }

                c => tokens.push(Token::Char(c)),
            }
            i += 1;
        }
        if !use_printf && !fmtstr.ends_with('\n') {
            tokens.push(Token::Char('\n'));
        }
        Ok(tokens)
    }

    fn new(matches: getopts::Matches) -> Result<Stater, String> {
        let fmtstr = if matches.opt_present("printf") {
            matches.opt_str("printf").expect("Invalid format string")
        } else {
            matches.opt_str("format").unwrap_or("".to_owned())
        };

        let use_printf = matches.opt_present("printf");
        let terse = matches.opt_present("terse");
        let showfs = matches.opt_present("file-system");

        let default_tokens = if fmtstr.is_empty() {
            Stater::generate_tokens(&Stater::default_fmt(showfs, terse, false), use_printf).unwrap()
        } else {
            match Stater::generate_tokens(&fmtstr, use_printf) {
                Ok(ts) => ts,
                Err(e) => return Err(e),
            }
        };
        let default_dev_tokens = Stater::generate_tokens(&Stater::default_fmt(showfs, terse, true),
                                                         use_printf)
                                     .unwrap();

        Ok(Stater {
            follow: matches.opt_present("dereference"),
            showfs: showfs,
            from_user: !fmtstr.is_empty(),
            files: matches.free,
            default_tokens: default_tokens,
            default_dev_tokens: default_dev_tokens,
        })
    }

    fn exec(&self) -> i32 {
        for f in &self.files {
            self.do_stat(f.as_str());
        }
        0
    }

    fn do_stat(&self, file: &str) {

        #[inline]
        fn get_grp_name(gid: u32) -> String {
            if let Some(g) = users::get_group_by_gid(gid) {
                g.name().to_owned()
            } else {
                "UNKNOWN".to_owned()
            }
        }

        #[inline]
        fn get_usr_name(uid: u32) -> String {
            if let Some(g) = users::get_user_by_uid(uid) {
                g.name().to_owned()
            } else {
                "UNKNOWN".to_owned()
            }
        }

        if !self.showfs {
            let result = if self.follow {
                fs::metadata(file)
            } else {
                fs::symlink_metadata(file)
            };
            match result {
                Ok(meta) => {
                    let ftype = meta.file_type();
                    let tokens = if self.from_user ||
                                    !(ftype.is_char_device() || ftype.is_block_device()) {
                        &self.default_tokens
                    } else {
                        &self.default_dev_tokens
                    };
                    let is_symlink = ftype.is_symlink();

                    for t in tokens.into_iter() {
                        match t {
                            &Token::Char(c) => print!("{}", c),
                            &Token::Directive { flag, width, precision, format } => {

                                let arg: String;
                                let otype: OutputType;

                                match format {
                                    // unsigned oct
                                    'a' => {
                                        arg = format!("{:o}", 0o7777 & meta.mode());
                                        otype = OutputType::UnsignedOct;
                                    }
                                    // string
                                    'A' => {
                                        arg = pretty_access(meta.mode());
                                        otype = OutputType::Str;
                                    }
                                    // unsigned
                                    'b' => {
                                        arg = format!("{}", meta.blocks());
                                        otype = OutputType::Unsigned;
                                    }

                                    // unsigned
                                    // FIXME: blocksize differs on various platform
                                    // See coreutils/gnulib/lib/stat-size.h ST_NBLOCKSIZE
                                    'B' => {
                                        // the size in bytes of each block reported by %b
                                        arg = format!("{}", 512);
                                        otype = OutputType::Unsigned;
                                    }

                                    // unsigned
                                    'd' => {
                                        arg = format!("{}", meta.dev());
                                        otype = OutputType::Unsigned;
                                    }
                                    // unsigned hex
                                    'D' => {
                                        arg = format!("{:x}", meta.dev());
                                        otype = OutputType::UnsignedHex;
                                    }
                                    // unsigned hex
                                    'f' => {
                                        arg = format!("{:x}", meta.mode());
                                        otype = OutputType::UnsignedHex;
                                    }
                                    // string
                                    'F' => {
                                        arg = pretty_filetype(meta.mode(), meta.len()).to_owned();
                                        otype = OutputType::Str;
                                    }
                                    // unsigned
                                    'g' => {
                                        arg = format!("{}", meta.gid());
                                        otype = OutputType::Unsigned;
                                    }
                                    // string
                                    'G' => {
                                        arg = get_grp_name(meta.gid());
                                        otype = OutputType::Str;
                                    }
                                    // unsigned
                                    'h' => {
                                        arg = format!("{}", meta.nlink());
                                        otype = OutputType::Unsigned;
                                    }
                                    // unsigned
                                    'i' => {
                                        arg = format!("{}", meta.ino());
                                        otype = OutputType::Unsigned;
                                    }

                                    // string
                                    // FIXME:
                                    'm' => {
                                        // mount point
                                        arg = "/".to_owned();
                                        otype = OutputType::Str;
                                    }

                                    // string
                                    'n' => {
                                        arg = file.to_owned();
                                        otype = OutputType::Str;
                                    }
                                    // string
                                    'N' => {
                                        if is_symlink {
                                            arg = format!("'{}' -> '{}'",
                                                          file,
                                                          fs::read_link(file)
                                                              .expect("Invalid symlink")
                                                              .to_string_lossy());
                                        } else {
                                            arg = format!("'{}'", file);
                                        }
                                        otype = OutputType::Str;
                                    }
                                    // unsigned
                                    'o' => {
                                        arg = format!("{}", meta.blksize());
                                        otype = OutputType::Unsigned;
                                    }
                                    // int
                                    's' => {
                                        arg = format!("{}", meta.len());
                                        otype = OutputType::Integer;
                                    }
                                    // unsigned hex
                                    't' => {
                                        arg = format!("{:x}", meta.rdev() >> 8);
                                        otype = OutputType::UnsignedHex;
                                    }
                                    // unsigned hex
                                    'T' => {
                                        arg = format!("{:x}", meta.rdev() & 0xff);
                                        otype = OutputType::UnsignedHex;
                                    }
                                    // unsigned
                                    'u' => {
                                        arg = format!("{}", meta.uid());
                                        otype = OutputType::Unsigned;
                                    }
                                    // string
                                    'U' => {
                                        arg = get_usr_name(meta.uid());
                                        otype = OutputType::Str;
                                    }

                                    // string
                                    // FIXME:
                                    'w' => {
                                        // time of file birth, human-readable; - if unknown
                                        arg = "-".to_owned();
                                        otype = OutputType::Str;
                                    }

                                    // int
                                    // FIXME:
                                    'W' => {
                                        // time of file birth, seconds since Epoch; 0 if unknown
                                        arg = format!("{}", 0);
                                        otype = OutputType::Integer;
                                    }

                                    // string
                                    'x' => {
                                        arg = pretty_time(meta.atime(), meta.atime_nsec());
                                        otype = OutputType::Str;
                                    }
                                    // int
                                    'X' => {
                                        arg = format!("{}", meta.atime());
                                        otype = OutputType::Integer;
                                    }
                                    // string
                                    'y' => {
                                        arg = pretty_time(meta.mtime(), meta.mtime_nsec());
                                        otype = OutputType::Str;
                                    }
                                    // int
                                    'Y' => {
                                        arg = format!("{}", meta.mtime());
                                        otype = OutputType::Str;
                                    }
                                    // string
                                    'z' => {
                                        arg = pretty_time(meta.ctime(), meta.ctime_nsec());
                                        otype = OutputType::Str;
                                    }
                                    // int
                                    'Z' => {
                                        arg = format!("{}", meta.ctime());
                                        otype = OutputType::Integer;
                                    }

                                    _ => {
                                        arg = "?".to_owned();
                                        otype = OutputType::Unknown;
                                    }
                                }
                                print_it(&arg, otype, flag, width, precision);
                            }
                        }
                    }
                }
                Err(e) => {
                    show_info!("cannot stat '{}': {}", file, e);
                    return;
                }
            }
        } else {
            match statfs(file) {
                Ok(data) => {
                    let tokens = &self.default_tokens;

                    for t in tokens.into_iter() {
                        match t {
                            &Token::Char(c) => print!("{}", c),
                            &Token::Directive { flag, width, precision, format } => {

                                let arg: String;
                                let otype: OutputType;
                                match format {
                                    // int
                                    'a' => {
                                        arg = format!("{}", data.f_bavail);
                                        otype = OutputType::Integer;
                                    }
                                    // int
                                    'b' => {
                                        arg = format!("{}", data.f_blocks);
                                        otype = OutputType::Integer;
                                    }
                                    // unsigned
                                    'c' => {
                                        arg = format!("{}", data.f_files);
                                        otype = OutputType::Unsigned;
                                    }
                                    // int
                                    'd' => {
                                        arg = format!("{}", data.f_ffree);
                                        otype = OutputType::Integer;
                                    }
                                    // int
                                    'f' => {
                                        arg = format!("{}", data.f_bfree);
                                        otype = OutputType::Integer;
                                    }
                                    // hex unsigned
                                    'i' => {
                                        arg = format!("{:x}", data.f_fsid);
                                        otype = OutputType::UnsignedHex;
                                    }
                                    // unsigned
                                    'l' => {
                                        arg = format!("{}", data.f_namelen);
                                        otype = OutputType::Unsigned;
                                    }
                                    // string
                                    'n' => {
                                        arg = file.to_owned();
                                        otype = OutputType::Str;
                                    }
                                    // unsigned
                                    's' => {
                                        arg = format!("{}", data.f_bsize);
                                        otype = OutputType::Unsigned;
                                    }
                                    // unsigned
                                    'S' => {
                                        arg = format!("{}", data.f_frsize);
                                        otype = OutputType::Unsigned;
                                    }
                                    // hex unsigned
                                    't' => {
                                        arg = format!("{:x}", data.f_type);
                                        otype = OutputType::UnsignedHex;
                                    }
                                    // string
                                    'T' => {
                                        arg = pretty_fstype(data.f_type).into_owned();
                                        otype = OutputType::Str;
                                    }
                                    _ => {
                                        arg = "?".to_owned();
                                        otype = OutputType::Unknown;
                                    }
                                }

                                print_it(&arg, otype, flag, width, precision);
                            }
                        }
                    }
                }
                Err(e) => {
                    show_info!("cannot stat '{}': {}", file, e);
                    return;
                }
            }
        }
    }

    // taken from coreutils/src/stat.c
    fn default_fmt(showfs: bool, terse: bool, dev: bool) -> String {

        // SELinux related format is *ignored*

        // 36 is taken randomly
        let mut fmtstr = String::with_capacity(36);
        if showfs {
            if terse {
                fmtstr.push_str("%n %i %l %t %s %S %b %f %a %c %d\n");
            } else {
                fmtstr.push_str("  File: \"%n\"\n    ID: %-8i Namelen: %-7l Type: %T\nBlock \
                                 size: %-10s Fundamental block size: %S\nBlocks: Total: %-10b \
                                 Free: %-10f Available: %a\nInodes: Total: %-10c Free: %d\n");
            }
        } else if terse {
            fmtstr.push_str("%n %s %b %f %u %g %D %i %h %t %T %X %Y %Z %W %o\n");
        } else {
            fmtstr.push_str("  File: %N\n  Size: %-10s\tBlocks: %-10b IO Block: %-6o %F\n");
            if dev {
                fmtstr.push_str("Device: %Dh/%dd\tInode: %-10i  Links: %-5h Device type: %t,%T\n");
            } else {
                fmtstr.push_str("Device: %Dh/%dd\tInode: %-10i  Links: %h\n");
            }
            fmtstr.push_str("Access: (%04a/%10.10A)  Uid: (%5u/%8U)   Gid: (%5g/%8G)\n");
            fmtstr.push_str("Access: %x\nModify: %y\nChange: %z\n Birth: %w\n");
        }
        fmtstr
    }
}

pub fn uumain(args: Vec<String>) -> i32 {
    let mut opts = Options::new();

    opts.optflag("h", "help", "display this help and exit");
    opts.optflag("", "version", "output version information and exit");

    opts.optflag("L", "dereference", "follow links");
    opts.optflag("f",
                 "file-system",
                 "display file system status instead of file status");
    opts.optflag("t", "terse", "print the information in terse form");

    // Omit the unused description as they are too long
    opts.optopt("c", "format", "", "FORMAT");
    opts.optopt("", "printf", "", "FORMAT");

    let matches = match opts.parse(&args[1..]) {
        Ok(m) => m,
        Err(f) => {
            disp_err!("{}", f);
            return 1;
        }
    };

    if matches.opt_present("help") {
        return help();
    } else if matches.opt_present("version") {
        return version();
    }

    if matches.free.is_empty() {
        disp_err!("missing operand");
        return 1;
    }

    match Stater::new(matches) {
        // FIXME: Handle error
        Ok(stater) => stater.exec(),
        Err(e) => {
            show_info!("{}", e);
            return 1;
        }
    }
}

fn version() -> i32 {
    println!("{} {}", NAME, VERSION);
    0
}

fn help() -> i32 {
    let msg = format!(r#"Usage: {} [OPTION]... FILE...
Display file or file system status.

Mandatory arguments to long options are mandatory for short options too.
  -L, --dereference     follow links
  -f, --file-system     display file system status instead of file status
  -c  --format=FORMAT   use the specified FORMAT instead of the default;
                          output a newline after each use of FORMAT
      --printf=FORMAT   like --format, but interpret backslash escapes,
                          and do not output a mandatory trailing newline;
                          if you want a newline, include \n in FORMAT
  -t, --terse           print the information in terse form
      --help     display this help and exit
      --version  output version information and exit

The valid format sequences for files (without --file-system):

  %a   access rights in octal (note '#' and '0' printf flags)
  %A   access rights in human readable form
  %b   number of blocks allocated (see %B)
  %B   the size in bytes of each block reported by %b
  %C   SELinux security context string
  %d   device number in decimal
  %D   device number in hex
  %f   raw mode in hex
  %F   file type
  %g   group ID of owner
  %G   group name of owner
  %h   number of hard links
  %i   inode number
  %m   mount point
  %n   file name
  %N   quoted file name with dereference if symbolic link
  %o   optimal I/O transfer size hint
  %s   total size, in bytes
  %t   major device type in hex, for character/block device special files
  %T   minor device type in hex, for character/block device special files
  %u   user ID of owner
  %U   user name of owner
  %w   time of file birth, human-readable; - if unknown
  %W   time of file birth, seconds since Epoch; 0 if unknown
  %x   time of last access, human-readable
  %X   time of last access, seconds since Epoch
  %y   time of last data modification, human-readable
  %Y   time of last data modification, seconds since Epoch
  %z   time of last status change, human-readable
  %Z   time of last status change, seconds since Epoch

Valid format sequences for file systems:

  %a   free blocks available to non-superuser
  %b   total data blocks in file system
  %c   total file nodes in file system
  %d   free file nodes in file system
  %f   free blocks in file system
  %i   file system ID in hex
  %l   maximum length of filenames
  %n   file name
  %s   block size (for faster transfers)
  %S   fundamental block size (for block counts)
  %t   file system type in hex
  %T   file system type in human readable form

NOTE: your shell may have its own version of stat, which usually supersedes
the version described here.  Please refer to your shell's documentation
for details about the options it supports."#,
                      NAME);
    println!("{}", msg);
    0
}
<|endoftext|>


<commit_before><commit_msg>test-json example for Cargo intro<commit_after>// test-json/src/main.rs
extern crate json;

fn main() {
    let mut doc = json::parse(r#"
    {
        "code": 200,
        "success": true,
        "payload": {
            "features": [
                "awesome",
                "easyAPI",
                "lowLearningCurve"
            ]
        }
    }
    "#).expect("parse failed");

    let code = doc["code"].as_u32().unwrap_or(0);
    let success = doc["success"].as_bool().unwrap_or(false);
    let features = &mut doc["payload"]["features"];
    features.push("cargo!").expect("couldn't push");
    for v in features.members() {
        println!("{}",v.as_str().unwrap());
    }

    assert_eq!(code, 200);
    assert_eq!(success, true);

    //~ println!("debug {:?}",doc);
    //~ println!("display {}",doc);
}
<|endoftext|>


<commit_before><commit_msg>Fix doctest<commit_after><|endoftext|>


<commit_before>extern crate clap;
extern crate glob;
#[macro_use] extern crate log;
extern crate serde_json;
extern crate semver;
extern crate toml;
#[macro_use] extern crate version;

extern crate task_hookrs;

extern crate libimagrt;
extern crate libimagstore;
extern crate libimagerror;
extern crate libimagtodo;

use std::process::exit;
use std::process::{Command, Stdio};
use std::io::stdin;
use std::io::BufRead;

use task_hookrs::import::{import_task, import_tasks};

use libimagrt::runtime::Runtime;
use libimagtodo::task::IntoTask;
use libimagerror::trace::trace_error;

mod ui;

use ui::build_ui;
fn main() {
    let name = "imag-todo";
    let version = &version!()[..];
    let about = "Interface with taskwarrior";
    let ui = build_ui(Runtime::get_default_cli_builder(name, version, about));

    let rt = {
        let rt = Runtime::new(ui);
        if rt.is_ok() {
            rt.unwrap()
        } else {
            println!("Could not set up Runtime");
            println!("{:?}", rt.unwrap_err());
            exit(1);
        }
    };

    let scmd = rt.cli().subcommand_name();
    match scmd {
        Some("tw-hook") => tw_hook(&rt),
        Some("exec") => exec(&rt),
        Some("list") => list(&rt),
        _ => unimplemented!(),
    } // end match scmd
} // end main

fn tw_hook(rt: &Runtime) {
    let subcmd = rt.cli().subcommand_matches("tw-hook").unwrap();
    if subcmd.is_present("add") {
        let stdin = stdin();
        let mut stdin = stdin.lock();
        let mut line = String::new();
        match stdin.read_line(&mut line) {
            Ok(_) => { }
            Err(e) => {
                error!("{}", e);
                return;
            }
        };
        if let Ok(ttask) = import_task(&line.as_str()) {
            let uuid = *ttask.uuid();
            println!("{}", match serde_json::ser::to_string(&ttask) {
                Ok(val) => val,
                Err(e) => {
                    error!("{}", e);
                    return;
                }
            });
            match ttask.into_filelockentry(rt.store()) {
                Ok(val) => {
                    println!("Task {} stored in imag", uuid);
                    val
                },
                Err(e) => {
                    trace_error(&e);
                    error!("{}", e);
                    return;
                }
            };
        }
        else {
            error!("No usable input");
            return;
        }
    }
    else if subcmd.is_present("delete") {
        // The used hook is "on-modify". This hook gives two json-objects
        // per usage und wants one (the second one) back.
        let mut counter = 0;
        let stdin = stdin();
        let stdin = stdin.lock();
        if let Ok(ttasks) = import_tasks(stdin) {
            for ttask in ttasks {
                if counter % 2 == 1 {
                    // Only every second task is needed, the first one is the
                    // task before the change, and the second one after
                    // the change. The (maybe modified) second one is
                    // expected by taskwarrior.
                    println!("{}", match serde_json::ser::to_string(&ttask) {
                        Ok(val) => val,
                        Err(e) => {
                            error!("{}", e);
                            return;
                        }
                    });
                    match ttask.status() {
                        &task_hookrs::status::TaskStatus::Deleted => {
                            match libimagtodo::delete::delete(rt.store(), *ttask.uuid()) {
                                Ok(_) => {
                                    println!("Deleted task {}", *ttask.uuid());
                                }
                                Err(e) => {
                                    trace_error(&e);
                                    error!("{}", e);
                                    return;
                                }
                            }
                        }
                        _ => {
                        }
                    } // end match ttask.status()
                } // end if c % 2
                counter += 1;
            } // end for
        } // end if let
        else {
            error!("No usable input");
        }
    }
    else {
        // Should not be possible, as one argument is required via
        // ArgGroup
        unreachable!();
    }
}

fn exec(rt: &Runtime) {
    let subcmd = rt.cli().subcommand_matches("exec").unwrap();
    let mut args = Vec::new();
    if let Some(exec_string) = subcmd.values_of("command") {
        for e in exec_string {
            args.push(e);
        }
        let tw_process = Command::new("task").stdin(Stdio::null()).args(&args).spawn().unwrap_or_else(|e| {
            panic!("failed to execute taskwarrior: {}", e);
        });

        let output = tw_process.wait_with_output().unwrap_or_else(|e| {
            panic!("failed to unwrap output: {}", e);
        });
        let outstring = String::from_utf8(output.stdout).unwrap_or_else(|e| {
            panic!("failed to ececute: {}", e);
        });
        println!("{}", outstring);
    } else {
        panic!("faild to execute: You need to exec --command");
    }
}

fn list(rt: &Runtime) {
    let subcmd = rt.cli().subcommand_matches("list").unwrap();
    let mut args = Vec::new();
    let verbose = subcmd.is_present("verbose");
    let iter = match libimagtodo::read::get_todo_iterator(rt.store()) {
        //let iter = match rt.store().retrieve_for_module("todo/taskwarrior") {
        Err(e) => {
            error!("{}", e);
            return;
        }
        Ok(val) => val,
    };
    for task in iter {
        match task {
            Ok(val) => {
                //let val = libimagtodo::task::Task::new(fle);
                //println!("{:#?}", val.flentry);
                let uuid = match val.flentry.get_header().read("todo.uuid") {
                    Ok(Some(u)) => u,
                    Ok(None) => continue,
                    Err(e) => {
                        error!("{}", e);
                        continue;
                    }
                };
                if verbose {
                    args.clear();
                    args.push(format!("uuid:{}", uuid));
                    args.push(format!("{}", "information"));
                    let tw_process = Command::new("task").stdin(Stdio::null()).args(&args).spawn()
                        .unwrap_or_else(|e| {
                            error!("{}", e);
                            panic!("failed");
                        });
                    let output = tw_process.wait_with_output().unwrap_or_else(|e| {
                        panic!("failed to unwrap output: {}", e);
                    });
                    let outstring = String::from_utf8(output.stdout).unwrap_or_else(|e| {
                        panic!("failed to ececute: {}", e);
                    });
                    println!("{}", outstring);
                }
                else {
                    println!("{}", match uuid {
                        toml::Value::String(s) => s,
                        _ => {
                            error!("Unexpected type for todo.uuid: {}", uuid);
                            continue;
                        },
                    });
                }
            }
            Err(e) => {
                error!("{}", e);
                continue;
            }
        } // end match task
    } // end for
}

<commit_msg>Remove the most ugly parts<commit_after>extern crate clap;
extern crate glob;
#[macro_use] extern crate log;
extern crate serde_json;
extern crate semver;
extern crate toml;
#[macro_use] extern crate version;

extern crate task_hookrs;

extern crate libimagrt;
extern crate libimagstore;
extern crate libimagerror;
extern crate libimagtodo;

use std::process::exit;
use std::process::{Command, Stdio};
use std::io::stdin;
use std::io::BufRead;

use task_hookrs::import::{import_task, import_tasks};

use libimagrt::runtime::Runtime;
use libimagtodo::task::IntoTask;
use libimagerror::trace::trace_error;

mod ui;

use ui::build_ui;
fn main() {
    let name = "imag-todo";
    let version = &version!()[..];
    let about = "Interface with taskwarrior";
    let ui = build_ui(Runtime::get_default_cli_builder(name, version, about));

    let rt = {
        let rt = Runtime::new(ui);
        if rt.is_ok() {
            rt.unwrap()
        } else {
            println!("Could not set up Runtime");
            println!("{:?}", rt.unwrap_err());
            exit(1);
        }
    };

    match rt.cli().subcommand_name() {
        Some("tw-hook") => tw_hook(&rt),
        Some("exec") => exec(&rt),
        Some("list") => list(&rt),
        _ => unimplemented!(),
    } // end match scmd
} // end main

fn tw_hook(rt: &Runtime) {
    let subcmd = rt.cli().subcommand_matches("tw-hook").unwrap();
    if subcmd.is_present("add") {
        let stdin     = stdin();
        let mut stdin = stdin.lock();
        let mut line  = String::new();

        if let Err(e) = stdin.read_line(&mut line) {
            trace_error(&e);
            exit(1);
        };

        if let Ok(ttask) = import_task(&line.as_str()) {
            match serde_json::ser::to_string(&ttask) {
                Ok(val) => println!("{}", val),
                Err(e) => {
                    trace_error(&e);
                    exit(1);
                }
            }

            let uuid = *ttask.uuid();
            match ttask.into_filelockentry(rt.store()) {
                Ok(val) => {
                    println!("Task {} stored in imag", uuid);
                    val
                },
                Err(e) => {
                    trace_error(&e);
                    exit(1);
                }
            };
        } else {
            error!("No usable input");
            exit(1);
        }
    } else if subcmd.is_present("delete") {
        // The used hook is "on-modify". This hook gives two json-objects
        // per usage und wants one (the second one) back.
        let mut counter   = 0;
        let stdin         = stdin();
        let stdin         = stdin.lock();

        if let Ok(ttasks) = import_tasks(stdin) {
            for ttask in ttasks {
                if counter % 2 == 1 {
                    // Only every second task is needed, the first one is the
                    // task before the change, and the second one after
                    // the change. The (maybe modified) second one is
                    // expected by taskwarrior.
                    match serde_json::ser::to_string(&ttask) {
                        Ok(val) => println!("{}", val),
                        Err(e) => {
                            trace_error(&e);
                            exit(1);
                        }
                    }

                    match ttask.status() {
                        &task_hookrs::status::TaskStatus::Deleted => {
                            match libimagtodo::delete::delete(rt.store(), *ttask.uuid()) {
                                Ok(_) => println!("Deleted task {}", *ttask.uuid()),
                                Err(e) => {
                                    trace_error(&e);
                                    exit(1);
                                }
                            }
                        }
                        _ => {
                        }
                    } // end match ttask.status()
                } // end if c % 2
                counter += 1;
            } // end for
        } else {
            error!("No usable input");
        }
    } else {
        // Should not be possible, as one argument is required via
        // ArgGroup
        unreachable!();
    }
}

fn exec(rt: &Runtime) {
    let subcmd = rt.cli().subcommand_matches("exec").unwrap();
    let mut args = Vec::new();
    if let Some(exec_string) = subcmd.values_of("command") {
        for e in exec_string {
            args.push(e);
        }
        let tw_process = Command::new("task").stdin(Stdio::null()).args(&args).spawn().unwrap_or_else(|e| {
            panic!("failed to execute taskwarrior: {}", e);
        });

        let output = tw_process.wait_with_output().unwrap_or_else(|e| {
            panic!("failed to unwrap output: {}", e);
        });
        let outstring = String::from_utf8(output.stdout).unwrap_or_else(|e| {
            panic!("failed to ececute: {}", e);
        });
        println!("{}", outstring);
    } else {
        panic!("faild to execute: You need to exec --command");
    }
}

fn list(rt: &Runtime) {
    let subcmd   = rt.cli().subcommand_matches("list").unwrap();
    let mut args = Vec::new();
    let verbose  = subcmd.is_present("verbose");
    let iter     = match libimagtodo::read::get_todo_iterator(rt.store()) {
        Err(e) => {
            trace_error(&e);
            exit(1);
        }
        Ok(val) => val,
    };

    for task in iter {
        match task {
            Ok(val) => {
                let uuid = match val.flentry.get_header().read("todo.uuid") {
                    Ok(Some(u)) => u,
                    Ok(None)    => continue,
                    Err(e)      => {
                        trace_error(&e);
                        continue;
                    }
                };

                if verbose {
                    args.clear();
                    args.push(format!("uuid:{}", uuid));
                    args.push(format!("{}", "information"));
                    let tw_process = Command::new("task").stdin(Stdio::null()).args(&args).spawn()
                        .unwrap_or_else(|e| {
                            trace_error(&e);
                            panic!("failed");
                        });
                    let output = tw_process.wait_with_output().unwrap_or_else(|e| {
                        panic!("failed to unwrap output: {}", e);
                    });
                    let outstring = String::from_utf8(output.stdout).unwrap_or_else(|e| {
                        panic!("failed to execute: {}", e);
                    });
                    println!("{}", outstring);
                } else {
                    println!("{}", match uuid {
                        toml::Value::String(s) => s,
                        _ => {
                            error!("Unexpected type for todo.uuid: {}", uuid);
                            continue;
                        },
                    });
                }
            }
            Err(e) => {
                trace_error(&e);
                continue;
            }
        } // end match task
    } // end for
}

<|endoftext|>