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

//! A pass that annotates every item and method with its stability level,
//! propagating default levels lexically from parent to children ast nodes.

use util::nodemap::{NodeMap, DefIdMap};
use syntax::codemap::Span;
use syntax::{attr, visit};
use syntax::ast;
use syntax::ast::{Attribute, Block, Crate, DefId, FnDecl, NodeId, Variant};
use syntax::ast::{Item, RequiredMethod, ProvidedMethod, TraitItem};
use syntax::ast::{TypeMethod, Method, Generics, StructDef, StructField};
use syntax::ast::{Ident, TypeTraitItem};
use syntax::ast_util::is_local;
use syntax::attr::Stability;
use syntax::visit::{FnKind, FkMethod, Visitor};
use middle::ty;
use metadata::csearch;

use std::mem::replace;

/// A stability index, giving the stability level for items and methods.
pub struct Index {
    // stability for crate-local items; unmarked stability == no entry
    local: NodeMap<Stability>,
    // cache for extern-crate items; unmarked stability == entry with None
    extern_cache: DefIdMap<Option<Stability>>
}

// A private tree-walker for producing an Index.
struct Annotator {
    index: Index,
    parent: Option<Stability>
}

impl Annotator {
    // Determine the stability for a node based on its attributes and inherited
    // stability. The stability is recorded in the index and used as the parent.
    fn annotate(&mut self, id: NodeId, attrs: &Vec<Attribute>, f: |&mut Annotator|) {
        match attr::find_stability(attrs.as_slice()) {
            Some(stab) => {
                self.index.local.insert(id, stab.clone());
                let parent = replace(&mut self.parent, Some(stab));
                f(self);
                self.parent = parent;
            }
            None => {
                self.parent.clone().map(|stab| self.index.local.insert(id, stab));
                f(self);
            }
        }
    }
}

impl<'v> Visitor<'v> for Annotator {
    fn visit_item(&mut self, i: &Item) {
        self.annotate(i.id, &i.attrs, |v| visit::walk_item(v, i));
    }

    fn visit_fn(&mut self, fk: FnKind<'v>, fd: &'v FnDecl,
                b: &'v Block, s: Span, _: NodeId) {
        match fk {
            FkMethod(_, _, meth) => {
                self.annotate(meth.id, &meth.attrs, |v| visit::walk_fn(v, fk, fd, b, s));
            }
            _ => visit::walk_fn(self, fk, fd, b, s)
        }
    }

    fn visit_trait_item(&mut self, t: &TraitItem) {
        let (id, attrs) = match *t {
            RequiredMethod(TypeMethod {id, ref attrs, ..}) => (id, attrs),

            // work around lack of pattern matching for @ types
            ProvidedMethod(ref method) => {
                match **method {
                    Method {ref attrs, id, ..} => (id, attrs),
                }
            }

            TypeTraitItem(ref typedef) => (typedef.ty_param.id, &typedef.attrs),
        };
        self.annotate(id, attrs, |v| visit::walk_trait_item(v, t));
    }

    fn visit_variant(&mut self, var: &Variant, g: &'v Generics) {
        self.annotate(var.node.id, &var.node.attrs, |v| visit::walk_variant(v, var, g))
    }

    fn visit_struct_def(&mut self, s: &StructDef, _: Ident, _: &Generics, _: NodeId) {
        match s.ctor_id {
            Some(id) => self.annotate(id, &vec![], |v| visit::walk_struct_def(v, s)),
            None => visit::walk_struct_def(self, s)
        }
    }

    fn visit_struct_field(&mut self, s: &StructField) {
        self.annotate(s.node.id, &s.node.attrs, |v| visit::walk_struct_field(v, s));
    }
}

impl Index {
    /// Construct the stability index for a crate being compiled.
    pub fn build(krate: &Crate) -> Index {
        let mut annotator = Annotator {
            index: Index {
                local: NodeMap::new(),
                extern_cache: DefIdMap::new()
            },
            parent: None
        };
        annotator.annotate(ast::CRATE_NODE_ID, &krate.attrs, |v| visit::walk_crate(v, krate));
        annotator.index
    }
}

/// Lookup the stability for a node, loading external crate
/// metadata as necessary.
pub fn lookup(tcx: &ty::ctxt, id: DefId) -> Option<Stability> {
    // is this definition the implementation of a trait method?
    match ty::trait_item_of_item(tcx, id) {
        Some(ty::MethodTraitItemId(trait_method_id))
                if trait_method_id != id => {
            lookup(tcx, trait_method_id)
        }
        _ if is_local(id) => {
            tcx.stability.borrow().local.find_copy(&id.node)
        }
        _ => {
            let stab = csearch::get_stability(&tcx.sess.cstore, id);
            let mut index = tcx.stability.borrow_mut();
            (*index).extern_cache.insert(id, stab.clone());
            stab
        }
    }
}
<commit_msg>rustc: do not inherit #[stable]<commit_after>// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! A pass that annotates every item and method with its stability level,
//! propagating default levels lexically from parent to children ast nodes.

use util::nodemap::{NodeMap, DefIdMap};
use syntax::codemap::Span;
use syntax::{attr, visit};
use syntax::ast;
use syntax::ast::{Attribute, Block, Crate, DefId, FnDecl, NodeId, Variant};
use syntax::ast::{Item, RequiredMethod, ProvidedMethod, TraitItem};
use syntax::ast::{TypeMethod, Method, Generics, StructField, TypeTraitItem};
use syntax::ast_util::is_local;
use syntax::attr::Stability;
use syntax::visit::{FnKind, FkMethod, Visitor};
use middle::ty;
use metadata::csearch;

use std::mem::replace;

/// A stability index, giving the stability level for items and methods.
pub struct Index {
    // stability for crate-local items; unmarked stability == no entry
    local: NodeMap<Stability>,
    // cache for extern-crate items; unmarked stability == entry with None
    extern_cache: DefIdMap<Option<Stability>>
}

// A private tree-walker for producing an Index.
struct Annotator {
    index: Index,
    parent: Option<Stability>
}

impl Annotator {
    // Determine the stability for a node based on its attributes and inherited
    // stability. The stability is recorded in the index and used as the parent.
    fn annotate(&mut self, id: NodeId, attrs: &Vec<Attribute>, f: |&mut Annotator|) {
        match attr::find_stability(attrs.as_slice()) {
            Some(stab) => {
                self.index.local.insert(id, stab.clone());

                // Don't inherit #[stable]
                if stab.level != attr::Stable {
                    let parent = replace(&mut self.parent, Some(stab));
                    f(self);
                    self.parent = parent;
                } else {
                    f(self);
                }
            }
            None => {
                self.parent.clone().map(|stab| self.index.local.insert(id, stab));
                f(self);
            }
        }
    }
}

impl<'v> Visitor<'v> for Annotator {
    fn visit_item(&mut self, i: &Item) {
        self.annotate(i.id, &i.attrs, |v| visit::walk_item(v, i));

        match i.node {
            ast::ItemStruct(ref sd, _) => {
                sd.ctor_id.map(|id| {
                    self.annotate(id, &i.attrs, |_| {})
                });
            }
            _ => {}
        }
    }

    fn visit_fn(&mut self, fk: FnKind<'v>, fd: &'v FnDecl,
                b: &'v Block, s: Span, _: NodeId) {
        match fk {
            FkMethod(_, _, meth) => {
                self.annotate(meth.id, &meth.attrs, |v| visit::walk_fn(v, fk, fd, b, s));
            }
            _ => visit::walk_fn(self, fk, fd, b, s)
        }
    }

    fn visit_trait_item(&mut self, t: &TraitItem) {
        let (id, attrs) = match *t {
            RequiredMethod(TypeMethod {id, ref attrs, ..}) => (id, attrs),

            // work around lack of pattern matching for @ types
            ProvidedMethod(ref method) => {
                match **method {
                    Method {ref attrs, id, ..} => (id, attrs),
                }
            }

            TypeTraitItem(ref typedef) => (typedef.ty_param.id, &typedef.attrs),
        };
        self.annotate(id, attrs, |v| visit::walk_trait_item(v, t));
    }

    fn visit_variant(&mut self, var: &Variant, g: &'v Generics) {
        self.annotate(var.node.id, &var.node.attrs, |v| visit::walk_variant(v, var, g))
    }

    fn visit_struct_field(&mut self, s: &StructField) {
        self.annotate(s.node.id, &s.node.attrs, |v| visit::walk_struct_field(v, s));
    }
}

impl Index {
    /// Construct the stability index for a crate being compiled.
    pub fn build(krate: &Crate) -> Index {
        let mut annotator = Annotator {
            index: Index {
                local: NodeMap::new(),
                extern_cache: DefIdMap::new()
            },
            parent: None
        };
        annotator.annotate(ast::CRATE_NODE_ID, &krate.attrs, |v| visit::walk_crate(v, krate));
        annotator.index
    }
}

/// Lookup the stability for a node, loading external crate
/// metadata as necessary.
pub fn lookup(tcx: &ty::ctxt, id: DefId) -> Option<Stability> {
    // is this definition the implementation of a trait method?
    match ty::trait_item_of_item(tcx, id) {
        Some(ty::MethodTraitItemId(trait_method_id))
                if trait_method_id != id => {
            lookup(tcx, trait_method_id)
        }
        _ if is_local(id) => {
            tcx.stability.borrow().local.find_copy(&id.node)
        }
        _ => {
            let stab = csearch::get_stability(&tcx.sess.cstore, id);
            let mut index = tcx.stability.borrow_mut();
            (*index).extern_cache.insert(id, stab.clone());
            stab
        }
    }
}
<|endoftext|>


<commit_before>use std::io::{self, Write};
use std::cell::RefCell;
use std::collections::{BTreeSet, HashMap, VecDeque};

use cargo::core::{Dependency, Package, PackageId, Workspace};
use cargo::ops::{self, Packages};
use cargo::util::{CargoError, CargoErrorKind, CargoResult, Config};
use tabwriter::TabWriter;

use super::Options;
use super::pkg_status::*;

/// An elaborate workspace containing resolved dependencies and
/// the update status of packages
pub struct ElaborateWorkspace<'ela> {
    pub workspace: &'ela Workspace<'ela>,
    pub pkgs: HashMap<PackageId, Package>,
    pub pkg_deps: HashMap<PackageId, HashMap<PackageId, Dependency>>,
    /// Map of package status
    pub pkg_status: RefCell<HashMap<Vec<&'ela PackageId>, PkgStatus>>,
    /// Whether using workspace mode
    pub workspace_mode: bool,
}

impl<'ela> ElaborateWorkspace<'ela> {
    /// Elaborate a `Workspace`
    pub fn from_workspace(
        workspace: &'ela Workspace,
        options: &Options,
    ) -> CargoResult<ElaborateWorkspace<'ela>> {
        let specs = Packages::All.into_package_id_specs(workspace)?;
        let (packages, resolve) = ops::resolve_ws_precisely(
            workspace,
            None,
            &options.flag_features,
            options.all_features(),
            options.no_default_features(),
            &specs,
        )?;
        let mut pkgs = HashMap::new();
        let mut pkg_deps = HashMap::new();
        for pkg_id in packages.package_ids() {
            let pkg = packages.get(pkg_id)?;
            pkgs.insert(pkg_id.clone(), pkg.clone());
            let deps = pkg.dependencies();
            let mut dep_map = HashMap::new();
            for dep_id in resolve.deps(pkg_id) {
                for d in deps {
                    if d.matches_id(dep_id) {
                        dep_map.insert(dep_id.clone(), d.clone());
                        break;
                    }
                }
            }
            pkg_deps.insert(pkg_id.clone(), dep_map);
        }

        Ok(ElaborateWorkspace {
            workspace: workspace,
            pkgs: pkgs,
            pkg_deps: pkg_deps,
            pkg_status: RefCell::new(HashMap::new()),
            workspace_mode: options.flag_workspace || workspace.current().is_err(),
        })
    }

    /// Determine root package based on current workspace and CLI options
    pub fn determine_root(&self, options: &Options) -> CargoResult<&PackageId> {
        if let Some(ref root_name) = options.flag_root {
            if let Ok(workspace_root) = self.workspace.current() {
                if root_name == workspace_root.name() {
                    Ok(workspace_root.package_id())
                } else {
                    for direct_dep in self.pkg_deps[workspace_root.package_id()].keys() {
                        if self.pkgs[direct_dep].name() == root_name {
                            return Ok(direct_dep);
                        }
                    }
                    return Err(CargoError::from_kind(CargoErrorKind::Msg(
                        "Root is neither the workspace root nor a direct dependency".to_owned(),
                    )));
                }
            } else {
                Err(CargoError::from_kind(CargoErrorKind::Msg(
                    "--root is not allowed when running against a virtual manifest".to_owned(),
                )))
            }
        } else {
            Ok(self.workspace.current()?.package_id())
        }
    }

    /// Find a member based on member name
    fn find_member(&self, member: &PackageId) -> CargoResult<&PackageId> {
        for m in self.workspace.members() {
            // members with the same name in a workspace is not allowed
            // even with different paths
            if member.name() == m.name() {
                return Ok(m.package_id());
            }
        }
        Err(CargoError::from_kind(CargoErrorKind::Msg(format!(
            "Workspace member {} not found",
            member.name()
        ))))
    }

    /// Find a contained package, which is a member or dependency inside the workspace
    fn find_contained_package(&self, name: &str) -> CargoResult<PackageId> {
        let root_path = self.workspace.root();
        for (pkg_id, pkg) in &self.pkgs {
            if pkg.manifest_path().starts_with(root_path) && pkg.name() == name {
                return Ok(pkg_id.clone());
            }
        }
        Err(CargoError::from_kind(CargoErrorKind::Msg(format!(
            "Cannot find package {} in workspace",
            name
        ))))
    }

    /// Find a direct dependency of a contained package
    pub fn find_direct_dependency(
        &self,
        dependency_name: &str,
        dependent_package_name: &str,
    ) -> CargoResult<PackageId> {
        let dependent_package = self.find_contained_package(dependent_package_name)?;
        for direct_dep in self.pkg_deps[&dependent_package].keys() {
            if direct_dep.name() == dependency_name {
                return Ok(direct_dep.clone());
            }
        }
        Err(CargoError::from_kind(CargoErrorKind::Msg(format!(
            "Direct dependency {} not found for package {}",
            dependency_name, dependent_package_name
        ))))
    }

    /// Resolve compatible and latest status from the corresponding `ElaborateWorkspace`s
    pub fn resolve_status(
        &'ela self,
        compat: &ElaborateWorkspace,
        latest: &ElaborateWorkspace,
        options: &Options,
        _config: &Config,
        root: &'ela PackageId,
    ) -> CargoResult<()> {
        self.pkg_status.borrow_mut().clear();
        let (compat_root, latest_root) = if self.workspace_mode {
            (compat.find_member(root)?, latest.find_member(root)?)
        } else {
            (
                compat.determine_root(options)?,
                latest.determine_root(options)?,
            )
        };

        let mut queue = VecDeque::new();
        queue.push_back((vec![root], Some(compat_root), Some(latest_root)));
        while let Some((path, compat_pkg, latest_pkg)) = queue.pop_front() {
            let pkg = path.last().unwrap();
            let depth = path.len() as i32 - 1;
            // generate pkg_status
            let status = PkgStatus {
                compat: Status::from_versions(pkg.version(), compat_pkg.map(|p| p.version())),
                latest: Status::from_versions(pkg.version(), latest_pkg.map(|p| p.version())),
            };
            debug!(
                _config,
                "STATUS => PKG: {}; PATH: {:?}; COMPAT: {:?}; LATEST: {:?}; STATUS: {:?}",
                pkg,
                path,
                compat_pkg,
                latest_pkg,
                status
            );
            self.pkg_status.borrow_mut().insert(path.clone(), status);
            // next layer
            if options.flag_depth.is_none() || &depth < options.flag_depth.as_ref().unwrap() {
                self.pkg_deps[pkg]
                    .keys()
                    .filter(|dep| !path.contains(dep))
                    .for_each(|dep| {
                        let name = dep.name();
                        let compat_pkg = compat_pkg
                            .and_then(|id| compat.pkg_deps.get(id))
                            .map(|dep_map| dep_map.keys())
                            .and_then(|ref mut deps| deps.find(|dep| dep.name() == name));
                        let latest_pkg = latest_pkg
                            .and_then(|id| latest.pkg_deps.get(id))
                            .map(|dep_map| dep_map.keys())
                            .and_then(|ref mut deps| deps.find(|dep| dep.name() == name));
                        let mut path = path.clone();
                        path.push(dep);
                        queue.push_back((path, compat_pkg, latest_pkg));
                    });
            }
        }

        Ok(())
    }

    /// Print package status to `TabWriter`
    pub fn print_list(
        &'ela self,
        options: &Options,
        root: &'ela PackageId,
        preceding_line: bool,
    ) -> CargoResult<i32> {
        let mut lines = BTreeSet::new();
        let mut queue = VecDeque::new();
        queue.push_back(vec![root]);
        while let Some(path) = queue.pop_front() {
            let pkg = path.last().unwrap();
            let depth = path.len() as i32 - 1;
            // generate lines
            let status = &self.pkg_status.borrow_mut()[&path];
            if (status.compat.is_changed() || status.latest.is_changed())
                && (options.flag_packages.is_empty()
                    || options.flag_packages.contains(&pkg.name().to_string()))
            {
                // name version compatible latest kind platform
                let parent = path.get(path.len() - 2);
                if let Some(parent) = parent {
                    let dependency = &self.pkg_deps[parent][pkg];
                    let label = if self.workspace_mode
                        || parent == &self.workspace.current()?.package_id()
                    {
                        pkg.name().to_string()
                    } else {
                        format!("{}->{}", self.pkgs[parent].name(), pkg.name())
                    };
                    let line = format!(
                        "{}\t{}\t{}\t{}\t{:?}\t{}\n",
                        label,
                        pkg.version(),
                        status.compat.to_string(),
                        status.latest.to_string(),
                        dependency.kind(),
                        dependency
                            .platform()
                            .map(|p| p.to_string())
                            .unwrap_or_else(|| "---".to_owned())
                    );
                    lines.insert(line);
                } else {
                    let line = format!(
                        "{}\t{}\t{}\t{}\t---\t---\n",
                        pkg.name(),
                        pkg.version(),
                        status.compat.to_string(),
                        status.latest.to_string()
                    );
                    lines.insert(line);
                }
            }
            // next layer
            if options.flag_depth.is_none() || &depth < options.flag_depth.as_ref().unwrap() {
                self.pkg_deps[pkg]
                    .keys()
                    .filter(|dep| !path.contains(dep))
                    .filter(|dep| {
                        !self.workspace_mode
                            || !self.workspace.members().any(|mem| &mem.package_id() == dep)
                    })
                    .for_each(|dep| {
                        let mut path = path.clone();
                        path.push(dep);
                        queue.push_back(path);
                    });
            }
        }

        if lines.is_empty() {
            if !self.workspace_mode {
                println!("All dependencies are up to date, yay!");
            }
        } else {
            if preceding_line {
                println!();
            }
            if self.workspace_mode {
                println!("{}\n================", root.name());
            }
            let mut tw = TabWriter::new(vec![]);
            write!(&mut tw, "Name\tProject\tCompat\tLatest\tKind\tPlatform\n")?;
            write!(&mut tw, "----\t-------\t------\t------\t----\t--------\n")?;
            for line in &lines {
                write!(&mut tw, "{}", line)?;
            }
            tw.flush()?;
            write!(
                io::stdout(),
                "{}",
                String::from_utf8(tw.into_inner().unwrap()).unwrap()
            )?;
            io::stdout().flush()?;
        }

        Ok(lines.len() as i32)
    }
}
<commit_msg>fix: Remove extra reference taking per clippy.<commit_after>use std::io::{self, Write};
use std::cell::RefCell;
use std::collections::{BTreeSet, HashMap, VecDeque};

use cargo::core::{Dependency, Package, PackageId, Workspace};
use cargo::ops::{self, Packages};
use cargo::util::{CargoError, CargoErrorKind, CargoResult, Config};
use tabwriter::TabWriter;

use super::Options;
use super::pkg_status::*;

/// An elaborate workspace containing resolved dependencies and
/// the update status of packages
pub struct ElaborateWorkspace<'ela> {
    pub workspace: &'ela Workspace<'ela>,
    pub pkgs: HashMap<PackageId, Package>,
    pub pkg_deps: HashMap<PackageId, HashMap<PackageId, Dependency>>,
    /// Map of package status
    pub pkg_status: RefCell<HashMap<Vec<&'ela PackageId>, PkgStatus>>,
    /// Whether using workspace mode
    pub workspace_mode: bool,
}

impl<'ela> ElaborateWorkspace<'ela> {
    /// Elaborate a `Workspace`
    pub fn from_workspace(
        workspace: &'ela Workspace,
        options: &Options,
    ) -> CargoResult<ElaborateWorkspace<'ela>> {
        let specs = Packages::All.into_package_id_specs(workspace)?;
        let (packages, resolve) = ops::resolve_ws_precisely(
            workspace,
            None,
            &options.flag_features,
            options.all_features(),
            options.no_default_features(),
            &specs,
        )?;
        let mut pkgs = HashMap::new();
        let mut pkg_deps = HashMap::new();
        for pkg_id in packages.package_ids() {
            let pkg = packages.get(pkg_id)?;
            pkgs.insert(pkg_id.clone(), pkg.clone());
            let deps = pkg.dependencies();
            let mut dep_map = HashMap::new();
            for dep_id in resolve.deps(pkg_id) {
                for d in deps {
                    if d.matches_id(dep_id) {
                        dep_map.insert(dep_id.clone(), d.clone());
                        break;
                    }
                }
            }
            pkg_deps.insert(pkg_id.clone(), dep_map);
        }

        Ok(ElaborateWorkspace {
            workspace: workspace,
            pkgs: pkgs,
            pkg_deps: pkg_deps,
            pkg_status: RefCell::new(HashMap::new()),
            workspace_mode: options.flag_workspace || workspace.current().is_err(),
        })
    }

    /// Determine root package based on current workspace and CLI options
    pub fn determine_root(&self, options: &Options) -> CargoResult<&PackageId> {
        if let Some(ref root_name) = options.flag_root {
            if let Ok(workspace_root) = self.workspace.current() {
                if root_name == workspace_root.name() {
                    Ok(workspace_root.package_id())
                } else {
                    for direct_dep in self.pkg_deps[workspace_root.package_id()].keys() {
                        if self.pkgs[direct_dep].name() == root_name {
                            return Ok(direct_dep);
                        }
                    }
                    return Err(CargoError::from_kind(CargoErrorKind::Msg(
                        "Root is neither the workspace root nor a direct dependency".to_owned(),
                    )));
                }
            } else {
                Err(CargoError::from_kind(CargoErrorKind::Msg(
                    "--root is not allowed when running against a virtual manifest".to_owned(),
                )))
            }
        } else {
            Ok(self.workspace.current()?.package_id())
        }
    }

    /// Find a member based on member name
    fn find_member(&self, member: &PackageId) -> CargoResult<&PackageId> {
        for m in self.workspace.members() {
            // members with the same name in a workspace is not allowed
            // even with different paths
            if member.name() == m.name() {
                return Ok(m.package_id());
            }
        }
        Err(CargoError::from_kind(CargoErrorKind::Msg(format!(
            "Workspace member {} not found",
            member.name()
        ))))
    }

    /// Find a contained package, which is a member or dependency inside the workspace
    fn find_contained_package(&self, name: &str) -> CargoResult<PackageId> {
        let root_path = self.workspace.root();
        for (pkg_id, pkg) in &self.pkgs {
            if pkg.manifest_path().starts_with(root_path) && pkg.name() == name {
                return Ok(pkg_id.clone());
            }
        }
        Err(CargoError::from_kind(CargoErrorKind::Msg(format!(
            "Cannot find package {} in workspace",
            name
        ))))
    }

    /// Find a direct dependency of a contained package
    pub fn find_direct_dependency(
        &self,
        dependency_name: &str,
        dependent_package_name: &str,
    ) -> CargoResult<PackageId> {
        let dependent_package = self.find_contained_package(dependent_package_name)?;
        for direct_dep in self.pkg_deps[&dependent_package].keys() {
            if direct_dep.name() == dependency_name {
                return Ok(direct_dep.clone());
            }
        }
        Err(CargoError::from_kind(CargoErrorKind::Msg(format!(
            "Direct dependency {} not found for package {}",
            dependency_name, dependent_package_name
        ))))
    }

    /// Resolve compatible and latest status from the corresponding `ElaborateWorkspace`s
    pub fn resolve_status(
        &'ela self,
        compat: &ElaborateWorkspace,
        latest: &ElaborateWorkspace,
        options: &Options,
        _config: &Config,
        root: &'ela PackageId,
    ) -> CargoResult<()> {
        self.pkg_status.borrow_mut().clear();
        let (compat_root, latest_root) = if self.workspace_mode {
            (compat.find_member(root)?, latest.find_member(root)?)
        } else {
            (
                compat.determine_root(options)?,
                latest.determine_root(options)?,
            )
        };

        let mut queue = VecDeque::new();
        queue.push_back((vec![root], Some(compat_root), Some(latest_root)));
        while let Some((path, compat_pkg, latest_pkg)) = queue.pop_front() {
            let pkg = path.last().unwrap();
            let depth = path.len() as i32 - 1;
            // generate pkg_status
            let status = PkgStatus {
                compat: Status::from_versions(pkg.version(), compat_pkg.map(|p| p.version())),
                latest: Status::from_versions(pkg.version(), latest_pkg.map(|p| p.version())),
            };
            debug!(
                _config,
                "STATUS => PKG: {}; PATH: {:?}; COMPAT: {:?}; LATEST: {:?}; STATUS: {:?}",
                pkg,
                path,
                compat_pkg,
                latest_pkg,
                status
            );
            self.pkg_status.borrow_mut().insert(path.clone(), status);
            // next layer
            if options.flag_depth.is_none() || depth < options.flag_depth.unwrap() {
                self.pkg_deps[pkg]
                    .keys()
                    .filter(|dep| !path.contains(dep))
                    .for_each(|dep| {
                        let name = dep.name();
                        let compat_pkg = compat_pkg
                            .and_then(|id| compat.pkg_deps.get(id))
                            .map(|dep_map| dep_map.keys())
                            .and_then(|ref mut deps| deps.find(|dep| dep.name() == name));
                        let latest_pkg = latest_pkg
                            .and_then(|id| latest.pkg_deps.get(id))
                            .map(|dep_map| dep_map.keys())
                            .and_then(|ref mut deps| deps.find(|dep| dep.name() == name));
                        let mut path = path.clone();
                        path.push(dep);
                        queue.push_back((path, compat_pkg, latest_pkg));
                    });
            }
        }

        Ok(())
    }

    /// Print package status to `TabWriter`
    pub fn print_list(
        &'ela self,
        options: &Options,
        root: &'ela PackageId,
        preceding_line: bool,
    ) -> CargoResult<i32> {
        let mut lines = BTreeSet::new();
        let mut queue = VecDeque::new();
        queue.push_back(vec![root]);
        while let Some(path) = queue.pop_front() {
            let pkg = path.last().unwrap();
            let depth = path.len() as i32 - 1;
            // generate lines
            let status = &self.pkg_status.borrow_mut()[&path];
            if (status.compat.is_changed() || status.latest.is_changed())
                && (options.flag_packages.is_empty()
                    || options.flag_packages.contains(&pkg.name().to_string()))
            {
                // name version compatible latest kind platform
                let parent = path.get(path.len() - 2);
                if let Some(parent) = parent {
                    let dependency = &self.pkg_deps[parent][pkg];
                    let label = if self.workspace_mode
                        || parent == &self.workspace.current()?.package_id()
                    {
                        pkg.name().to_string()
                    } else {
                        format!("{}->{}", self.pkgs[parent].name(), pkg.name())
                    };
                    let line = format!(
                        "{}\t{}\t{}\t{}\t{:?}\t{}\n",
                        label,
                        pkg.version(),
                        status.compat.to_string(),
                        status.latest.to_string(),
                        dependency.kind(),
                        dependency
                            .platform()
                            .map(|p| p.to_string())
                            .unwrap_or_else(|| "---".to_owned())
                    );
                    lines.insert(line);
                } else {
                    let line = format!(
                        "{}\t{}\t{}\t{}\t---\t---\n",
                        pkg.name(),
                        pkg.version(),
                        status.compat.to_string(),
                        status.latest.to_string()
                    );
                    lines.insert(line);
                }
            }
            // next layer
            if options.flag_depth.is_none() || depth < options.flag_depth.unwrap() {
                self.pkg_deps[pkg]
                    .keys()
                    .filter(|dep| !path.contains(dep))
                    .filter(|dep| {
                        !self.workspace_mode
                            || !self.workspace.members().any(|mem| &mem.package_id() == dep)
                    })
                    .for_each(|dep| {
                        let mut path = path.clone();
                        path.push(dep);
                        queue.push_back(path);
                    });
            }
        }

        if lines.is_empty() {
            if !self.workspace_mode {
                println!("All dependencies are up to date, yay!");
            }
        } else {
            if preceding_line {
                println!();
            }
            if self.workspace_mode {
                println!("{}\n================", root.name());
            }
            let mut tw = TabWriter::new(vec![]);
            write!(&mut tw, "Name\tProject\tCompat\tLatest\tKind\tPlatform\n")?;
            write!(&mut tw, "----\t-------\t------\t------\t----\t--------\n")?;
            for line in &lines {
                write!(&mut tw, "{}", line)?;
            }
            tw.flush()?;
            write!(
                io::stdout(),
                "{}",
                String::from_utf8(tw.into_inner().unwrap()).unwrap()
            )?;
            io::stdout().flush()?;
        }

        Ok(lines.len() as i32)
    }
}
<|endoftext|>


<commit_before><commit_msg>Actually implement Iterator for Lines.<commit_after><|endoftext|>


<commit_before><commit_msg>Use `ErrorKind::Continue` for stream parsing<commit_after><|endoftext|>


<commit_before>extern crate rusqlite;

use super::{Image,Tag,AnyWith,parse_tag};

use self::rusqlite::{Result as SQLResult, Row};

pub struct Db {
    db: rusqlite::Connection
}

impl Db {
    pub fn new() -> Self {
        use self::rusqlite::Connection;
        use std::path::Path;

        let conn = Connection::open(Path::new("db.db")).unwrap();
        conn.execute("CREATE TABLE IF NOT EXISTS images(
                    id INTEGER PRIMARY KEY AUTOINCREMENT,
                    name TEXT NOT NULL UNIQUE,
                    tags TEXT NOT NULL,

                    got_from TEXT,
                    original_link TEXT,
                    rating CHAR);",&[]).unwrap();
        Db{
            db: conn
        }
    }

    pub fn add_with_tags_name(&self, tags: &[String], ext: &str) -> SQLResult<String> {
        let mut name = tags.join("_").replace("'","''");
        name.push_str(ext);
        self.add_image(&name, tags, None, None, None)?;
        Ok(name)
    }

    pub fn add_image<'a, T1: Into<Option<&'a str>>,
    T2: Into<Option<&'a str>>,
    C: Into<Option<char>>>(&self, name: &str, tags: &[String], got_from: T1, original_link: T2, rating: C) -> SQLResult<()> {
        let mut fields = "INSERT INTO images (name, tags".to_string();
        let mut values = format!("VALUES('{}', '{}'", name, format!(",{},",tags.join(",").replace("'","''")));
        if let Some(x) = got_from.into() {
            fields.push_str(", got_from");
            values.push_str(&format!(", '{}'", x));
        }
        if let Some(x) = original_link.into() {
            fields.push_str(", original_link");
            values.push_str(&format!(", '{}'", x));
        }
        if let Some(x) = rating.into() {
            fields.push_str(", rating");
            values.push_str(&format!(", '{}'", x));
        }

        fields.push_str(")");
        values.push_str(")");

        let q = format!("{} {}", fields, values);
        self.db.execute(&q, &[]).unwrap();
        Ok(())
    }

    fn extract_all(row: Row) -> Image {
        let id = row.get(0);
        let name = row.get(1);
        let mut tags = row.get::<i32,String>(2).split(',').map(String::from).collect::<Vec<_>>();
        let l = tags.len()-2;
        tags.remove(0); tags.remove(l);

        let got_from = row.get::<i32, Option<String>>(3).unwrap_or(" ".to_string());
        let original_link = row.get::<i32,Option<String>>(4).unwrap_or(" ".to_string());
        let rating = row.get::<i32,Option<String>>(5).unwrap_or(" ".to_string()).chars().nth(0).unwrap_or(' ');

        Image{
            id: id,
            name: name,
            tags: tags,
            got_from: got_from,
            original_link: original_link,
            rating: rating
        }
    }

    fn extract_all_ref(row: &Row) -> Image {
        let id = row.get(0);
        let name = row.get(1);
        let mut tags = row.get::<i32,String>(2).split(',').map(String::from).collect::<Vec<_>>();
        let l = tags.len()-2;
        tags.remove(0); tags.remove(l);

        let got_from = row.get::<i32, Option<String>>(3).unwrap_or(" ".to_string());
        let original_link = row.get::<i32,Option<String>>(4).unwrap_or(" ".to_string());
        let rating = row.get::<i32,Option<String>>(5).unwrap_or(" ".to_string()).chars().nth(0).unwrap_or(' ');

        Image{
            id: id,
            name: name,
            tags: tags,
            got_from: got_from,
            original_link: original_link,
            rating: rating
        }
    }

    pub fn get_image(&self, id: i32) -> SQLResult<Image> {
        self.db.query_row("SELECT * FROM images WHERE id = ?", &[&id], Db::extract_all)
    }

    pub fn get_images<T: Into<Option<i32>>>(&self, take: T, skip: usize) -> SQLResult<Vec<Image>>{
        let take = match take.into() {
            Some(x) => x,
            None    => -1
        };

        let mut st = self.db.prepare(&format!("SELECT * FROM images ORDER BY id DESC LIMIT {} OFFSET {}", take, skip))?;
        let st = st.query_map(&[], Db::extract_all_ref)?.map(|x| x.unwrap());
        Ok(st.collect::<Vec<_>>())
    }

    pub fn by_tags<T: Into<Option<i32>>>(&self, take: T, skip: usize, tags: &[String]) -> SQLResult<Vec<Image>> {
        let tags = tags.iter().map(|x| parse_tag(&x.replace("_",r"\_").replace("%", r"\%").replace("'", "''"))).collect::<Vec<_>>();

        let q = tags.iter().map(|t| {
            match *t {
                Tag::Include(ref incl) => format!(r"tags LIKE '%,{},%' ESCAPE '\'", incl),
                Tag::Exclude(ref excl) => format!(r"tags NOT LIKE '%,{},%' ESCAPE '\'", excl),
                Tag::AnyWith(ref x) => match *x {
                    AnyWith::Before(ref bef) => format!(r"tags LIKE '%,{}%,%' ESCAPE '\'", bef),
                    AnyWith::After(ref aft) => format!(r"tags LIKE '%,%{},%' ESCAPE '\'", aft),
                },
                Tag::Rating(ref r) => {
                    let mut s = "(".to_string();
                    for tg in r {
                        s.push_str(&format!("rating = '{}' OR ", tg))
                    }
                    let _ = (0..4).inspect(|_| {s.pop(); }).collect::<Vec<_>>();
                    s.push_str(")");

                    s
                },

                Tag::From(ref f) => {
                    let mut s = "(".to_string();
                    for tg in f {
                        s.push_str(&format!("got_from = '{}' OR ", tg))
                    }
                    let _ = (0..4).inspect(|_| {s.pop(); }).collect::<Vec<_>>();
                    s.push_str(")");

                    s
                }
            }
        }).collect::<Vec<_>>().join(" AND ");

        let take = match take.into() {
            Some(x) => x,
            None    => -1
        };

        let mut st = self.db.prepare(&format!("SELECT * FROM images WHERE {} ORDER BY id DESC LIMIT {} OFFSET {}", q, take, skip))?;
        let st = st.query_map(&[], Db::extract_all_ref)?.map(|x| x.unwrap());
        Ok(st.collect::<Vec<_>>())
    }
}
<commit_msg>Упс, а оно точку не ставило к расширению...<commit_after>extern crate rusqlite;

use super::{Image,Tag,AnyWith,parse_tag};

use self::rusqlite::{Result as SQLResult, Row};

pub struct Db {
    db: rusqlite::Connection
}

impl Db {
    pub fn new() -> Self {
        use self::rusqlite::Connection;
        use std::path::Path;

        let conn = Connection::open(Path::new("db.db")).unwrap();
        conn.execute("CREATE TABLE IF NOT EXISTS images(
                    id INTEGER PRIMARY KEY AUTOINCREMENT,
                    name TEXT NOT NULL UNIQUE,
                    tags TEXT NOT NULL,

                    got_from TEXT,
                    original_link TEXT,
                    rating CHAR);",&[]).unwrap();
        Db{
            db: conn
        }
    }

    pub fn add_with_tags_name(&self, tags: &[String], ext: &str) -> SQLResult<String> {
        let name = tags.join("_").replace("'","''") + "." + ext;
        self.add_image(&name, tags, None, None, None)?;
        Ok(name)
    }

    pub fn add_image<'a, T1: Into<Option<&'a str>>,
    T2: Into<Option<&'a str>>,
    C: Into<Option<char>>>(&self, name: &str, tags: &[String], got_from: T1, original_link: T2, rating: C) -> SQLResult<()> {
        let mut fields = "INSERT INTO images (name, tags".to_string();
        let mut values = format!("VALUES('{}', '{}'", name, format!(",{},",tags.join(",").replace("'","''")));
        if let Some(x) = got_from.into() {
            fields.push_str(", got_from");
            values.push_str(&format!(", '{}'", x));
        }
        if let Some(x) = original_link.into() {
            fields.push_str(", original_link");
            values.push_str(&format!(", '{}'", x));
        }
        if let Some(x) = rating.into() {
            fields.push_str(", rating");
            values.push_str(&format!(", '{}'", x));
        }

        fields.push_str(")");
        values.push_str(")");

        let q = format!("{} {}", fields, values);
        self.db.execute(&q, &[]).unwrap();
        Ok(())
    }

    fn extract_all(row: Row) -> Image {
        let id = row.get(0);
        let name = row.get(1);
        let mut tags = row.get::<i32,String>(2).split(',').map(String::from).collect::<Vec<_>>();
        let l = tags.len()-2;
        tags.remove(0); tags.remove(l);

        let got_from = row.get::<i32, Option<String>>(3).unwrap_or(" ".to_string());
        let original_link = row.get::<i32,Option<String>>(4).unwrap_or(" ".to_string());
        let rating = row.get::<i32,Option<String>>(5).unwrap_or(" ".to_string()).chars().nth(0).unwrap_or(' ');

        Image{
            id: id,
            name: name,
            tags: tags,
            got_from: got_from,
            original_link: original_link,
            rating: rating
        }
    }

    fn extract_all_ref(row: &Row) -> Image {
        let id = row.get(0);
        let name = row.get(1);
        let mut tags = row.get::<i32,String>(2).split(',').map(String::from).collect::<Vec<_>>();
        let l = tags.len()-2;
        tags.remove(0); tags.remove(l);

        let got_from = row.get::<i32, Option<String>>(3).unwrap_or(" ".to_string());
        let original_link = row.get::<i32,Option<String>>(4).unwrap_or(" ".to_string());
        let rating = row.get::<i32,Option<String>>(5).unwrap_or(" ".to_string()).chars().nth(0).unwrap_or(' ');

        Image{
            id: id,
            name: name,
            tags: tags,
            got_from: got_from,
            original_link: original_link,
            rating: rating
        }
    }

    pub fn get_image(&self, id: i32) -> SQLResult<Image> {
        self.db.query_row("SELECT * FROM images WHERE id = ?", &[&id], Db::extract_all)
    }

    pub fn get_images<T: Into<Option<i32>>>(&self, take: T, skip: usize) -> SQLResult<Vec<Image>>{
        let take = match take.into() {
            Some(x) => x,
            None    => -1
        };

        let mut st = self.db.prepare(&format!("SELECT * FROM images ORDER BY id DESC LIMIT {} OFFSET {}", take, skip))?;
        let st = st.query_map(&[], Db::extract_all_ref)?.map(|x| x.unwrap());
        Ok(st.collect::<Vec<_>>())
    }

    pub fn by_tags<T: Into<Option<i32>>>(&self, take: T, skip: usize, tags: &[String]) -> SQLResult<Vec<Image>> {
        let tags = tags.iter().map(|x| parse_tag(&x.replace("_",r"\_").replace("%", r"\%").replace("'", "''"))).collect::<Vec<_>>();

        let q = tags.iter().map(|t| {
            match *t {
                Tag::Include(ref incl) => format!(r"tags LIKE '%,{},%' ESCAPE '\'", incl),
                Tag::Exclude(ref excl) => format!(r"tags NOT LIKE '%,{},%' ESCAPE '\'", excl),
                Tag::AnyWith(ref x) => match *x {
                    AnyWith::Before(ref bef) => format!(r"tags LIKE '%,{}%,%' ESCAPE '\'", bef),
                    AnyWith::After(ref aft) => format!(r"tags LIKE '%,%{},%' ESCAPE '\'", aft),
                },
                Tag::Rating(ref r) => {
                    let mut s = "(".to_string();
                    for tg in r {
                        s.push_str(&format!("rating = '{}' OR ", tg))
                    }
                    let _ = (0..4).inspect(|_| {s.pop(); }).collect::<Vec<_>>();
                    s.push_str(")");

                    s
                },

                Tag::From(ref f) => {
                    let mut s = "(".to_string();
                    for tg in f {
                        s.push_str(&format!("got_from = '{}' OR ", tg))
                    }
                    let _ = (0..4).inspect(|_| {s.pop(); }).collect::<Vec<_>>();
                    s.push_str(")");

                    s
                }
            }
        }).collect::<Vec<_>>().join(" AND ");

        let take = match take.into() {
            Some(x) => x,
            None    => -1
        };

        let mut st = self.db.prepare(&format!("SELECT * FROM images WHERE {} ORDER BY id DESC LIMIT {} OFFSET {}", q, take, skip))?;
        let st = st.query_map(&[], Db::extract_all_ref)?.map(|x| x.unwrap());
        Ok(st.collect::<Vec<_>>())
    }
}
<|endoftext|>


<commit_before><commit_msg>text justification<commit_after><|endoftext|>


<commit_before>use std::path::Path;

fn main() {
    // Create a `Path` from an `&'static str`
    let path = Path::new(".");

    // The `display` method returns a `Show`able structure
    let display = path.display();

    // `join` merges a path with a byte container using the OS specific
    // separator, and returns the new path
    let new_path = path.join("a").join("b");

    // Convert the path into a string slice
    match new_path.to_str() {
        None => panic!("new path is not a valid UTF-8 sequence"),
        Some(s) => println!("new path is {}", s),
    }
}
<commit_msg>Translate examples/std_misc/path/path.rs<commit_after>use std::path::Path;

fn main() {
    // 从 `&'static str` 创建一个 `Path`
    let path = Path::new(".");

    // `display` 方法返回一个可显示（showable）的结构体
    let display = path.display();

    // `join` 使用操作系统的特定分隔符来合并路径，并返回新的路径
    let new_path = path.join("a").join("b");

    // 将路径转换成一个字符串 slice
    match new_path.to_str() {
        None => panic!("new path is not a valid UTF-8 sequence"),
        Some(s) => println!("new path is {}", s),
    }
}
<|endoftext|>


<commit_before>use libtest_mimic::{run_tests, Arguments, Outcome, Test};
use std::error::Error;
use std::fs::{read_dir, read_to_string};
use std::path::Path;
use wasmbin::Module;
use wast::parser::{parse, ParseBuffer};
use wast::Wast;

const IGNORED_ERRORS: &[&str] = &[
    // We don't perform cross-section analysis.
    "function and code section have inconsistent lengths",
    "data count section required",
    "data count and data section have inconsistent lengths",
    // We allow non-zero table and memory IDs already.
    "zero flag expected",
    // We don't perform full function analysis either.
    "too many locals",
];

struct WasmTest {
    module: Vec<u8>,
    expect_result: Result<(), String>,
}

fn read_tests_from_file(path: &Path, dest: &mut Vec<Test<WasmTest>>) -> Result<(), Box<dyn Error>> {
    let src = read_to_string(path)?;
    let set_err_path_text = |mut err: wast::Error| {
        err.set_path(path);
        err.set_text(&src);
        err
    };
    let buf = ParseBuffer::new(&src).map_err(set_err_path_text)?;
    let wast = parse::<Wast>(&buf).map_err(set_err_path_text)?;
    for directive in wast.directives {
        let (span, mut module, expect_result) = match directive {
            // Expect errors for assert_malformed on binary or AST modules.
            wast::WastDirective::AssertMalformed {
                span,
                module: wast::QuoteModule::Module(module),
                message,
            }
            // Unlike other AssertInvalid, this is actually something we
            // check at the parsing time, because it's part of our
            // typesystem and doesn't require cross-function or
            // cross-section checks.
            | wast::WastDirective::AssertInvalid {
                span,
                module,
                message: message @ "invalid lane index",
            } => (span, module, Err(message)),
            // Expect successful parsing for regular AST modules.
            wast::WastDirective::Module(module) => (module.span, module, Ok(())),
            // Counter-intuitively, expect successful parsing for modules that are supposed
            // to error out at runtime or linking stage, too.
            wast::WastDirective::AssertInvalid { span, module, .. }
            | wast::WastDirective::AssertUnlinkable { span, module, .. } => (span, module, Ok(())),
            _ => {
                // Skipping interpreted
                continue;
            }
        };
        let (line, col) = span.linecol_in(&src);
        dest.push(Test {
            name: format!("{}:{}:{}", path.display(), line + 1, col + 1),
            kind: String::default(),
            is_ignored: match expect_result {
                Ok(()) => false,
                Err(err) => cfg!(feature = "lazy-blob") || IGNORED_ERRORS.contains(&err),
            },
            is_bench: false,
            data: WasmTest {
                module: module.encode()?,
                expect_result: expect_result.map_err(|err| err.to_owned()),
            },
        });
    }
    Ok(())
}

fn read_tests_from_dir(path: &Path, dest: &mut Vec<Test<WasmTest>>) -> Result<(), Box<dyn Error>> {
    for file in read_dir(path)? {
        let path = file?.path();
        if path.extension().map_or(false, |ext| ext == "wast") {
            read_tests_from_file(&path, dest).map_err(|err| {
                format!("could not read tests from file {}: {}", path.display(), err)
            })?;
        }
    }
    Ok(())
}

fn read_all_tests(path: &Path) -> Result<Vec<Test<WasmTest>>, Box<dyn Error>> {
    let mut tests = Vec::new();
    read_tests_from_dir(path, &mut tests)?;
    let proposals_dir = path.join("proposals");

    macro_rules! read_proposal_tests {
        ($name:literal) => {
            if cfg!(feature = $name) {
                read_tests_from_dir(&proposals_dir.join($name), &mut tests)?;
            }
        };
    }

    read_proposal_tests!("tail-call");
    read_proposal_tests!("bulk-memory-operations");
    read_proposal_tests!("simd");

    if tests.is_empty() {
        return Err("Couldn't find any tests. Did you run `git submodule update --init`?".into());
    }

    Ok(tests)
}

fn run_test(test: &WasmTest) -> Result<(), Box<dyn Error>> {
    let mut slice = test.module.as_slice();
    let module = match (Module::decode_from(&mut slice), &test.expect_result) {
        (Ok(_), Err(err)) => {
            return Err(format!(
                "Expected an invalid module definition with an error: {}",
                err
            )
            .into());
        }
        (Err(err), Ok(())) => {
            return Err(format!(
                "Expected a valid module definition, but got an error\nParsed part: {:02X?}\nUnparsed part: {:02X?}\nError: {:#}",
                &test.module[..test.module.len() - slice.len()],
                slice,
                err
            )
            .into());
        }
        (Ok(module), Ok(())) => module,
        (Err(_), Err(_)) => return Ok(()),
    };
    let out = module.encode_into(Vec::new())?;
    if out != test.module {
        // In the rare case that binary representation doesn't match, it
        // might be because the test uses longer LEB128 form than
        // required. Verify that at least decoding it back produces the
        // same module.
        let module2 = Module::decode_from(out.as_slice())?;
        if module != module2 {
            return Err(format!(
                "Roundtrip mismatch. Old: {:#?}\nNew: {:#?}",
                module, module2
            )
            .into());
        }
    }
    Ok(())
}

fn main() {
    if cfg!(feature = "lazy-blob") {
        eprintln!("Warning: tests are being run in a lazy mode and will be incomplete.");
    }
    let tests = read_all_tests(&Path::new("tests").join("testsuite")).unwrap_or_else(|err| {
        panic!("{}", err);
    });
    run_tests(&Arguments::from_args(), tests, |test| {
        match run_test(&test.data) {
            Ok(()) => Outcome::Passed,
            Err(err) => Outcome::Failed {
                msg: Some(err.to_string()),
            },
        }
    })
    .exit()
}
<commit_msg>Include more tests for merged proposals<commit_after>use libtest_mimic::{run_tests, Arguments, Outcome, Test};
use std::error::Error;
use std::fs::{read_dir, read_to_string};
use std::path::Path;
use wasmbin::Module;
use wast::parser::{parse, ParseBuffer};
use wast::Wast;

const IGNORED_ERRORS: &[&str] = &[
    // We don't perform cross-section analysis.
    "function and code section have inconsistent lengths",
    "data count section required",
    "data count and data section have inconsistent lengths",
    // We allow non-zero table and memory IDs already.
    "zero flag expected",
    // We don't perform full function analysis either.
    "too many locals",
];

struct WasmTest {
    module: Vec<u8>,
    expect_result: Result<(), String>,
}

fn read_tests_from_file(path: &Path, dest: &mut Vec<Test<WasmTest>>) -> Result<(), Box<dyn Error>> {
    let src = read_to_string(path)?;
    let set_err_path_text = |mut err: wast::Error| {
        err.set_path(path);
        err.set_text(&src);
        err
    };
    let buf = ParseBuffer::new(&src).map_err(set_err_path_text)?;
    let wast = parse::<Wast>(&buf).map_err(set_err_path_text)?;
    for directive in wast.directives {
        let (span, mut module, expect_result) = match directive {
            // Expect errors for assert_malformed on binary or AST modules.
            wast::WastDirective::AssertMalformed {
                span,
                module: wast::QuoteModule::Module(module),
                message,
            }
            // Unlike other AssertInvalid, this is actually something we
            // check at the parsing time, because it's part of our
            // typesystem and doesn't require cross-function or
            // cross-section checks.
            | wast::WastDirective::AssertInvalid {
                span,
                module,
                message: message @ "invalid lane index",
            } => (span, module, Err(message)),
            // Expect successful parsing for regular AST modules.
            wast::WastDirective::Module(module) => (module.span, module, Ok(())),
            // Counter-intuitively, expect successful parsing for modules that are supposed
            // to error out at runtime or linking stage, too.
            wast::WastDirective::AssertInvalid { span, module, .. }
            | wast::WastDirective::AssertUnlinkable { span, module, .. } => (span, module, Ok(())),
            _ => {
                // Skipping interpreted
                continue;
            }
        };
        let (line, col) = span.linecol_in(&src);
        dest.push(Test {
            name: format!("{}:{}:{}", path.display(), line + 1, col + 1),
            kind: String::default(),
            is_ignored: match expect_result {
                Ok(()) => false,
                Err(err) => cfg!(feature = "lazy-blob") || IGNORED_ERRORS.contains(&err),
            },
            is_bench: false,
            data: WasmTest {
                module: module.encode()?,
                expect_result: expect_result.map_err(|err| err.to_owned()),
            },
        });
    }
    Ok(())
}

fn read_tests_from_dir(path: &Path, dest: &mut Vec<Test<WasmTest>>) -> Result<(), Box<dyn Error>> {
    for file in read_dir(path)? {
        let path = file?.path();
        if path.extension().map_or(false, |ext| ext == "wast") {
            read_tests_from_file(&path, dest).map_err(|err| {
                format!("could not read tests from file {}: {}", path.display(), err)
            })?;
        }
    }
    Ok(())
}

fn read_all_tests(path: &Path) -> Result<Vec<Test<WasmTest>>, Box<dyn Error>> {
    let mut tests = Vec::new();
    read_tests_from_dir(path, &mut tests)?;
    let proposals_dir = path.join("proposals");

    macro_rules! read_proposal_tests {
        ($name:literal) => {
            if cfg!(feature = $name) {
                read_proposal_tests!(unconditional $name)
            }
        };

        (unconditional $name:literal) => {
            read_tests_from_dir(&proposals_dir.join($name), &mut tests)?
        };
    }

    read_proposal_tests!("bulk-memory-operations");
    read_proposal_tests!(unconditional "multi-value");
    read_proposal_tests!(unconditional "mutable-global");
    read_proposal_tests!(unconditional "nontrapping-float-to-int-conversions");
    read_proposal_tests!(unconditional "sign-extension-ops");
    read_proposal_tests!("simd");
    read_proposal_tests!("tail-call");

    if tests.is_empty() {
        return Err("Couldn't find any tests. Did you run `git submodule update --init`?".into());
    }

    Ok(tests)
}

fn run_test(test: &WasmTest) -> Result<(), Box<dyn Error>> {
    let mut slice = test.module.as_slice();
    let module = match (Module::decode_from(&mut slice), &test.expect_result) {
        (Ok(_), Err(err)) => {
            return Err(format!(
                "Expected an invalid module definition with an error: {}",
                err
            )
            .into());
        }
        (Err(err), Ok(())) => {
            return Err(format!(
                "Expected a valid module definition, but got an error\nParsed part: {:02X?}\nUnparsed part: {:02X?}\nError: {:#}",
                &test.module[..test.module.len() - slice.len()],
                slice,
                err
            )
            .into());
        }
        (Ok(module), Ok(())) => module,
        (Err(_), Err(_)) => return Ok(()),
    };
    let out = module.encode_into(Vec::new())?;
    if out != test.module {
        // In the rare case that binary representation doesn't match, it
        // might be because the test uses longer LEB128 form than
        // required. Verify that at least decoding it back produces the
        // same module.
        let module2 = Module::decode_from(out.as_slice())?;
        if module != module2 {
            return Err(format!(
                "Roundtrip mismatch. Old: {:#?}\nNew: {:#?}",
                module, module2
            )
            .into());
        }
    }
    Ok(())
}

fn main() {
    if cfg!(feature = "lazy-blob") {
        eprintln!("Warning: tests are being run in a lazy mode and will be incomplete.");
    }
    let tests = read_all_tests(&Path::new("tests").join("testsuite")).unwrap_or_else(|err| {
        panic!("{}", err);
    });
    run_tests(&Arguments::from_args(), tests, |test| {
        match run_test(&test.data) {
            Ok(()) => Outcome::Passed,
            Err(err) => Outcome::Failed {
                msg: Some(err.to_string()),
            },
        }
    })
    .exit()
}
<|endoftext|>


<commit_before>use libc::{c_int, c_double, c_char, c_void};
use std::mem;

/// Typedef for initialization function.
pub type EnergyMonInitFn = unsafe extern fn(em: *mut EnergyMon) -> c_int;
/// Typedef for read function.
pub type EnergyMonReadTotalFn = unsafe extern fn(em: *mut EnergyMon) -> c_double;
/// Typedef for cleanup function.
pub type EnergyMonFinishFn = unsafe extern fn(em: *mut EnergyMon) -> c_int;
/// Typedef for function to get human-readable name.
pub type EnergyMonGetSourceFn = unsafe extern fn(*mut c_char) -> *mut c_char;

#[repr(C)]
/// Representation of native C struct `em_impl`.
pub struct EnergyMon {
    /// Native C function type signature that initializes the `EnergyMon`.
    pub finit: EnergyMonInitFn,
    /// Native C function type signature that reads energy data from the `EnergyMon`.
    pub fread: EnergyMonReadTotalFn,
    /// Native C function type signature that cleans up the `EnergyMon`.
    pub ffinish: EnergyMonFinishFn,
    /// Native C function type signature that gets the `EnergyMon`'s human-readable name.
    pub fsource: EnergyMonGetSourceFn,
    /// Native C pointer used by the underlying `EnergyMon` implementation for storing state.
    pub state: *mut c_void,
}

extern {
    /// Native C function that fills in the EnergyMon struct values and may allocate other
    /// resources.
    fn em_impl_get(em: *mut EnergyMon) -> c_int;
}

impl EnergyMon {
    /// Create an `EnergyMon` which represents a C struct.
    pub fn new() -> Result<EnergyMon, &'static str> {
        unsafe {
            let mut em: EnergyMon = mem::uninitialized();
            let result = em_impl_get(&mut em);
            if result != 0 {
                return Err("Failed to create energymon");
            }
            Ok(em)
        }
    }

    /// Initialize the `EnergyMon` - may allocate more resources and/or start threads.
    pub fn init(&mut self) -> Result<(), &'static str> {
        let result: i32 = unsafe {
            (self.finit)(self)
        };
        if result != 0 {
            return Err("Failed to initialize energymon");
        }
        Ok(())
    }

    /// Read the total energy from the `EnergyMon`.
    pub fn read(&mut self) -> f64 {
        unsafe {
            (self.fread)(self)
        }

    }

    /// Cleanup the `EnergyMon` - may deallocate associated resources and/or stop threads.
    pub fn finish(&mut self) -> Result<(), &'static str> {
        let result: i32 = unsafe {
            (self.ffinish)(self)
        };
        if result != 0 {
            return Err("Failed to cleanup energymon");
        }
        Ok(())
    }

    /// Utility function to get a human-readable name of the `EnergyMon`'s source.
    pub fn source(&mut self) -> Result<String, &'static str> {
        let mut buf = [0; 100];
        unsafe {
            let ret = (self.fsource)(buf.as_mut_ptr());
            if ret.is_null() {
                return Err("Failed to get energymon source");
            }
            let buf = mem::transmute::<&[c_char], &[u8]>(&buf);
            Ok(String::from_utf8_lossy(buf).into_owned())
        }
    }
}

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

    #[test]
    fn test_interface() {
        let mut em: EnergyMon = EnergyMon::new().unwrap();
        em.init().unwrap();
        let val = em.read();
        assert!(val >= 0.0);
        let source = em.source().unwrap();
        em.finish().unwrap();
        println!("Read {} from {}", val, source);
    }

}
<commit_msg>Specify types for all variables<commit_after>use libc::{c_int, c_double, c_char, c_void};
use std::mem;

/// Typedef for initialization function.
pub type EnergyMonInitFn = unsafe extern fn(em: *mut EnergyMon) -> c_int;
/// Typedef for read function.
pub type EnergyMonReadTotalFn = unsafe extern fn(em: *mut EnergyMon) -> c_double;
/// Typedef for cleanup function.
pub type EnergyMonFinishFn = unsafe extern fn(em: *mut EnergyMon) -> c_int;
/// Typedef for function to get human-readable name.
pub type EnergyMonGetSourceFn = unsafe extern fn(*mut c_char) -> *mut c_char;

#[repr(C)]
/// Representation of native C struct `em_impl`.
pub struct EnergyMon {
    /// Native C function type signature that initializes the `EnergyMon`.
    pub finit: EnergyMonInitFn,
    /// Native C function type signature that reads energy data from the `EnergyMon`.
    pub fread: EnergyMonReadTotalFn,
    /// Native C function type signature that cleans up the `EnergyMon`.
    pub ffinish: EnergyMonFinishFn,
    /// Native C function type signature that gets the `EnergyMon`'s human-readable name.
    pub fsource: EnergyMonGetSourceFn,
    /// Native C pointer used by the underlying `EnergyMon` implementation for storing state.
    pub state: *mut c_void,
}

extern {
    /// Native C function that fills in the EnergyMon struct values and may allocate other
    /// resources.
    fn em_impl_get(em: *mut EnergyMon) -> c_int;
}

impl EnergyMon {
    /// Create an `EnergyMon` which represents a C struct.
    pub fn new() -> Result<EnergyMon, &'static str> {
        unsafe {
            let mut em: EnergyMon = mem::uninitialized();
            let result: i32 = em_impl_get(&mut em);
            if result != 0 {
                return Err("Failed to create energymon");
            }
            Ok(em)
        }
    }

    /// Initialize the `EnergyMon` - may allocate more resources and/or start threads.
    pub fn init(&mut self) -> Result<(), &'static str> {
        let result: i32 = unsafe {
            (self.finit)(self)
        };
        if result != 0 {
            return Err("Failed to initialize energymon");
        }
        Ok(())
    }

    /// Read the total energy from the `EnergyMon`.
    pub fn read(&mut self) -> f64 {
        unsafe {
            (self.fread)(self)
        }

    }

    /// Cleanup the `EnergyMon` - may deallocate associated resources and/or stop threads.
    pub fn finish(&mut self) -> Result<(), &'static str> {
        let result: i32 = unsafe {
            (self.ffinish)(self)
        };
        if result != 0 {
            return Err("Failed to cleanup energymon");
        }
        Ok(())
    }

    /// Utility function to get a human-readable name of the `EnergyMon`'s source.
    pub fn source(&mut self) -> Result<String, &'static str> {
        const BUFSIZE: usize = 100;
        let mut buf: [c_char; BUFSIZE] = [0; BUFSIZE];
        unsafe {
            let ret: *mut c_char = (self.fsource)(buf.as_mut_ptr());
            if ret.is_null() {
                return Err("Failed to get energymon source");
            }
            let buf: &[u8] = mem::transmute::<&[c_char], &[u8]>(&buf);
            Ok(String::from_utf8_lossy(buf).into_owned())
        }
    }
}

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

    #[test]
    fn test_interface() {
        let mut em: EnergyMon = EnergyMon::new().unwrap();
        em.init().unwrap();
        let val = em.read();
        assert!(val >= 0.0);
        let source = em.source().unwrap();
        em.finish().unwrap();
        println!("Read {} from {}", val, source);
    }

}
<|endoftext|>


<commit_before>use sass::variable::SassVariable;

use std::borrow::Cow;
use std::borrow::Cow::Borrowed;
use std::collections::HashMap;

pub fn evaluate(original: &str, variables: &HashMap<String, String>) -> String {
    let vt = ValueTokenizer::new(original);
    original.split(' ').map(|original_part|
        match (*variables).get(original_part) {
            Some(v) => &v[..],
            None => original_part,
        }
    ).collect::<Vec<_>>().connect(" ")
}

#[derive(Debug, Clone, PartialEq)]
pub enum ValuePart<'a> {
    Variable(SassVariable<'a>),
    String(Cow<'a, str>),
}

#[derive(Debug)]
pub struct ValueTokenizer<'a> {
    value_str: &'a str,
    bytes: &'a [u8],
    offset: usize,
}

impl<'a> ValueTokenizer<'a> {
    pub fn new(value_str: &'a str) -> ValueTokenizer<'a> {
        ValueTokenizer {
            value_str: &value_str,
            bytes: &value_str.as_bytes(),
            offset: 0,
        }
    }

    pub fn parse(&mut self) -> Option<ValuePart<'a>> {
        let start = self.offset;
        let mut i = self.offset;
        let limit = self.value_str.len();

        while i < limit {
            i += 1;
        }
        self.offset = i;
        Some(ValuePart::String(Borrowed(&self.value_str[start..i])))
    }
}

impl<'a> Iterator for ValueTokenizer<'a> {
    type Item = ValuePart<'a>;

    fn next(&mut self) -> Option<ValuePart<'a>> {
        if self.offset < self.value_str.len() {
            return self.parse()
        }
        None
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use std::borrow::Cow::Borrowed;

    #[test]
    fn it_returns_string_part() {
        let mut vt = ValueTokenizer::new("foo");
        assert_eq!(Some(ValuePart::String(Borrowed(&"foo"))), vt.next());
        assert_eq!(None, vt.next());
    }
}
<commit_msg>Break up values on space<commit_after>use sass::variable::SassVariable;

use std::borrow::Cow;
use std::borrow::Cow::Borrowed;
use std::collections::HashMap;

pub fn evaluate(original: &str, variables: &HashMap<String, String>) -> String {
    let vt = ValueTokenizer::new(original);
    original.split(' ').map(|original_part|
        match (*variables).get(original_part) {
            Some(v) => &v[..],
            None => original_part,
        }
    ).collect::<Vec<_>>().connect(" ")
}

#[derive(Debug, Clone, PartialEq)]
pub enum ValuePart<'a> {
    Variable(SassVariable<'a>),
    String(Cow<'a, str>),
}

#[derive(Debug)]
pub struct ValueTokenizer<'a> {
    value_str: &'a str,
    bytes: &'a [u8],
    offset: usize,
}

impl<'a> ValueTokenizer<'a> {
    pub fn new(value_str: &'a str) -> ValueTokenizer<'a> {
        ValueTokenizer {
            value_str: &value_str,
            bytes: &value_str.as_bytes(),
            offset: 0,
        }
    }

    pub fn parse(&mut self) -> Option<ValuePart<'a>> {
        let start = self.offset;
        let mut i = self.offset;
        let limit = self.value_str.len();

        match self.bytes[i..limit].iter().position(|&c| c == b' ' ) {
            Some(pos) => { i += pos; },
            None      => { i = limit },
        }
        self.offset = i + 1;
        Some(ValuePart::String(Borrowed(&self.value_str[start..i])))
    }
}

impl<'a> Iterator for ValueTokenizer<'a> {
    type Item = ValuePart<'a>;

    fn next(&mut self) -> Option<ValuePart<'a>> {
        if self.offset < self.value_str.len() {
            return self.parse()
        }
        None
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use std::borrow::Cow::Borrowed;

    #[test]
    fn it_returns_string_part() {
        let mut vt = ValueTokenizer::new("foo");
        assert_eq!(Some(ValuePart::String(Borrowed(&"foo"))), vt.next());
        assert_eq!(None, vt.next());
    }

    #[test]
    fn it_returns_space_separated_string_parts() {
        let mut vt = ValueTokenizer::new("foo bar");
        assert_eq!(Some(ValuePart::String(Borrowed(&"foo"))), vt.next());
        assert_eq!(Some(ValuePart::String(Borrowed(&"bar"))), vt.next());
        assert_eq!(None, vt.next());
    }
}
<|endoftext|>


<commit_before>use json::JsonValue;

use Year;
use Degree;
use Course;
use get_json;

const base_url: &'static str = "https://www2.htw-dresden.de/~app/API/GetExams.php";

pub fn student_exams(year: Year, course: Course, degree: Degree) -> Option<Vec<Exam>> {
    let url = format!("{base}?StgJhr={year}&Stg={course}&AbSc={degree}",
                      base = base_url,
                      year = year,
                      course = course,
                      degree = degree.short());

    let json = get_json(&url);
    let exams = Exam::mult_from_json(json);
    Some(exams)
}

pub fn prof_exams(prof: &str) -> Option<Vec<Exam>> {
    let url = format!("{base}?Prof={prof}", base = base_url, prof = prof);
    let json = get_json(&url);
    let exams = Exam::mult_from_json(json);
    Some(exams)
}

#[derive(Debug)]
pub struct Exam {
    pub title: String,
    pub exam_type: String,
    pub study_branch: String,
    pub day: String,
    pub start_time: String,
    pub end_time: String,
    pub examiner: String,
    pub next_chance: String,
    pub rooms: Vec<String>,
}

impl Exam {
    fn mult_from_json(json: JsonValue) -> Vec<Exam> {
        let arr = match json {
            JsonValue::Array(arr) => arr,
            _ => panic!("Can't instantiate many exams from non-array in JSON."),
        };

        let mut exams: Vec<Exam> = Vec::new();
        for value in arr {
            let e = Exam::from_json(value);
            exams.push(e);
        }

        exams
    }

    fn from_json(json: JsonValue) -> Exam {
        Exam {
            // wat o.O
            title: String::from(json["Title"].as_str().unwrap()),
            exam_type: String::from(json["ExamType"].as_str().unwrap()),
            study_branch: String::from(json["StudyBranch"].as_str().unwrap()),
            day: String::from(json["Day"].as_str().unwrap()),
            start_time: String::from(json["StartTime"].as_str().unwrap()),
            end_time: String::from(json["EndTime"].as_str().unwrap()),
            examiner: String::from(json["Examiner"].as_str().unwrap()),
            next_chance: String::from(json["NextChance"].as_str().unwrap()),
            rooms: vec![String::new()], // TODO
        }
    }
}
<commit_msg>Add some documentation and examples to exams<commit_after>use json::JsonValue;

use Year;
use Degree;
use Course;
use get_json;

const base_url: &'static str = "https://www2.htw-dresden.de/~app/API/GetExams.php";

/// Returns a list of `Exam`s for a given student.
///
/// # Arguments
///
/// * `year` - Year
/// * `course` - Course identifier
/// * `degree` - Degree
///
/// # Example
///
/// ```
/// use htwdresden::Degree;
/// use htwdresden::exams::student_exams;
///
/// let exams = student_exams(2016, 121, Degree::Bachelor);
/// ```
pub fn student_exams(year: Year, course: Course, degree: Degree) -> Option<Vec<Exam>> {
    let url = format!("{base}?StgJhr={year}&Stg={course}&AbSc={degree}",
                      base = base_url,
                      year = year,
                      course = course,
                      degree = degree.short());

    let json = get_json(&url);
    let exams = Exam::mult_from_json(json);
    Some(exams)
}

/// Returns a list of `Exam`s for a given professor.
///
/// # Arguments
///
/// * `prof` - Professor name
///
/// # Example
///
/// ```
/// use htwdresden::exams::prof_exams;
///
/// let exams = prof_exams("Rennekamp");
/// ```
pub fn prof_exams(prof: &str) -> Option<Vec<Exam>> {
    let url = format!("{base}?Prof={prof}", base = base_url, prof = prof);
    let json = get_json(&url);
    let exams = Exam::mult_from_json(json);
    Some(exams)
}

#[derive(Debug)]
pub struct Exam {
    pub title: String,
    pub exam_type: String,
    pub study_branch: String,
    pub day: String,
    pub start_time: String,
    pub end_time: String,
    pub examiner: String,
    pub next_chance: String,
    pub rooms: Vec<String>,
}

impl Exam {
    fn mult_from_json(json: JsonValue) -> Vec<Exam> {
        let arr = match json {
            JsonValue::Array(arr) => arr,
            _ => panic!("Can't instantiate many exams from non-array in JSON."),
        };

        let mut exams: Vec<Exam> = Vec::new();
        for value in arr {
            let e = Exam::from_json(value);
            exams.push(e);
        }

        exams
    }

    fn from_json(json: JsonValue) -> Exam {
        Exam {
            // wat o.O
            title: String::from(json["Title"].as_str().unwrap()),
            exam_type: String::from(json["ExamType"].as_str().unwrap()),
            study_branch: String::from(json["StudyBranch"].as_str().unwrap()),
            day: String::from(json["Day"].as_str().unwrap()),
            start_time: String::from(json["StartTime"].as_str().unwrap()),
            end_time: String::from(json["EndTime"].as_str().unwrap()),
            examiner: String::from(json["Examiner"].as_str().unwrap()),
            next_chance: String::from(json["NextChance"].as_str().unwrap()),
            rooms: vec![String::new()], // TODO
        }
    }
}
<|endoftext|>


<commit_before>
<commit_msg>bracket-push: Added template to the stub file<commit_after>pub struct Brackets;

impl From<&'static str> for Brackets {
    fn from(input: &str) -> Self {
        unimplemented!("From the '{}' input construct a new Brackets struct", input);
    }
}

impl Brackets {
    pub fn are_balanced(&self) -> bool {
        unimplemented!("Check if your Brackets struct contains balanced brackets");
    }
}
<|endoftext|>


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

use std::error::Error;
use std::fs::File;
use std::io::prelude::*;
use std::panic;
use std::path::Path;
extern crate webrtc_sdp;

// Takes the filename of a file that contains SDP, and optionally the trailing
// flag --expect-failure.
// If --expect-failure is passed, then the program will exit with a successful
// exit code if the file fails to parse.
fn main() {
    let mut args = std::env::args();
    let filename = match args.nth(1) {
        None => {
            eprintln!("Missing file name argument!");
            std::process::exit(1);
        }
        Some(x) => x,
    };

    let path = Path::new(filename.as_str());
    let display = path.display();

    let mut file = match File::open(&path) {
        Err(why) => panic!("Failed to open {}: {}", display, why.description()),
        Ok(file) => file,
    };

    let mut s = String::new();
    match file.read_to_string(&mut s) {
        Err(why) => panic!("Couldn't read {}: {}", display, why.description()),
        Ok(s) => s,
    };

    // Hook up the panic handler if it is expected to fail to parse
    let expect_failure = if let Some(x) = args.next() {
        if x.to_lowercase() != "--expect-failure" {
            eprintln!("Extra arguments passed!");
            std::process::exit(1);
        }
        panic::set_hook(Box::new(|_| {
            println!("Exited with failure, as expected.");
            std::process::exit(0);
        }));
        true
    } else {
        false
    };

    // Remove comment lines
    let s = s
        .lines()
        .filter(|&l| !l.trim_start().starts_with(';'))
        .collect::<Vec<&str>>()
        .join("\r\n");

    if let Err(why) = webrtc_sdp::parse_sdp(&s, true) {
        panic!("Failed to parse SDP with error: {}", why);
    }

    if expect_failure {
        eprintln!("Successfully parsed SDP that was expected to fail. You may need to update the example expectations.");
        std::process::exit(1);
    }
    println!("Successfully parsed SDP");
}
<commit_msg>Error::description is deprecated, remove its use in the example… (#212)<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use std::fs::File;
use std::io::prelude::*;
use std::panic;
use std::path::Path;
extern crate webrtc_sdp;

// Takes the filename of a file that contains SDP, and optionally the trailing
// flag --expect-failure.
// If --expect-failure is passed, then the program will exit with a successful
// exit code if the file fails to parse.
fn main() {
    let mut args = std::env::args();
    let filename = match args.nth(1) {
        None => {
            eprintln!("Missing file name argument!");
            std::process::exit(1);
        }
        Some(x) => x,
    };

    let path = Path::new(filename.as_str());
    let display = path.display();

    let mut file = match File::open(&path) {
        Err(why) => panic!("Failed to open {}: {}", display, why),
        Ok(file) => file,
    };

    let mut s = String::new();
    match file.read_to_string(&mut s) {
        Err(why) => panic!("Couldn't read {}: {}", display, why),
        Ok(s) => s,
    };

    // Hook up the panic handler if it is expected to fail to parse
    let expect_failure = if let Some(x) = args.next() {
        if x.to_lowercase() != "--expect-failure" {
            eprintln!("Extra arguments passed!");
            std::process::exit(1);
        }
        panic::set_hook(Box::new(|_| {
            println!("Exited with failure, as expected.");
            std::process::exit(0);
        }));
        true
    } else {
        false
    };

    // Remove comment lines
    let s = s
        .lines()
        .filter(|&l| !l.trim_start().starts_with(';'))
        .collect::<Vec<&str>>()
        .join("\r\n");

    if let Err(why) = webrtc_sdp::parse_sdp(&s, true) {
        panic!("Failed to parse SDP with error: {}", why);
    }

    if expect_failure {
        eprintln!("Successfully parsed SDP that was expected to fail. You may need to update the example expectations.");
        std::process::exit(1);
    }
    println!("Successfully parsed SDP");
}
<|endoftext|>


<commit_before>#![allow(unused_variables)]
use std::collections::HashMap;

use lisp::lex::Token;

use lisp;

pub struct Environment{
    map : HashMap<String, Token>
}

impl Environment {

    pub fn new() -> Environment {
        Environment {
            map : HashMap::new()
        }
    }

    // Stub for default Environment
    pub fn default() -> Environment {
        let mut env = Environment::new();
        env.map.insert("pi".to_string(), Token::Number(3.14));

        env.map.insert("+".to_string(), Token::Proc(Environment::add));
        env.map.insert("-".to_string(), Token::Proc(Environment::sub));
        env.map.insert("*".to_string(), Token::Proc(Environment::mul));
        env.map.insert("/".to_string(), Token::Proc(Environment::div));

        env
    }

    pub fn add(args : Token) -> Token {
        match args {
            Token::List(v) => {
                let mut sum : f32 = 0.0;
                for arg in v {
                    sum += match arg {
                        Token::Number(n) => n,
                        _ => panic!("Cannot add")
                    }
                }
                Token::Number(sum)
            },
            _ => Token::Nil
        }
    }

    pub fn sub(args : Token) -> Token {
        match args {
            Token::List(mut v) => {
                let mut result : f32 = match v.remove(0) {
                    Token::Number(n) => n,
                    _ => panic!("Cannot sub: not a number")
                };

                for arg in v {
                    result -= match arg {
                        Token::Number(n) => n,
                        _ => panic!("Cannot sub: not a number")
                    }
                }

                Token::Number(result)
            },
            _ => Token::Nil
        }
    }

    pub fn mul(args : Token) -> Token {
        match args {
            Token::List(v) => {
                let mut mul : f32 = 1.0;
                for arg in v {
                    mul *= match arg {
                        Token::Number(n) => n,
                        _ => panic!("Cannot add")
                    }
                }
                Token::Number(mul)
            },
            _ => Token::Nil
        }
    }

    pub fn div(args : Token) -> Token {
        match args {
            Token::List(mut v) => {
                let mut div : f32 = match v.remove(0) {
                    Token::Number(n) => n,
                    _ => panic!("Cannot div: not a number")
                };

                for arg in v {
                    div /= match arg {
                        Token::Number(n) if n != 0.0 => n,
                        _ => panic!("Cannot div: not a number")
                    }
                }

                Token::Number(div)
            },
            _ => Token::Nil
        }
    }
}

pub fn eval(token : Token, env : &Environment) -> Token {

    match token {

        Token::Symbol(name) => {
            // check in the current env, return only values
            // missing Symbol?
            match env.map.get(&name).unwrap() {
                &Token::Number(n) => Token::Number(n),
                _ => Token::Nil
            }
        },
        Token::Number(n) => Token::Number(n),

        Token::List(mut tokens) => {
            // This branch does some heavy lifting
            // match on the first token then take action
            let first = tokens.remove(0);

            if let Token::Symbol(name) = first {

                if let &Token::Proc(f) = env.map.get(&name).unwrap() {
                    // eval each of the following tokens in the list
                    let mut args : Vec<Token> = Vec::new();

                    for arg in tokens {
                        args.push(eval(arg, env));
                    }
                    // executes the function with evaluated arguments
                    f(Token::List(args))

                } else {
                    // TODO: some keyword implementations here
                    let result : Token = match name.as_ref() {
                        "quote" => {
                            // returns the following token literally (should it be a symbol?)
                            tokens.remove(0)
                        },
                        "if" => {
                            Token::Nil
                        },
                        "set!" => {
                            Token::Nil
                        }

                        _ => Token::Nil
                    };

                    result
                }

            } else {
                // first is not a symbol, it's a regular list
                // TODO: should put back the first element
                Token::Nil
            }
        },

        _ => panic!("Unrecognized token") //Token::Nil
    }
}

// Utility function
fn parse_and_eval(input : &str) -> Token {
    let mut str_vec = lisp::lex::tokenize(input);
    let tokens = lisp::lex::parse_tree_from_tokens(&mut str_vec);
    lisp::env::eval(tokens.unwrap(), &lisp::env::Environment::default())
}

#[test]
fn eval_returns_pi() {
    let t = Token::Symbol("pi".to_string());
    let env = Environment::default();

    let res = match eval(t, &env) {
        Token::Number(n) => n,
        _ => 0.0
    };

    assert_eq!(res, 3.14);
}

#[test]
fn eval_sum() {
    let args = vec![Token::Symbol("+".to_string()),
                    Token::Number(2.0),
                    Token::Number(1.0)];

    let t = Token::List(args);
    let env = Environment::default();

    let res = match eval(t, &env) {
        Token::Number(n) => n,
        _ => 0.0
    };

    assert_eq!(res, 3.0);

    let args = vec![Token::Symbol("+".to_string()),
                    Token::Number(3.0),
                    Token::Number(2.0),
                    Token::Number(1.0)];

    let t = Token::List(args);
    let env = Environment::default();

    let res = match eval(t, &env) {
        Token::Number(n) => n,
        _ => 0.0
    };

    assert_eq!(res, 6.0);
}

#[test]
fn eval_sub() {
    let args = vec![Token::Symbol("-".to_string()),
                    Token::Number(3.0),
                    Token::Number(2.0),
                    Token::Number(1.0)];

    let t = Token::List(args);
    let env = Environment::default();

    let res = match eval(t, &env) {
        Token::Number(n) => n,
        _ => -10.0
    };

    assert_eq!(res, 0.0);
}
<commit_msg>implemented 'set!'<commit_after>#![allow(unused_variables)]
use std::collections::HashMap;

use lisp::lex::Token;

use lisp;

pub struct Environment{
    map : HashMap<String, Token>
}

impl Environment {

    pub fn new() -> Environment {
        Environment {
            map : HashMap::new()
        }
    }

    // Stub for default Environment
    pub fn default() -> Environment {
        let mut env = Environment::new();
        env.map.insert("pi".to_string(), Token::Number(3.14));

        env.map.insert("+".to_string(), Token::Proc(Environment::add));
        env.map.insert("-".to_string(), Token::Proc(Environment::sub));
        env.map.insert("*".to_string(), Token::Proc(Environment::mul));
        env.map.insert("/".to_string(), Token::Proc(Environment::div));

        env
    }

    pub fn add(args : Token) -> Token {
        match args {
            Token::List(v) => {
                let mut sum : f32 = 0.0;
                for arg in v {
                    sum += match arg {
                        Token::Number(n) => n,
                        _ => panic!("Cannot add")
                    }
                }
                Token::Number(sum)
            },
            _ => Token::Nil
        }
    }

    pub fn sub(args : Token) -> Token {
        match args {
            Token::List(mut v) => {
                let mut result : f32 = match v.remove(0) {
                    Token::Number(n) => n,
                    _ => panic!("Cannot sub: not a number")
                };

                for arg in v {
                    result -= match arg {
                        Token::Number(n) => n,
                        _ => panic!("Cannot sub: not a number")
                    }
                }

                Token::Number(result)
            },
            _ => Token::Nil
        }
    }

    pub fn mul(args : Token) -> Token {
        match args {
            Token::List(v) => {
                let mut mul : f32 = 1.0;
                for arg in v {
                    mul *= match arg {
                        Token::Number(n) => n,
                        _ => panic!("Cannot add")
                    }
                }
                Token::Number(mul)
            },
            _ => Token::Nil
        }
    }

    pub fn div(args : Token) -> Token {
        match args {
            Token::List(mut v) => {
                let mut div : f32 = match v.remove(0) {
                    Token::Number(n) => n,
                    _ => panic!("Cannot div: not a number")
                };

                for arg in v {
                    div /= match arg {
                        Token::Number(n) if n != 0.0 => n,
                        _ => panic!("Cannot div: not a number")
                    }
                }

                Token::Number(div)
            },
            _ => Token::Nil
        }
    }
}

pub fn eval(token : Token, env : &mut Environment) -> Token {

    match token {

        Token::Symbol(name) => {
            match *env.map.get(&name).unwrap() {
                Token::Number(n) => Token::Number(n),
                Token::Symbol(ref n) => Token::Symbol(n.to_string()),
                _ => Token::Nil
            }
        },
        Token::Number(n) => Token::Number(n),

        Token::List(mut tokens) => {
            // This branch does some heavy lifting
            // match on the first token then take action
            let first = tokens.remove(0);

            if let Token::Symbol(name) = first {

                if let Some(&Token::Proc(f)) = env.map.get(&name) {
                    // eval each of the following tokens in the list
                    let mut args : Vec<Token> = Vec::new();

                    for arg in tokens {
                        args.push(eval(arg, env));
                    }
                    // executes the function with evaluated arguments
                    f(Token::List(args))

                } else {
                    // TODO: some keyword implementations here
                    let result : Token = match name.as_ref() {
                        "quote" => {
                            // returns the following token literally (should it be a symbol?)
                            tokens.remove(0)
                        },
                        "if" => {
                            Token::Nil
                        },
                        "set!" => {
                            // usage: set! var_name expression
                            if let Token::Symbol(name) = tokens.remove(0) {
                                let t = eval(tokens.remove(0), env);
                                env.map.insert(name, t);
                            }

                            Token::Nil
                        }

                        _ => Token::Nil
                    };

                    result
                }

            } else {
                // first is not a symbol, it's a regular list
                // TODO: should put back the first element
                Token::Nil
            }
        },

        _ => panic!("Unrecognized token") //Token::Nil
    }
}

// Utility function
fn parse_and_eval(input : &str) -> Token {
    let mut str_vec = lisp::lex::tokenize(input);
    let tokens = lisp::lex::parse_tree_from_tokens(&mut str_vec);
    lisp::env::eval(tokens.unwrap(), &mut lisp::env::Environment::default())
}

#[test]
fn eval_returns_pi() {
    let t = Token::Symbol("pi".to_string());
    let env = Environment::default();

    let res = match eval(t, &env) {
        Token::Number(n) => n,
        _ => 0.0
    };

    assert_eq!(res, 3.14);
}

#[test]
fn eval_sum() {
    let args = vec![Token::Symbol("+".to_string()),
                    Token::Number(2.0),
                    Token::Number(1.0)];

    let t = Token::List(args);
    let env = Environment::default();

    let res = match eval(t, &env) {
        Token::Number(n) => n,
        _ => 0.0
    };

    assert_eq!(res, 3.0);

    let args = vec![Token::Symbol("+".to_string()),
                    Token::Number(3.0),
                    Token::Number(2.0),
                    Token::Number(1.0)];

    let t = Token::List(args);
    let env = Environment::default();

    let res = match eval(t, &env) {
        Token::Number(n) => n,
        _ => 0.0
    };

    assert_eq!(res, 6.0);
}

#[test]
fn eval_sub() {
    let args = vec![Token::Symbol("-".to_string()),
                    Token::Number(3.0),
                    Token::Number(2.0),
                    Token::Number(1.0)];

    let t = Token::List(args);
    let env = Environment::default();

    let res = match eval(t, &env) {
        Token::Number(n) => n,
        _ => -10.0
    };

    assert_eq!(res, 0.0);
}
<|endoftext|>