<commit_before>// The MIT License (MIT)
//
// Copyright (c) 2013 Jeremy Letang (letang.jeremy@gmail.com)
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of
// this software and associated documentation files (the "Software"), to deal in
// the Software without restriction, including without limitation the rights to
// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
// the Software, and to permit persons to whom the Software is furnished to do so,
// subject to the following conditions:

// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.

// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

/*!
# Rust-PortAudio

__Portaudio__ bindings for Rust

PortAudio provides a uniform application programming interface (API) across all supported platforms.
You can think of the PortAudio library as a wrapper that converts calls to the PortAudio API into calls to platform-specific native audio APIs.
Operating systems often offer more than one native audio API and some APIs (such as JACK) may be available on multiple target operating systems.
PortAudio supports all the major native audio APIs on each supported platform.

# Installation

You must install on your computer the Portaudio libraries who is used for the binding.

Portaudio is available with package management tools on Linux, or brew on Mac OS.

You can download it directly from the website : [portaudio](http://www.portaudio.com/download.html)

Then clone the repo and build the library with the following command at the root of the __rust-portaudio__ repository.

__rust-portaudio__ is build with the rustpkg tool :

```Shell
> rustpkg build portaudio
```

*/

#[link(name = "portaudio",
       vers = "0.0.1",
       package_id = "portaudio",
       author = "letang.jeremy@gmail.com",
       uuid = "57224177-873F-43C2-8F44-A41D501C1A63",
       url = "http://https://github.com/JeremyLetang/rust-portaudio")];

#[comment = "Portaudio binding for Rust"];
// #[license = "Zlib/png"];
#[crate_type = "lib"];

#[feature(globs, managed_boxes)];
#[warn(missing_doc)];

extern mod extra;

#[cfg(target_os="macos")]
#[cfg(target_os="linux")]
#[cfg(target_os="win32")]
mod c_library {
    #[link_args="-lportaudio"]
    extern {}
}

pub mod types;
pub mod pa;

#[doc(hidden)]
pub mod user_traits;
#[doc(hidden)]
#[cfg(target_os="macos")]
pub mod mac_core;
//pub mod asio;
#[doc(hidden)]
pub mod ffi;
<commit_msg>update to last rust<commit_after>// The MIT License (MIT)
//
// Copyright (c) 2013 Jeremy Letang (letang.jeremy@gmail.com)
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of
// this software and associated documentation files (the "Software"), to deal in
// the Software without restriction, including without limitation the rights to
// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
// the Software, and to permit persons to whom the Software is furnished to do so,
// subject to the following conditions:

// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.

// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

/*!
# Rust-PortAudio

__Portaudio__ bindings for Rust

PortAudio provides a uniform application programming interface (API) across all supported platforms.
You can think of the PortAudio library as a wrapper that converts calls to the PortAudio API into calls to platform-specific native audio APIs.
Operating systems often offer more than one native audio API and some APIs (such as JACK) may be available on multiple target operating systems.
PortAudio supports all the major native audio APIs on each supported platform.

# Installation

You must install on your computer the Portaudio libraries who is used for the binding.

Portaudio is available with package management tools on Linux, or brew on Mac OS.

You can download it directly from the website : [portaudio](http://www.portaudio.com/download.html)

Then clone the repo and build the library with the following command at the root of the __rust-portaudio__ repository.

__rust-portaudio__ is build with the rustpkg tool :

```Shell
> rustpkg build portaudio
```

*/

#[link(name = "portaudio",
       vers = "0.0.1",
       package_id = "portaudio",
       author = "letang.jeremy@gmail.com",
       uuid = "57224177-873F-43C2-8F44-A41D501C1A63",
       url = "http://https://github.com/JeremyLetang/rust-portaudio")];

#[comment = "Portaudio binding for Rust"];
// #[license = "Zlib/png"];
#[crate_type = "lib"];

#[feature(globs, managed_boxes)];
#[warn(missing_doc)];

extern mod extra;

#[cfg(target_os="macos")]
#[cfg(target_os="linux")]
#[cfg(target_os="win32")]
mod c_library {
    #[link(name = "portaudio")]
    extern {}
}

pub mod types;
pub mod pa;

#[doc(hidden)]
pub mod user_traits;
#[doc(hidden)]
#[cfg(target_os="macos")]
pub mod mac_core;
//pub mod asio;
#[doc(hidden)]
pub mod ffi;
<|endoftext|>


<commit_before>// The MIT License (MIT)
//
// Copyright (c) 2013 Jeremy Letang (letang.jeremy@gmail.com)
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of
// this software and associated documentation files (the "Software"), to deal in
// the Software without restriction, including without limitation the rights to
// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
// the Software, and to permit persons to whom the Software is furnished to do so,
// subject to the following conditions:

// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.

// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

/*!
# Rust-PortAudio

__Portaudio__ bindings for Rust

PortAudio provides a uniform application programming interface (API) across all supported platforms.
You can think of the PortAudio library as a wrapper that converts calls to the PortAudio API into calls to platform-specific native audio APIs.
Operating systems often offer more than one native audio API and some APIs (such as JACK) may be available on multiple target operating systems.
PortAudio supports all the major native audio APIs on each supported platform.

# Installation

You must install on your computer the Portaudio libraries who is used for the binding.

Portaudio is available with package management tools on Linux, or brew on Mac OS.

You can download it directly from the website : [portaudio](http://www.portaudio.com/download.html)

Then clone the repo and build the library with the following command at the root of the __rust-portaudio__ repository.

__rust-portaudio__ is build with the rustpkg tool :

```Shell
> rustpkg build portaudio
```

*/

#[crate_id = "portaudio#0.1"];

#[comment = "Portaudio binding for Rust"];
// #[license = "Zlib/png"];
#[crate_type = "dylib"];
#[crate_type = "rlib"];

#[feature(globs)];
#[warn(missing_doc)];
#[allow(dead_code)];

extern crate extra;

#[cfg(target_os="macos")]
#[cfg(target_os="linux")]
#[cfg(target_os="win32")]
mod c_library {
    #[link(name = "portaudio")]
    extern {}
}

pub mod types;
pub mod pa;

//#[doc(hidden)]
//pub mod user_traits;
//#[doc(hidden)]
//#[cfg(target_os="macos")]
//pub mod mac_core;
//pub mod asio;
#[doc(hidden)]
mod ffi;
<commit_msg>remove warning visible_private_types<commit_after>// The MIT License (MIT)
//
// Copyright (c) 2013 Jeremy Letang (letang.jeremy@gmail.com)
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of
// this software and associated documentation files (the "Software"), to deal in
// the Software without restriction, including without limitation the rights to
// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
// the Software, and to permit persons to whom the Software is furnished to do so,
// subject to the following conditions:

// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.

// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

/*!
# Rust-PortAudio

__Portaudio__ bindings for Rust

PortAudio provides a uniform application programming interface (API) across all
supported platforms.  You can think of the PortAudio library as a wrapper that
converts calls to the PortAudio API into calls to platform-specific native audio
APIs. Operating systems often offer more than one native audio API and some APIs
(such as JACK) may be available on multiple target operating systems.
PortAudio supports all the major native audio APIs on each supported platform.

# Installation

You must install on your computer the Portaudio libraries who is used for
the binding.

Portaudio is available with package management tools on Linux, or brew on Mac OS.

You can download it directly from the website :
[portaudio](http://www.portaudio.com/download.html)

Then clone the repo and build the library with the following command at the root
of the __rust-portaudio__ repository.

__rust-portaudio__ is build with the rustpkg tool :

```Shell
> rustpkg build portaudio
```

*/

#[crate_id = "portaudio#0.1"];

#[comment = "Portaudio binding for Rust"];
// #[license = "Zlib/png"];
#[crate_type = "dylib"];
#[crate_type = "rlib"];

#[feature(globs)];
#[warn(missing_doc)];
#[allow(dead_code)];
#[allow(visible_private_types)];

extern crate extra;

#[cfg(target_os="macos")]
#[cfg(target_os="linux")]
#[cfg(target_os="win32")]
mod c_library {
    #[link(name = "portaudio")]
    extern {}
}

pub mod types;
pub mod pa;

//#[doc(hidden)]
//pub mod user_traits;
//#[doc(hidden)]
//#[cfg(target_os="macos")]
//pub mod mac_core;
//pub mod asio;
#[doc(hidden)]
mod ffi;
<|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 https://mozilla.org/MPL/2.0/.

//! Printer for displaying crate as a graoh.

use std::fmt::{self, Write};

use petgraph::{
    graph::NodeIndex,
    visit::{IntoNodeReferences, NodeRef},
};
use ra_ap_hir as hir;
use ra_ap_ide::RootDatabase;

use crate::{
    graph::{
        edge::{Edge, EdgeKind},
        node::{visibility::NodeVisibility, Node, NodeKind},
        util, Graph,
    },
    theme::graph::{edge_styles, node_styles},
};

const INDENTATION: &str = "    ";

#[derive(Clone, Debug)]
pub struct Options {
    pub layout: String,
    pub full_paths: bool,
}

pub struct Printer {
    options: Options,
    member_krate: String,
}

impl Printer {
    pub fn new(options: Options, member_krate: hir::Crate, db: &RootDatabase) -> Self {
        let member_krate = util::krate_name(member_krate, db);
        Self {
            options,
            member_krate,
        }
    }

    pub fn fmt(
        &self,
        f: &mut dyn fmt::Write,
        graph: &Graph,
        start_node_idx: NodeIndex,
    ) -> Result<(), anyhow::Error> {
        let root_node = &graph[start_node_idx];
        let crate_name = root_node.display_name();
        let layout_name = &self.options.layout[..];

        writeln!(f, "digraph {{")?;

        writeln!(f)?;

        indoc::writedoc!(
            f,
            r#"
            {i}graph [
            {i}    label={label:?},
            {i}    labelloc=t,

            {i}    pad=0.4,

            {i}    // Consider rendering the graph using a different layout algorithm, such as:
            {i}    // [dot, neato, twopi, circo, fdp, sfdp]
            {i}    layout={layout},
            {i}    overlap=false,
            {i}    splines="line",
            {i}    rankdir=LR,

            {i}    fontname="Helvetica",
            {i}    fontsize="36",
            {i}];
            "#,
            i = INDENTATION,
            label = crate_name,
            layout = layout_name,
        )?;

        writeln!(f)?;

        indoc::writedoc!(
            f,
            r#"
            {i}node [
            {i}    fontname="monospace",
            {i}    fontsize="10",
            {i}    shape="record",
            {i}    style="filled",
            {i}];
            "#,
            i = INDENTATION,
        )?;

        writeln!(f)?;

        indoc::writedoc!(
            f,
            r#"
            {i}edge [
            {i}    fontname="monospace",
            {i}    fontsize="10",
            {i}];
            "#,
            i = INDENTATION,
        )?;

        writeln!(f)?;

        self.fmt_nodes(f, graph)?;

        writeln!(f)?;

        self.fmt_edges(f, graph)?;

        writeln!(f)?;

        writeln!(f, "}}")?;

        Ok(())
    }

    fn fmt_nodes(&self, f: &mut dyn fmt::Write, graph: &Graph) -> fmt::Result {
        for node_ref in graph.node_references() {
            let node: &Node = node_ref.weight();

            let id = node.path.join("::");
            let kind = node.kind.display_name().unwrap_or("orphan");

            let label = self.node_label(node)?;
            let attributes = self.node_attributes(node);

            writeln!(
                f,
                r#"{i}{id:?} [label={label:?}{attributes}]; // {kind:?} node"#,
                i = INDENTATION,
                id = id,
                label = label,
                attributes = attributes,
                kind = kind,
            )?;
        }

        Ok(())
    }

    fn fmt_edges(&self, f: &mut dyn fmt::Write, graph: &Graph) -> fmt::Result {
        for edge_idx in graph.edge_indices() {
            let edge = &graph[edge_idx];
            let (source_idx, target_idx) = graph.edge_endpoints(edge_idx).unwrap();

            let source_id = graph[source_idx].path.join("::");
            let target_id = graph[target_idx].path.join("::");

            let kind = edge.kind.display_name();

            let label = self.edge_label(edge);
            let attributes = self.edge_attributes(edge);

            writeln!(
                f,
                r#"{i}{source:?} -> {target:?} [label={label:?}{attributes}]; // {kind:?} edge"#,
                i = INDENTATION,
                source = source_id,
                target = target_id,
                label = label,
                attributes = attributes,
                kind = kind,
            )?;
        }

        Ok(())
    }

    fn node_label(&self, node: &Node) -> Result<String, fmt::Error> {
        let mut label = String::new();

        self.fmt_node_header(&mut label, node)?;
        write!(&mut label, "|")?;
        self.fmt_node_body(&mut label, node)?;

        Ok(label)
    }

    fn fmt_node_header(&self, f: &mut dyn fmt::Write, node: &Node) -> fmt::Result {
        let is_external = node.krate != Some(self.member_krate.clone());

        let visibility = match &node.visibility {
            Some(visibility) => {
                if is_external {
                    Some("external".to_owned())
                } else if node.kind == NodeKind::Crate {
                    None
                } else {
                    Some(format!("{}", visibility))
                }
            }
            None => Some("orphan".to_owned()),
        };

        let kind = node.kind.display_name().unwrap_or("mod");

        if let Some(visibility) = visibility {
            write!(f, "{} ", visibility)?;
        }

        write!(f, "{}", kind)
    }

    fn fmt_node_body(&self, f: &mut dyn fmt::Write, node: &Node) -> fmt::Result {
        let path = if self.options.full_paths {
            // If we explicitly want full paths, return it unaltered:
            node.path.join("::")
        } else if node.path.len() > 1 {
            // Otherwise try to drop the crate-name from the path:
            node.path[1..].join("::")
        } else {
            node.path.join("::")
        };

        write!(f, "{}", path)
    }

    fn node_attributes(&self, node: &Node) -> String {
        let styles = node_styles();

        let style = match &node.kind {
            NodeKind::Crate => styles.krate,
            NodeKind::Orphan => styles.orphan,
            _ => match &node.visibility {
                Some(visibility) => match visibility {
                    NodeVisibility::Crate => styles.visibility.pub_crate,
                    NodeVisibility::Module(_) => styles.visibility.pub_module,
                    NodeVisibility::Private => styles.visibility.pub_private,
                    NodeVisibility::Public => styles.visibility.pub_global,
                    NodeVisibility::Super => styles.visibility.pub_super,
                },
                None => styles.visibility.pub_global,
            },
        };

        format!(r#", fillcolor="{}""#, style.fill_color)
    }

    fn edge_label(&self, edge: &Edge) -> String {
        edge.kind.display_name().to_owned()
    }

    fn edge_attributes(&self, edge: &Edge) -> String {
        let styles = edge_styles();

        let style = match edge.kind {
            EdgeKind::Uses { .. } => styles.uses,
            EdgeKind::Owns => styles.owns,
        };

        format!(r#", color="{}", style="{}""#, style.color, style.stroke)
    }
}
<commit_msg>Ignore "uses" edges in graph layout<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 https://mozilla.org/MPL/2.0/.

//! Printer for displaying crate as a graoh.

use std::fmt::{self, Write};

use petgraph::{
    graph::NodeIndex,
    visit::{IntoNodeReferences, NodeRef},
};
use ra_ap_hir as hir;
use ra_ap_ide::RootDatabase;

use crate::{
    graph::{
        edge::{Edge, EdgeKind},
        node::{visibility::NodeVisibility, Node, NodeKind},
        util, Graph,
    },
    theme::graph::{edge_styles, node_styles},
};

const INDENTATION: &str = "    ";

#[derive(Clone, Debug)]
pub struct Options {
    pub layout: String,
    pub full_paths: bool,
}

pub struct Printer {
    options: Options,
    member_krate: String,
}

impl Printer {
    pub fn new(options: Options, member_krate: hir::Crate, db: &RootDatabase) -> Self {
        let member_krate = util::krate_name(member_krate, db);
        Self {
            options,
            member_krate,
        }
    }

    pub fn fmt(
        &self,
        f: &mut dyn fmt::Write,
        graph: &Graph,
        start_node_idx: NodeIndex,
    ) -> Result<(), anyhow::Error> {
        let root_node = &graph[start_node_idx];
        let crate_name = root_node.display_name();
        let layout_name = &self.options.layout[..];

        writeln!(f, "digraph {{")?;

        writeln!(f)?;

        indoc::writedoc!(
            f,
            r#"
            {i}graph [
            {i}    label={label:?},
            {i}    labelloc=t,

            {i}    pad=0.4,

            {i}    // Consider rendering the graph using a different layout algorithm, such as:
            {i}    // [dot, neato, twopi, circo, fdp, sfdp]
            {i}    layout={layout},
            {i}    overlap=false,
            {i}    splines="line",
            {i}    rankdir=LR,

            {i}    fontname="Helvetica",
            {i}    fontsize="36",
            {i}];
            "#,
            i = INDENTATION,
            label = crate_name,
            layout = layout_name,
        )?;

        writeln!(f)?;

        indoc::writedoc!(
            f,
            r#"
            {i}node [
            {i}    fontname="monospace",
            {i}    fontsize="10",
            {i}    shape="record",
            {i}    style="filled",
            {i}];
            "#,
            i = INDENTATION,
        )?;

        writeln!(f)?;

        indoc::writedoc!(
            f,
            r#"
            {i}edge [
            {i}    fontname="monospace",
            {i}    fontsize="10",
            {i}];
            "#,
            i = INDENTATION,
        )?;

        writeln!(f)?;

        self.fmt_nodes(f, graph)?;

        writeln!(f)?;

        self.fmt_edges(f, graph)?;

        writeln!(f)?;

        writeln!(f, "}}")?;

        Ok(())
    }

    fn fmt_nodes(&self, f: &mut dyn fmt::Write, graph: &Graph) -> fmt::Result {
        for node_ref in graph.node_references() {
            let node: &Node = node_ref.weight();

            let id = node.path.join("::");
            let kind = node.kind.display_name().unwrap_or("orphan");

            let label = self.node_label(node)?;
            let attributes = self.node_attributes(node);

            writeln!(
                f,
                r#"{i}{id:?} [label={label:?}{attributes}]; // {kind:?} node"#,
                i = INDENTATION,
                id = id,
                label = label,
                attributes = attributes,
                kind = kind,
            )?;
        }

        Ok(())
    }

    fn fmt_edges(&self, f: &mut dyn fmt::Write, graph: &Graph) -> fmt::Result {
        for edge_idx in graph.edge_indices() {
            let edge = &graph[edge_idx];
            let (source_idx, target_idx) = graph.edge_endpoints(edge_idx).unwrap();

            let source = graph[source_idx].path.join("::");
            let target = graph[target_idx].path.join("::");

            let kind = edge.kind.display_name();

            let label = self.edge_label(edge);
            let attributes = self.edge_attributes(edge);

            let constraint = match edge.kind {
                EdgeKind::Uses => "[constraint=false]",
                EdgeKind::Owns => "[constraint=true]",
            };

            writeln!(
                f,
                r#"{i}{source:?} -> {target:?} [label={label:?}{attributes}] {constraint}; // {kind:?} edge"#,
                i = INDENTATION,
                source = source,
                target = target,
                label = label,
                attributes = attributes,
                kind = kind,
                constraint = constraint
            )?;
        }

        Ok(())
    }

    fn node_label(&self, node: &Node) -> Result<String, fmt::Error> {
        let mut label = String::new();

        self.fmt_node_header(&mut label, node)?;
        write!(&mut label, "|")?;
        self.fmt_node_body(&mut label, node)?;

        Ok(label)
    }

    fn fmt_node_header(&self, f: &mut dyn fmt::Write, node: &Node) -> fmt::Result {
        let is_external = node.krate != Some(self.member_krate.clone());

        let visibility = match &node.visibility {
            Some(visibility) => {
                if is_external {
                    Some("external".to_owned())
                } else if node.kind == NodeKind::Crate {
                    None
                } else {
                    Some(format!("{}", visibility))
                }
            }
            None => Some("orphan".to_owned()),
        };

        let kind = node.kind.display_name().unwrap_or("mod");

        if let Some(visibility) = visibility {
            write!(f, "{} ", visibility)?;
        }

        write!(f, "{}", kind)
    }

    fn fmt_node_body(&self, f: &mut dyn fmt::Write, node: &Node) -> fmt::Result {
        let path = if self.options.full_paths {
            // If we explicitly want full paths, return it unaltered:
            node.path.join("::")
        } else if node.path.len() > 1 {
            // Otherwise try to drop the crate-name from the path:
            node.path[1..].join("::")
        } else {
            node.path.join("::")
        };

        write!(f, "{}", path)
    }

    fn node_attributes(&self, node: &Node) -> String {
        let styles = node_styles();

        let style = match &node.kind {
            NodeKind::Crate => styles.krate,
            NodeKind::Orphan => styles.orphan,
            _ => match &node.visibility {
                Some(visibility) => match visibility {
                    NodeVisibility::Crate => styles.visibility.pub_crate,
                    NodeVisibility::Module(_) => styles.visibility.pub_module,
                    NodeVisibility::Private => styles.visibility.pub_private,
                    NodeVisibility::Public => styles.visibility.pub_global,
                    NodeVisibility::Super => styles.visibility.pub_super,
                },
                None => styles.visibility.pub_global,
            },
        };

        format!(r#", fillcolor="{}""#, style.fill_color)
    }

    fn edge_label(&self, edge: &Edge) -> String {
        edge.kind.display_name().to_owned()
    }

    fn edge_attributes(&self, edge: &Edge) -> String {
        let styles = edge_styles();

        let style = match edge.kind {
            EdgeKind::Uses { .. } => styles.uses,
            EdgeKind::Owns => styles.owns,
        };

        format!(r#", color="{}", style="{}""#, style.color, style.stroke)
    }
}
<|endoftext|>


<commit_before>use regex::Regex;
use std::collections::hashmap::HashMap;

pub struct Params {
    captures: HashMap<String, String>
}

impl Params {
    pub fn new<I: Iterator<String>>(uri: &str, matcher: Regex, params: I) -> Params {
        let captures = matcher.captures(uri).unwrap();
        Params {
            captures: params.map(
                          // Map captures into (String, String) pairs so they
                          // can be collected into a HashMap<String, String>
                          |p| (p.clone(), captures.name(p.as_slice()).to_string())
                      ).collect()
        }
    }

    pub fn get<'a>(&'a self, param: &'static str) -> Option<String> {
        self.captures.find(&param.to_string()).and_then(|p| Some(p.clone()))
    }
}

#[cfg(test)]
mod test {
    use test::{Bencher, black_box};
    use super::*;
    use super::super::glob::deglob;

    #[test]
    fn test_new() {
        let params = Params::new(
            "/users/7324/235",
            deglob("/users/:userid/:groupid".to_string()),
            vec!["userid".to_string(), "groupid".to_string()].move_iter());
        assert_eq!(params.get("userid").unwrap(), "7324".to_string());
        assert_eq!(params.get("groupid").unwrap(), "235".to_string());
    }

    #[bench]
    fn bench_get(b: &mut Bencher) {
        let params = Params::new("/users/7324", deglob("/users/:userid".to_string()), vec!["userid".to_string()].move_iter());
        b.iter(|| {
            black_box(params.get("userid").unwrap())
        })
    }
}

<commit_msg>(doc) Documented Params struct and interface.<commit_after>use regex::Regex;
use std::collections::hashmap::HashMap;

/// `Params` contains a `HashMap` of all the glob parameters stored in alloy.
///
/// For instance, for a glob pattern like `/users/:userid` `Params` will
/// contain the key `userid` matched with the value from the request url.
/// This works for any number of parameters in a glob pattern.
///
/// These values can be accessed using `Params::get`.
pub struct Params {
    captures: HashMap<String, String>
}

impl Params {
    #[doc(hidden)]
    pub fn new<I: Iterator<String>>(uri: &str, matcher: Regex, params: I) -> Params {
        let captures = matcher.captures(uri).unwrap();
        Params {
            captures: params.map(
                          // Map captures into (String, String) pairs so they
                          // can be collected into a HashMap<String, String>
                          |p| (p.clone(), captures.name(p.as_slice()).to_string())
                      ).collect()
        }
    }

    /// `get` allows you to query the HashMap contained inside Params.
    ///
    /// You can use `get` to access the parameters in the glob pattern
    /// for the matched route which are from the request url.
    ///
    /// If your route contains `:groupid`, for instance, then you can get its
    /// value from a `Params` by doing `params.get("groupid")`.
    pub fn get<'a>(&'a self, param: &str) -> Option<String> {
        self.captures.find(&param.to_string()).and_then(|p| Some(p.clone()))
    }
}

#[cfg(test)]
mod test {
    use test::{Bencher, black_box};
    use super::*;
    use super::super::glob::deglob;

    #[test]
    fn test_new() {
        let params = Params::new(
            "/users/7324/235",
            deglob("/users/:userid/:groupid".to_string()),
            vec!["userid".to_string(), "groupid".to_string()].move_iter());
        assert_eq!(params.get("userid").unwrap(), "7324".to_string());
        assert_eq!(params.get("groupid").unwrap(), "235".to_string());
    }

    #[bench]
    fn bench_get(b: &mut Bencher) {
        let params = Params::new("/users/7324", deglob("/users/:userid".to_string()), vec!["userid".to_string()].move_iter());
        b.iter(|| {
            black_box(params.get("userid").unwrap())
        })
    }
}

<|endoftext|>


<commit_before>extern crate clap;
extern crate rusqlite;

#[macro_use] extern crate log;

extern crate env_logger;
extern crate rustc_serialize;
extern crate uuid;

mod loader;
mod db;
mod dbFsDirType;
mod dbFsDir;
mod dbFsFile;
mod dbProvider;
mod dbJob;
mod dbJobProvide;
mod dbJobDepend;
mod dbVariableName;
mod dbJobRequireVariable;
mod dbVariablePair;
mod dbJobRequireVariablePair;
mod json_loader_elephant;
mod cli_clap;
mod jobs_load;
mod elephant;
mod dbSession;
mod dbEnviroment;
mod autoconf;
mod clap_actions;

use uuid::Uuid;

fn main() {
    env_logger::init().unwrap();
    let some_value = 10;
    let clap_matches = cli_clap::cli_clap(&some_value);
    let actions = clap_actions::actions_get(&clap_matches);
    let session_uuid = Uuid::new_v4();
    let session_uuid_string = session_uuid.simple().to_string();
    let conn = db::connect_deligate(&clap_matches);
    db::create_tables(&conn);
    loader::deligate(&conn, &actions, &clap_matches);
    let pk_session = elephant::elephant_session(&conn, &session_uuid_string);
    loader::enviroment(&conn, pk_session, &clap_matches);
    jobs_load::load(&conn);
}
<commit_msg>Use actions<commit_after>extern crate clap;
extern crate rusqlite;

#[macro_use] extern crate log;

extern crate env_logger;
extern crate rustc_serialize;
extern crate uuid;

mod loader;
mod db;
mod dbFsDirType;
mod dbFsDir;
mod dbFsFile;
mod dbProvider;
mod dbJob;
mod dbJobProvide;
mod dbJobDepend;
mod dbVariableName;
mod dbJobRequireVariable;
mod dbVariablePair;
mod dbJobRequireVariablePair;
mod json_loader_elephant;
mod cli_clap;
mod jobs_load;
mod elephant;
mod dbSession;
mod dbEnviroment;
mod autoconf;
mod clap_actions;
mod actions_process;

use uuid::Uuid;

fn main() {
    env_logger::init().unwrap();
    let some_value = 10;
    let clap_matches = cli_clap::cli_clap(&some_value);
    let actions = clap_actions::actions_get(&clap_matches);
    let session_uuid = Uuid::new_v4();
    let session_uuid_string = session_uuid.simple().to_string();
    let conn = db::connect_deligate(&clap_matches);
    db::create_tables(&conn);
    loader::deligate(&conn, &actions, &clap_matches);
    let pk_session = elephant::elephant_session(&conn, &session_uuid_string);
    loader::enviroment(&conn, pk_session, &clap_matches);
    jobs_load::load(&conn);
    actions_process::process(&conn, &actions)
}
<|endoftext|>


<commit_before>use std::fmt::Debug;
use std::ops::{Add, Range, Sub};

use take_mut;

#[derive(Debug)]
pub struct ScheduleTree<'a, T, D: 'a> {
    root: Option<Node<'a, T, D>>,
    scope: Option<Range<T>>,
}

#[derive(Debug, PartialEq)]
pub enum Node<'a, T, D: 'a> {
    Leaf { start: T, end: T, data: &'a D },
    Intermediate {
        left: Box<Node<'a, T, D>>,
        right: Box<Node<'a, T, D>>,
        free: Range<T>,
    },
}

impl<'a, T, D> ScheduleTree<'a, T, D>
    where T: Copy + Clone + Ord + Debug,
          D: Debug
{
    pub fn new() -> Self {
        ScheduleTree {
            root: None,
            scope: None,
        }
    }

    pub fn iter(&self) -> Iter<T, D> {
        Iter { path: self.root.iter().collect() }
    }

    pub fn schedule_exact<W>(&mut self, start: T, duration: W, data: &'a D) -> bool
        where T: Add<W, Output = T>
    {
        let end = start + duration;
        let new_node = Node::Leaf {
            start: start,
            end: end,
            data: data,
        };

        if self.root.is_none() {
            self.root = Some(new_node);
            self.scope = Some(start..end);
            return true;
        }

        let scope = self.scope
            .as_ref()
            .cloned()
            .unwrap();
        if end <= scope.start {
            let root = self.root.take().unwrap();
            self.root = Some(Node::Intermediate {
                                 left: Box::new(new_node),
                                 right: Box::new(root),
                                 free: end..scope.start,
                             });
            self.scope = Some(start..scope.end);
            return true;
        } else if scope.end <= start {
            let root = self.root.take().unwrap();
            self.root = Some(Node::Intermediate {
                                 left: Box::new(root),
                                 right: Box::new(new_node),
                                 free: scope.end..start,
                             });
            self.scope = Some(scope.start..end);
            return true;
        }

        self.root
            .as_mut()
            .unwrap()
            .insert(start, end, new_node)
    }

    pub fn schedule_after<W>(&self, start: T, duration: W, max_end: Option<T>, data: &'a D) -> bool
        where T: Add<W, Output = T> + Sub<T, Output = W> + Sub<W, Output = T>,
              W: Add<W, Output = W> + Add<T, Output = T> + Sub<W, Output = W> + Copy
    {
        assert!(max_end.map_or(true, |max_end| start + duration <= max_end));
        // TODO schedule
        true
    }
}

impl<'a, T, D> Node<'a, T, D>
    where T: Copy + Ord + Debug
{
    fn insert(&mut self, start: T, end: T, sub_tree: Node<'a, T, D>) -> bool {
        match *self {
            Node::Intermediate { ref mut left, ref mut right, ref mut free } => {
                if end <= free.start {
                    left.insert(start, end, sub_tree)
                } else if free.end <= start {
                    right.insert(start, end, sub_tree)
                } else if free.start <= start && end <= free.end {
                    // [start, end] completely within self.free
                    take_mut::take(right, |right_value| {
                        Box::new(Node::Intermediate {
                                     left: Box::new(sub_tree),
                                     right: right_value,
                                     free: end..free.end,
                                 })
                    });
                    *free = free.start..start;
                    true
                } else {
                    // Overlap between [start, end] and self.free
                    false
                }
            }
            Node::Leaf { .. } => false,
        }
    }
}

#[derive(Debug)]
pub struct Entry<'a, T, D: 'a> {
    pub start: T,
    pub end: T,
    pub data: &'a D,
}

#[derive(Debug)]
pub struct Iter<'b, 'a: 'b, T: 'b, D: 'a> {
    path: Vec<&'b Node<'a, T, D>>,
}

impl<'b, 'a, T, D> Iterator for Iter<'b, 'a, T, D>
    where T: Copy
{
    type Item = Entry<'a, T, D>;

    fn next(&mut self) -> Option<Self::Item> {
        self.path.pop().and_then(|mut current| {
            while let Node::Intermediate { ref left, ref right, .. } = *current {
                self.path.push(right);
                current = left;
            }
            if let Node::Leaf { start, end, ref data } = *current {
                Some(Entry {
                         start: start,
                         end: end,
                         data: *data,
                     })
            } else {
                None
            }
        })
    }
}

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

    const DATA: &i8 = &9;

    #[test]
    fn test_schedule_exact() {
        let mut tree: ScheduleTree<i8, i8> = ScheduleTree::new();

        // 5..10
        let scheduled = tree.schedule_exact(5, 5, DATA);
        assert!(scheduled);
        assert!(tree.scope == Some(5..10));
        assert_matches!(tree.root, Some(Node::Leaf { start: 5, end: 10, .. }));

        //   free:10..13
        //    /        \
        // 5..10      13..18
        let scheduled = tree.schedule_exact(13, 5, DATA);
        assert!(scheduled);
        assert!(tree.scope == Some(5..18));
        assert_matches!(tree.root, Some(Node::Intermediate {
            free: Range { start: 10, end: 13 },
            right: box Node::Leaf { start: 13, end: 18, .. },
        .. }));

        //   free:10..10
        //    /        \
        // 5..10     free:12..13
        //             /     \
        //          10..12  13..18
        let scheduled = tree.schedule_exact(10, 2, DATA);
        assert!(scheduled);
        assert!(tree.scope == Some(5..18));
        assert_matches!(tree.root, Some(Node::Intermediate {
            free: Range { start: 10, end: 10 },
            right: box Node::Intermediate {
                free: Range { start: 12, end: 13 },
                left: box Node::Leaf { start: 10, end: 12, .. },
            .. },
        .. }));
    }
}
<commit_msg>Fix lifetime issues<commit_after>use std::fmt::Debug;
use std::ops::{Add, Range, Sub};

use take_mut;

#[derive(Debug)]
pub struct ScheduleTree<'a, T, D: 'a> {
    root: Option<Node<'a, T, D>>,
    scope: Option<Range<T>>,
}

#[derive(Debug, PartialEq)]
pub enum Node<'a, T, D: 'a> {
    Leaf { start: T, end: T, data: &'a D },
    Intermediate {
        left: Box<Node<'a, T, D>>,
        right: Box<Node<'a, T, D>>,
        free: Range<T>,
    },
}

impl<'a, T, D> ScheduleTree<'a, T, D>
    where T: Copy + Clone + Ord + Debug,
          D: Debug
{
    pub fn new() -> Self {
        ScheduleTree {
            root: None,
            scope: None,
        }
    }

    pub fn iter<'b>(&'b self) -> Iter<'b, 'a, T, D> {
        Iter { path: self.root.iter().collect() }
    }

    pub fn schedule_exact<W>(&mut self, start: T, duration: W, data: &'a D) -> bool
        where T: Add<W, Output = T>
    {
        let end = start + duration;
        let new_node = Node::Leaf {
            start: start,
            end: end,
            data: data,
        };

        if self.root.is_none() {
            self.root = Some(new_node);
            self.scope = Some(start..end);
            return true;
        }

        let scope = self.scope
            .as_ref()
            .cloned()
            .unwrap();
        if end <= scope.start {
            let root = self.root.take().unwrap();
            self.root = Some(Node::Intermediate {
                                 left: Box::new(new_node),
                                 right: Box::new(root),
                                 free: end..scope.start,
                             });
            self.scope = Some(start..scope.end);
            return true;
        } else if scope.end <= start {
            let root = self.root.take().unwrap();
            self.root = Some(Node::Intermediate {
                                 left: Box::new(root),
                                 right: Box::new(new_node),
                                 free: scope.end..start,
                             });
            self.scope = Some(scope.start..end);
            return true;
        }

        self.root
            .as_mut()
            .unwrap()
            .insert(start, end, new_node)
    }

    pub fn schedule_after<W>(&self, start: T, duration: W, max_end: Option<T>, data: &'a D) -> bool
        where T: Add<W, Output = T> + Sub<T, Output = W> + Sub<W, Output = T>,
              W: Add<W, Output = W> + Add<T, Output = T> + Sub<W, Output = W> + Copy
    {
        assert!(max_end.map_or(true, |max_end| start + duration <= max_end));
        // TODO schedule
        true
    }
}

impl<'a, T, D> Node<'a, T, D>
    where T: Copy + Ord + Debug
{
    fn insert(&mut self, start: T, end: T, sub_tree: Node<'a, T, D>) -> bool {
        match *self {
            Node::Intermediate { ref mut left, ref mut right, ref mut free } => {
                if end <= free.start {
                    left.insert(start, end, sub_tree)
                } else if free.end <= start {
                    right.insert(start, end, sub_tree)
                } else if free.start <= start && end <= free.end {
                    // [start, end] completely within self.free
                    take_mut::take(right, |right_value| {
                        Box::new(Node::Intermediate {
                                     left: Box::new(sub_tree),
                                     right: right_value,
                                     free: end..free.end,
                                 })
                    });
                    *free = free.start..start;
                    true
                } else {
                    // Overlap between [start, end] and self.free
                    false
                }
            }
            Node::Leaf { .. } => false,
        }
    }
}

#[derive(Debug)]
pub struct Entry<'a, T, D: 'a> {
    pub start: T,
    pub end: T,
    pub data: &'a D,
}

#[derive(Debug)]
pub struct Iter<'b, 'a: 'b, T: 'b, D: 'a> {
    path: Vec<&'b Node<'a, T, D>>,
}

impl<'b, 'a, T, D> Iterator for Iter<'b, 'a, T, D>
    where T: Copy
{
    type Item = Entry<'a, T, D>;

    fn next(&mut self) -> Option<Self::Item> {
        self.path.pop().and_then(|mut current| {
            while let Node::Intermediate { ref left, ref right, .. } = *current {
                self.path.push(right);
                current = left;
            }
            if let Node::Leaf { start, end, data } = *current {
                Some(Entry {
                         start: start,
                         end: end,
                         data: data,
                     })
            } else {
                None
            }
        })
    }
}

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

    const DATA: &i8 = &9;

    #[test]
    fn test_schedule_exact() {
        let mut tree: ScheduleTree<i8, i8> = ScheduleTree::new();

        // 5..10
        let scheduled = tree.schedule_exact(5, 5, DATA);
        assert!(scheduled);
        assert!(tree.scope == Some(5..10));
        assert_matches!(tree.root, Some(Node::Leaf { start: 5, end: 10, .. }));

        //   free:10..13
        //    /        \
        // 5..10      13..18
        let scheduled = tree.schedule_exact(13, 5, DATA);
        assert!(scheduled);
        assert!(tree.scope == Some(5..18));
        assert_matches!(tree.root, Some(Node::Intermediate {
            free: Range { start: 10, end: 13 },
            right: box Node::Leaf { start: 13, end: 18, .. },
        .. }));

        //   free:10..10
        //    /        \
        // 5..10     free:12..13
        //             /     \
        //          10..12  13..18
        let scheduled = tree.schedule_exact(10, 2, DATA);
        assert!(scheduled);
        assert!(tree.scope == Some(5..18));
        assert_matches!(tree.root, Some(Node::Intermediate {
            free: Range { start: 10, end: 10 },
            right: box Node::Intermediate {
                free: Range { start: 12, end: 13 },
                left: box Node::Leaf { start: 10, end: 12, .. },
            .. },
        .. }));
    }
}
<|endoftext|>


<commit_before>//! Read configurations files.

#![deny(missing_docs_in_private_items)]

use std::{env, fmt, fs, io, path};
use std::io::Read;
use syntax::{ast, codemap};
use toml;
use std::sync::Mutex;

/// Get the configuration file from arguments.
pub fn file_from_args(
    args: &[codemap::Spanned<ast::NestedMetaItemKind>],
) -> Result<Option<path::PathBuf>, (&'static str, codemap::Span)> {
    for arg in args.iter().filter_map(|a| a.meta_item()) {
        if arg.name() == "conf_file" {
            return match arg.node {
                ast::MetaItemKind::Word | ast::MetaItemKind::List(_) => {
                    Err(("`conf_file` must be a named value", arg.span))
                },
                ast::MetaItemKind::NameValue(ref value) => if let ast::LitKind::Str(ref file, _) = value.node {
                    Ok(Some(file.to_string().into()))
                } else {
                    Err(("`conf_file` value must be a string", value.span))
                },
            };
        }
    }

    Ok(None)
}

/// Error from reading a configuration file.
#[derive(Debug)]
pub enum Error {
    /// An I/O error.
    Io(io::Error),
    /// Not valid toml or doesn't fit the expected conf format
    Toml(String),
    /// Type error.
    Type(
        /// The name of the key.
        &'static str,
        /// The expected type.
        &'static str,
        /// The type we got instead.
        &'static str,
    ),
    /// There is an unknown key is the file.
    UnknownKey(String),
}

impl fmt::Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        match *self {
            Error::Io(ref err) => err.fmt(f),
            Error::Toml(ref err) => err.fmt(f),
            Error::Type(key, expected, got) => {
                write!(f, "`{}` is expected to be a `{}` but is a `{}`", key, expected, got)
            },
            Error::UnknownKey(ref key) => write!(f, "unknown key `{}`", key),
        }
    }
}

impl From<io::Error> for Error {
    fn from(e: io::Error) -> Self {
        Error::Io(e)
    }
}

lazy_static! {
    static ref ERRORS: Mutex<Vec<Error>> = Mutex::new(Vec::new());
}

macro_rules! define_Conf {
    ($(#[$doc: meta] ($rust_name: ident, $rust_name_str: expr, $default: expr => $($ty: tt)+),)+) => {
        pub use self::helpers::Conf;
        mod helpers {
            /// Type used to store lint configuration.
            #[derive(Deserialize)]
            #[serde(rename_all="kebab-case")]
            #[serde(deny_unknown_fields)]
            pub struct Conf {
                $(#[$doc] #[serde(default=$rust_name_str)] #[serde(with=$rust_name_str)]
                          pub $rust_name: define_Conf!(TY $($ty)+),)+
                #[allow(dead_code)]
                #[serde(default)]
                third_party: Option<::toml::Value>,
            }
            $(
                mod $rust_name {
                    use serde;
                    use serde::Deserialize;
                    pub fn deserialize<'de, D: serde::Deserializer<'de>>(deserializer: D)
                    -> Result<define_Conf!(TY $($ty)+), D::Error> {
                        type T = define_Conf!(TY $($ty)+);
                        Ok(T::deserialize(deserializer).unwrap_or_else(|e| {
                            ::utils::conf::ERRORS.lock().expect("no threading here")
                                                        .push(::utils::conf::Error::Toml(e.to_string()));
                            super::$rust_name()
                        }))
                    }
                }

                fn $rust_name() -> define_Conf!(TY $($ty)+) {
                    define_Conf!(DEFAULT $($ty)+, $default)
                }
            )+
        }
    };

    // hack to convert tts
    (TY $ty: ty) => { $ty };

    // how to read the value?
    (CONV i64, $value: expr) => { $value.as_integer() };
    (CONV u64, $value: expr) => {
        $value.as_integer()
        .iter()
        .filter_map(|&i| if i >= 0 { Some(i as u64) } else { None })
        .next()
    };
    (CONV String, $value: expr) => { $value.as_str().map(Into::into) };
    (CONV Vec<String>, $value: expr) => {{
        let slice = $value.as_array();

        if let Some(slice) = slice {
            if slice.iter().any(|v| v.as_str().is_none()) {
                None
            } else {
                Some(slice.iter().map(|v| v.as_str().expect("already checked").to_owned()).collect())
            }
        } else {
            None
        }
    }};

    // provide a nicer syntax to declare the default value of `Vec<String>` variables
    (DEFAULT Vec<String>, $e: expr) => { $e.iter().map(|&e| e.to_owned()).collect() };
    (DEFAULT $ty: ty, $e: expr) => { $e };
}

define_Conf! {
    /// Lint: BLACKLISTED_NAME. The list of blacklisted names to lint about
    (blacklisted_names, "blacklisted_names", ["foo", "bar", "baz", "quux"] => Vec<String>),
    /// Lint: CYCLOMATIC_COMPLEXITY. The maximum cyclomatic complexity a function can have
    (cyclomatic_complexity_threshold, "cyclomatic_complexity_threshold", 25 => u64),
    /// Lint: DOC_MARKDOWN. The list of words this lint should not consider as identifiers needing ticks
    (doc_valid_idents, "doc_valid_idents", [
        "KiB", "MiB", "GiB", "TiB", "PiB", "EiB",
        "DirectX",
        "ECMAScript",
        "GPLv2", "GPLv3",
        "GitHub",
        "IPv4", "IPv6",
        "JavaScript",
        "NaN",
        "OAuth",
        "OpenGL", "OpenSSH", "OpenSSL",
        "TrueType",
        "iOS", "macOS",
        "TeX", "LaTeX", "BibTeX", "BibLaTeX",
        "MinGW",
    ] => Vec<String>),
    /// Lint: TOO_MANY_ARGUMENTS. The maximum number of argument a function or method can have
    (too_many_arguments_threshold, "too_many_arguments_threshold", 7 => u64),
    /// Lint: TYPE_COMPLEXITY. The maximum complexity a type can have
    (type_complexity_threshold, "type_complexity_threshold", 250 => u64),
    /// Lint: MANY_SINGLE_CHAR_NAMES. The maximum number of single char bindings a scope may have
    (single_char_binding_names_threshold, "single_char_binding_names_threshold", 5 => u64),
    /// Lint: BOXED_LOCAL. The maximum size of objects (in bytes) that will be linted. Larger objects are ok on the heap
    (too_large_for_stack, "too_large_for_stack", 200 => u64),
    /// Lint: ENUM_VARIANT_NAMES. The minimum number of enum variants for the lints about variant names to trigger
    (enum_variant_name_threshold, "enum_variant_name_threshold", 3 => u64),
    /// Lint: LARGE_ENUM_VARIANT. The maximum size of a emum's variant to avoid box suggestion
    (enum_variant_size_threshold, "enum_variant_size_threshold", 200 => u64),
    /// Lint: VERBOSE_BIT_MASK. The maximum allowed size of a bit mask before suggesting to use 'trailing_zeros'
    (verbose_bit_mask_threshold, "verbose_bit_mask_threshold", 1 => u64),
}

/// Search for the configuration file.
pub fn lookup_conf_file() -> io::Result<Option<path::PathBuf>> {
    /// Possible filename to search for.
    const CONFIG_FILE_NAMES: [&str; 2] = [".clippy.toml", "clippy.toml"];

    let mut current = try!(env::current_dir());

    loop {
        for config_file_name in &CONFIG_FILE_NAMES {
            let config_file = current.join(config_file_name);
            match fs::metadata(&config_file) {
                // Only return if it's a file to handle the unlikely situation of a directory named
                // `clippy.toml`.
                Ok(ref md) if md.is_file() => return Ok(Some(config_file)),
                // Return the error if it's something other than `NotFound`; otherwise we didn't
                // find the project file yet, and continue searching.
                Err(e) => if e.kind() != io::ErrorKind::NotFound {
                    return Err(e);
                },
                _ => (),
            }
        }

        // If the current directory has no parent, we're done searching.
        if !current.pop() {
            return Ok(None);
        }
    }
}

/// Produces a `Conf` filled with the default values and forwards the errors
///
/// Used internally for convenience
fn default(errors: Vec<Error>) -> (Conf, Vec<Error>) {
    (toml::from_str("").expect("we never error on empty config files"), errors)
}

/// Read the `toml` configuration file.
///
/// In case of error, the function tries to continue as much as possible.
pub fn read(path: Option<&path::Path>) -> (Conf, Vec<Error>) {
    let path = if let Some(path) = path {
        path
    } else {
        return default(Vec::new());
    };

    let file = match fs::File::open(path) {
        Ok(mut file) => {
            let mut buf = String::new();

            if let Err(err) = file.read_to_string(&mut buf) {
                return default(vec![err.into()]);
            }

            buf
        },
        Err(err) => return default(vec![err.into()]),
    };

    assert!(
        ERRORS
            .lock()
            .expect("no threading -> mutex always safe")
            .is_empty()
    );
    match toml::from_str(&file) {
        Ok(toml) => (
            toml,
            ERRORS
                .lock()
                .expect("no threading -> mutex always safe")
                .split_off(0),
        ),
        Err(e) => {
            let mut errors = ERRORS
                .lock()
                .expect("no threading -> mutex always safe")
                .split_off(0);
            errors.push(Error::Toml(e.to_string()));
            default(errors)
        },
    }
}
<commit_msg>Ignore identifier 'OpenStreetMap' for DOC_MARKDOWN lint<commit_after>//! Read configurations files.

#![deny(missing_docs_in_private_items)]

use std::{env, fmt, fs, io, path};
use std::io::Read;
use syntax::{ast, codemap};
use toml;
use std::sync::Mutex;

/// Get the configuration file from arguments.
pub fn file_from_args(
    args: &[codemap::Spanned<ast::NestedMetaItemKind>],
) -> Result<Option<path::PathBuf>, (&'static str, codemap::Span)> {
    for arg in args.iter().filter_map(|a| a.meta_item()) {
        if arg.name() == "conf_file" {
            return match arg.node {
                ast::MetaItemKind::Word | ast::MetaItemKind::List(_) => {
                    Err(("`conf_file` must be a named value", arg.span))
                },
                ast::MetaItemKind::NameValue(ref value) => if let ast::LitKind::Str(ref file, _) = value.node {
                    Ok(Some(file.to_string().into()))
                } else {
                    Err(("`conf_file` value must be a string", value.span))
                },
            };
        }
    }

    Ok(None)
}

/// Error from reading a configuration file.
#[derive(Debug)]
pub enum Error {
    /// An I/O error.
    Io(io::Error),
    /// Not valid toml or doesn't fit the expected conf format
    Toml(String),
    /// Type error.
    Type(
        /// The name of the key.
        &'static str,
        /// The expected type.
        &'static str,
        /// The type we got instead.
        &'static str,
    ),
    /// There is an unknown key is the file.
    UnknownKey(String),
}

impl fmt::Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        match *self {
            Error::Io(ref err) => err.fmt(f),
            Error::Toml(ref err) => err.fmt(f),
            Error::Type(key, expected, got) => {
                write!(f, "`{}` is expected to be a `{}` but is a `{}`", key, expected, got)
            },
            Error::UnknownKey(ref key) => write!(f, "unknown key `{}`", key),
        }
    }
}

impl From<io::Error> for Error {
    fn from(e: io::Error) -> Self {
        Error::Io(e)
    }
}

lazy_static! {
    static ref ERRORS: Mutex<Vec<Error>> = Mutex::new(Vec::new());
}

macro_rules! define_Conf {
    ($(#[$doc: meta] ($rust_name: ident, $rust_name_str: expr, $default: expr => $($ty: tt)+),)+) => {
        pub use self::helpers::Conf;
        mod helpers {
            /// Type used to store lint configuration.
            #[derive(Deserialize)]
            #[serde(rename_all="kebab-case")]
            #[serde(deny_unknown_fields)]
            pub struct Conf {
                $(#[$doc] #[serde(default=$rust_name_str)] #[serde(with=$rust_name_str)]
                          pub $rust_name: define_Conf!(TY $($ty)+),)+
                #[allow(dead_code)]
                #[serde(default)]
                third_party: Option<::toml::Value>,
            }
            $(
                mod $rust_name {
                    use serde;
                    use serde::Deserialize;
                    pub fn deserialize<'de, D: serde::Deserializer<'de>>(deserializer: D)
                    -> Result<define_Conf!(TY $($ty)+), D::Error> {
                        type T = define_Conf!(TY $($ty)+);
                        Ok(T::deserialize(deserializer).unwrap_or_else(|e| {
                            ::utils::conf::ERRORS.lock().expect("no threading here")
                                                        .push(::utils::conf::Error::Toml(e.to_string()));
                            super::$rust_name()
                        }))
                    }
                }

                fn $rust_name() -> define_Conf!(TY $($ty)+) {
                    define_Conf!(DEFAULT $($ty)+, $default)
                }
            )+
        }
    };

    // hack to convert tts
    (TY $ty: ty) => { $ty };

    // how to read the value?
    (CONV i64, $value: expr) => { $value.as_integer() };
    (CONV u64, $value: expr) => {
        $value.as_integer()
        .iter()
        .filter_map(|&i| if i >= 0 { Some(i as u64) } else { None })
        .next()
    };
    (CONV String, $value: expr) => { $value.as_str().map(Into::into) };
    (CONV Vec<String>, $value: expr) => {{
        let slice = $value.as_array();

        if let Some(slice) = slice {
            if slice.iter().any(|v| v.as_str().is_none()) {
                None
            } else {
                Some(slice.iter().map(|v| v.as_str().expect("already checked").to_owned()).collect())
            }
        } else {
            None
        }
    }};

    // provide a nicer syntax to declare the default value of `Vec<String>` variables
    (DEFAULT Vec<String>, $e: expr) => { $e.iter().map(|&e| e.to_owned()).collect() };
    (DEFAULT $ty: ty, $e: expr) => { $e };
}

define_Conf! {
    /// Lint: BLACKLISTED_NAME. The list of blacklisted names to lint about
    (blacklisted_names, "blacklisted_names", ["foo", "bar", "baz", "quux"] => Vec<String>),
    /// Lint: CYCLOMATIC_COMPLEXITY. The maximum cyclomatic complexity a function can have
    (cyclomatic_complexity_threshold, "cyclomatic_complexity_threshold", 25 => u64),
    /// Lint: DOC_MARKDOWN. The list of words this lint should not consider as identifiers needing ticks
    (doc_valid_idents, "doc_valid_idents", [
        "KiB", "MiB", "GiB", "TiB", "PiB", "EiB",
        "DirectX",
        "ECMAScript",
        "GPLv2", "GPLv3",
        "GitHub",
        "IPv4", "IPv6",
        "JavaScript",
        "NaN",
        "OAuth",
        "OpenGL", "OpenSSH", "OpenSSL", "OpenStreetMap",
        "TrueType",
        "iOS", "macOS",
        "TeX", "LaTeX", "BibTeX", "BibLaTeX",
        "MinGW",
    ] => Vec<String>),
    /// Lint: TOO_MANY_ARGUMENTS. The maximum number of argument a function or method can have
    (too_many_arguments_threshold, "too_many_arguments_threshold", 7 => u64),
    /// Lint: TYPE_COMPLEXITY. The maximum complexity a type can have
    (type_complexity_threshold, "type_complexity_threshold", 250 => u64),
    /// Lint: MANY_SINGLE_CHAR_NAMES. The maximum number of single char bindings a scope may have
    (single_char_binding_names_threshold, "single_char_binding_names_threshold", 5 => u64),
    /// Lint: BOXED_LOCAL. The maximum size of objects (in bytes) that will be linted. Larger objects are ok on the heap
    (too_large_for_stack, "too_large_for_stack", 200 => u64),
    /// Lint: ENUM_VARIANT_NAMES. The minimum number of enum variants for the lints about variant names to trigger
    (enum_variant_name_threshold, "enum_variant_name_threshold", 3 => u64),
    /// Lint: LARGE_ENUM_VARIANT. The maximum size of a emum's variant to avoid box suggestion
    (enum_variant_size_threshold, "enum_variant_size_threshold", 200 => u64),
    /// Lint: VERBOSE_BIT_MASK. The maximum allowed size of a bit mask before suggesting to use 'trailing_zeros'
    (verbose_bit_mask_threshold, "verbose_bit_mask_threshold", 1 => u64),
}

/// Search for the configuration file.
pub fn lookup_conf_file() -> io::Result<Option<path::PathBuf>> {
    /// Possible filename to search for.
    const CONFIG_FILE_NAMES: [&str; 2] = [".clippy.toml", "clippy.toml"];

    let mut current = try!(env::current_dir());

    loop {
        for config_file_name in &CONFIG_FILE_NAMES {
            let config_file = current.join(config_file_name);
            match fs::metadata(&config_file) {
                // Only return if it's a file to handle the unlikely situation of a directory named
                // `clippy.toml`.
                Ok(ref md) if md.is_file() => return Ok(Some(config_file)),
                // Return the error if it's something other than `NotFound`; otherwise we didn't
                // find the project file yet, and continue searching.
                Err(e) => if e.kind() != io::ErrorKind::NotFound {
                    return Err(e);
                },
                _ => (),
            }
        }

        // If the current directory has no parent, we're done searching.
        if !current.pop() {
            return Ok(None);
        }
    }
}

/// Produces a `Conf` filled with the default values and forwards the errors
///
/// Used internally for convenience
fn default(errors: Vec<Error>) -> (Conf, Vec<Error>) {
    (toml::from_str("").expect("we never error on empty config files"), errors)
}

/// Read the `toml` configuration file.
///
/// In case of error, the function tries to continue as much as possible.
pub fn read(path: Option<&path::Path>) -> (Conf, Vec<Error>) {
    let path = if let Some(path) = path {
        path
    } else {
        return default(Vec::new());
    };

    let file = match fs::File::open(path) {
        Ok(mut file) => {
            let mut buf = String::new();

            if let Err(err) = file.read_to_string(&mut buf) {
                return default(vec![err.into()]);
            }

            buf
        },
        Err(err) => return default(vec![err.into()]),
    };

    assert!(
        ERRORS
            .lock()
            .expect("no threading -> mutex always safe")
            .is_empty()
    );
    match toml::from_str(&file) {
        Ok(toml) => (
            toml,
            ERRORS
                .lock()
                .expect("no threading -> mutex always safe")
                .split_off(0),
        ),
        Err(e) => {
            let mut errors = ERRORS
                .lock()
                .expect("no threading -> mutex always safe")
                .split_off(0);
            errors.push(Error::Toml(e.to_string()));
            default(errors)
        },
    }
}
<|endoftext|>


<commit_before>use crate::{
    frame::{AMQPFrame, ProtocolVersion},
    protocol::{basic::gen_properties, *},
    types::{generation::*, *},
};
use cookie_factory::{
    combinator::slice,
    sequence::tuple,
};
use std::io::Write;

/// Serialize a frame in the given buffer
pub fn gen_frame<'a, W: Write + BackToTheBuffer + 'a>(
    frame: &'a AMQPFrame,
) -> impl SerializeFn<W> + 'a {
    move |x| match frame {
        AMQPFrame::ProtocolHeader(version) => gen_protocol_header(version)(x),
        AMQPFrame::Heartbeat(_) => gen_heartbeat_frame()(x),
        AMQPFrame::Method(channel_id, method) => gen_method_frame(*channel_id, method)(x),
        AMQPFrame::Header(channel_id, class_id, header) => {
            gen_content_header_frame(*channel_id, *class_id, header.body_size, &header.properties)(
                x,
            )
        }
        AMQPFrame::Body(channel_id, data) => gen_content_body_frame(*channel_id, data)(x),
    }
}

fn gen_protocol_header<W: Write>(version: &ProtocolVersion) -> impl SerializeFn<W> {
    tuple((
        slice(metadata::NAME.as_bytes()),
        gen_short_short_uint(0),
        gen_protocol_version(version)
    ))
}

fn gen_protocol_version<W: Write>(version: &ProtocolVersion) -> impl SerializeFn<W> {
    tuple((
        gen_short_short_uint(version.major),
        gen_short_short_uint(version.minor),
        gen_short_short_uint(version.revision),
    ))
}

fn gen_heartbeat_frame<W: Write>() -> impl SerializeFn<W> {
    slice(&[
        constants::FRAME_HEARTBEAT,
        0,
        0,
        0,
        0,
        0,
        0,
        constants::FRAME_END,
    ])
}

fn gen_method_frame<'a, W: Write + BackToTheBuffer + 'a>(
    channel_id: ShortUInt,
    class: &'a AMQPClass,
) -> impl SerializeFn<W> + 'a {
    tuple((
        gen_short_short_uint(constants::FRAME_METHOD),
        gen_id(channel_id),
        gen_with_len(gen_class(class)),
        gen_short_short_uint(constants::FRAME_END),
    ))
}

fn gen_content_header_frame<'a, W: Write + BackToTheBuffer + 'a>(
    channel_id: ShortUInt,
    class_id: ShortUInt,
    length: LongLongUInt,
    properties: &'a basic::AMQPProperties,
) -> impl SerializeFn<W> + 'a {
    tuple((
        gen_short_short_uint(constants::FRAME_HEADER),
        gen_id(channel_id),
        gen_with_len(tuple((
            gen_id(class_id),
            gen_short_uint(0 /* weight */),
            gen_long_long_uint(length),
            gen_properties(properties),
        ))),
        gen_short_short_uint(constants::FRAME_END),
    ))
}

fn gen_content_body_frame<'a, W: Write + 'a>(
    channel_id: ShortUInt,
    content: &'a [u8],
) -> impl SerializeFn<W> + 'a {
    tuple((
        gen_short_short_uint(constants::FRAME_BODY),
        gen_id(channel_id),
        gen_long_uint(content.len() as LongUInt),
        slice(content),
        gen_short_short_uint(constants::FRAME_END),
    ))
}
<commit_msg>cleaner heartbeat frame generation<commit_after>use crate::{
    frame::{AMQPFrame, ProtocolVersion},
    protocol::{basic::gen_properties, *},
    types::{generation::*, *},
};
use cookie_factory::{combinator::slice, sequence::tuple};
use std::io::Write;

/// Serialize a frame in the given buffer
pub fn gen_frame<'a, W: Write + BackToTheBuffer + 'a>(
    frame: &'a AMQPFrame,
) -> impl SerializeFn<W> + 'a {
    move |x| match frame {
        AMQPFrame::ProtocolHeader(version) => gen_protocol_header(version)(x),
        AMQPFrame::Heartbeat(channel_id) => gen_heartbeat_frame(*channel_id)(x),
        AMQPFrame::Method(channel_id, method) => gen_method_frame(*channel_id, method)(x),
        AMQPFrame::Header(channel_id, class_id, header) => {
            gen_content_header_frame(*channel_id, *class_id, header.body_size, &header.properties)(
                x,
            )
        }
        AMQPFrame::Body(channel_id, data) => gen_content_body_frame(*channel_id, data)(x),
    }
}

fn gen_protocol_header<W: Write>(version: &ProtocolVersion) -> impl SerializeFn<W> {
    tuple((
        slice(metadata::NAME.as_bytes()),
        gen_short_short_uint(0),
        gen_protocol_version(version),
    ))
}

fn gen_protocol_version<W: Write>(version: &ProtocolVersion) -> impl SerializeFn<W> {
    tuple((
        gen_short_short_uint(version.major),
        gen_short_short_uint(version.minor),
        gen_short_short_uint(version.revision),
    ))
}

fn gen_heartbeat_frame<W: Write>(channel_id: ShortUInt) -> impl SerializeFn<W> {
    tuple((
        gen_short_short_uint(constants::FRAME_HEARTBEAT),
        gen_id(channel_id),
        gen_long_uint(0),
        gen_short_short_uint(constants::FRAME_END),
    ))
}

fn gen_method_frame<'a, W: Write + BackToTheBuffer + 'a>(
    channel_id: ShortUInt,
    class: &'a AMQPClass,
) -> impl SerializeFn<W> + 'a {
    tuple((
        gen_short_short_uint(constants::FRAME_METHOD),
        gen_id(channel_id),
        gen_with_len(gen_class(class)),
        gen_short_short_uint(constants::FRAME_END),
    ))
}

fn gen_content_header_frame<'a, W: Write + BackToTheBuffer + 'a>(
    channel_id: ShortUInt,
    class_id: ShortUInt,
    length: LongLongUInt,
    properties: &'a basic::AMQPProperties,
) -> impl SerializeFn<W> + 'a {
    tuple((
        gen_short_short_uint(constants::FRAME_HEADER),
        gen_id(channel_id),
        gen_with_len(tuple((
            gen_id(class_id),
            gen_short_uint(0 /* weight */),
            gen_long_long_uint(length),
            gen_properties(properties),
        ))),
        gen_short_short_uint(constants::FRAME_END),
    ))
}

fn gen_content_body_frame<'a, W: Write + 'a>(
    channel_id: ShortUInt,
    content: &'a [u8],
) -> impl SerializeFn<W> + 'a {
    tuple((
        gen_short_short_uint(constants::FRAME_BODY),
        gen_id(channel_id),
        gen_long_uint(content.len() as LongUInt),
        slice(content),
        gen_short_short_uint(constants::FRAME_END),
    ))
}
<|endoftext|>


<commit_before>use std::cell::RefCell;
use std::cmp::Ordering;
use std::collections::hash_map::DefaultHasher;
use std::collections::{BTreeSet, HashSet};
use std::hash::{Hash, Hasher};
use std::mem;

type Book = u32;
type GroupedBasket = Vec<Group>;
type Price = u32;
const BOOK_PRICE: Price = 800;

#[derive(Debug, Clone, PartialEq, Eq)]
struct Group(RefCell<BTreeSet<Book>>);

impl Group {
    fn new() -> Group {
        Group(RefCell::new(BTreeSet::new()))
    }

    fn new_containing(book: Book) -> Group {
        let g = Group::new();
        g.0.borrow_mut().insert(book);
        g
    }

    fn price(&self) -> Price {
        (self.0.borrow().len() as Price) * BOOK_PRICE * match self.0.borrow().len() {
            2 => 95,
            3 => 90,
            4 => 80,
            5 => 75,
            _ => 100,
        } / 100
    }
}

impl Ord for Group {
    // we want to order groups first by qty contained DESC, then by lowest value ASC
    fn cmp(&self, other: &Group) -> Ordering {
        match other.0.borrow().len().cmp(&self.0.borrow().len()) {
            Ordering::Equal => {
                if self.0.borrow().is_empty() {
                    Ordering::Equal
                } else {
                    self.0
                        .borrow()
                        .iter()
                        .next()
                        .unwrap()
                        .cmp(other.0.borrow().iter().next().unwrap())
                }
            }
            otherwise => otherwise,
        }
    }
}

impl PartialOrd for Group {
    fn partial_cmp(&self, other: &Group) -> Option<Ordering> {
        Some(self.cmp(other))
    }
}

impl Hash for Group {
    fn hash<H: Hasher>(&self, hasher: &mut H) {
        self.0.borrow().hash(hasher);
    }
}

fn basket_price(basket: &GroupedBasket) -> Price {
    basket.iter().map(|g| g.price()).sum()
}

/// Compute the hash of a GroupedBasket
///
/// Note that we don't actually care at all about the _values_ within
/// the groups, only their lengths. Therefore, let's hash not the actual
/// GB but its lengths.
fn hash_of(basket: &GroupedBasket) -> u64 {
    let lengths = basket
        .iter()
        .map(|g| g.0.borrow().len())
        .collect::<Vec<_>>();
    let mut hasher = DefaultHasher::new();
    lengths.hash(&mut hasher);
    hasher.finish()
}

pub fn lowest_price(books: &[Book]) -> Price {
    DecomposeGroups::new(books)
        .map(|gb| basket_price(&gb))
        .min()
        .unwrap_or(0)
}

struct DecomposeGroups {
    prev_states: HashSet<u64>,
    next: Option<GroupedBasket>,
}

impl Iterator for DecomposeGroups {
    type Item = GroupedBasket;
    fn next(&mut self) -> Option<Self::Item> {
        // our goal here: produce a stream of valid groups, differentiated by their
        // counts, from most compact to most dispersed.
        //
        // Algorithm:
        //  - Start with the most compact groups possible
        //  - If the number of groups == 0 or the max population of any group == 1, return None
        //  - For every item in the most populous group:
        //      - Try removing it and adding it to a smaller group.
        //          - Can any smaller group accept it? if yes, move it there and return
        //  - If it cannot be added to any smaller group, try the next item from this set
        //  - If no item from the most populous group can be added to any smaller group,
        //    then move the last item from the most populous group into a new group, alone,
        //    and return
        let return_value = self.next.clone();
        if let Some(groups) = mem::replace(&mut self.next, None) {
            if !(groups.is_empty() || groups.iter().all(|g| g.0.borrow().len() == 1)) {
                let mut hypothetical;
                for mpg_book in groups[0].0.borrow().iter() {
                    for (idx, other_group) in groups[1..].iter().enumerate() {
                        if !other_group.0.borrow().contains(mpg_book) {
                            hypothetical = groups.clone();
                            hypothetical[0].0.borrow_mut().remove(mpg_book);
                            hypothetical[1 + idx].0.borrow_mut().insert(*mpg_book);
                            hypothetical.sort();
                            let hypothetical_hash = hash_of(&hypothetical);
                            if !self.prev_states.contains(&hypothetical_hash) {
                                self.prev_states.insert(hypothetical_hash);
                                mem::replace(&mut self.next, Some(hypothetical));
                                return return_value;
                            }
                        }
                    }
                }
                // we've gone through all the items of the most populous group,
                // and none of them can be added to any other existing group.
                // We need to create a new group;
                let book = {
                    let backing_bt = groups[0].0.borrow();
                    let mut book_iter = backing_bt.iter();
                    book_iter.next().unwrap().clone()
                };
                hypothetical = groups.clone();
                hypothetical[0].0.borrow_mut().remove(&book);
                hypothetical.push(Group::new_containing(book));
                hypothetical.sort();
                self.prev_states.insert(hash_of(&hypothetical));
                mem::replace(&mut self.next, Some(hypothetical));
            }
        }
        return_value
    }
}

impl DecomposeGroups {
    fn new(books: &[Book]) -> DecomposeGroups {
        let mut book_groups = GroupedBasket::new();
        'nextbook: for book in books {
            for idx in 0..book_groups.len() {
                if !book_groups[idx].0.borrow().contains(&book) {
                    book_groups[idx].0.borrow_mut().insert(*book);
                    continue 'nextbook;
                }
            }
            // if we're here, we still haven't found a place for the book.
            // better add it to a new group
            book_groups.push(Group::new_containing(*book));
        }
        book_groups.sort();

        DecomposeGroups {
            next: Some(book_groups),
            prev_states: HashSet::new(),
        }
    }
}
<commit_msg>book-store: Use iterator instead of `for` loop with index<commit_after>use std::cell::RefCell;
use std::cmp::Ordering;
use std::collections::hash_map::DefaultHasher;
use std::collections::{BTreeSet, HashSet};
use std::hash::{Hash, Hasher};
use std::mem;

type Book = u32;
type GroupedBasket = Vec<Group>;
type Price = u32;
const BOOK_PRICE: Price = 800;

#[derive(Debug, Clone, PartialEq, Eq)]
struct Group(RefCell<BTreeSet<Book>>);

impl Group {
    fn new() -> Group {
        Group(RefCell::new(BTreeSet::new()))
    }

    fn new_containing(book: Book) -> Group {
        let g = Group::new();
        g.0.borrow_mut().insert(book);
        g
    }

    fn price(&self) -> Price {
        (self.0.borrow().len() as Price) * BOOK_PRICE * match self.0.borrow().len() {
            2 => 95,
            3 => 90,
            4 => 80,
            5 => 75,
            _ => 100,
        } / 100
    }
}

impl Ord for Group {
    // we want to order groups first by qty contained DESC, then by lowest value ASC
    fn cmp(&self, other: &Group) -> Ordering {
        match other.0.borrow().len().cmp(&self.0.borrow().len()) {
            Ordering::Equal => {
                if self.0.borrow().is_empty() {
                    Ordering::Equal
                } else {
                    self.0
                        .borrow()
                        .iter()
                        .next()
                        .unwrap()
                        .cmp(other.0.borrow().iter().next().unwrap())
                }
            }
            otherwise => otherwise,
        }
    }
}

impl PartialOrd for Group {
    fn partial_cmp(&self, other: &Group) -> Option<Ordering> {
        Some(self.cmp(other))
    }
}

impl Hash for Group {
    fn hash<H: Hasher>(&self, hasher: &mut H) {
        self.0.borrow().hash(hasher);
    }
}

fn basket_price(basket: &GroupedBasket) -> Price {
    basket.iter().map(|g| g.price()).sum()
}

/// Compute the hash of a GroupedBasket
///
/// Note that we don't actually care at all about the _values_ within
/// the groups, only their lengths. Therefore, let's hash not the actual
/// GB but its lengths.
fn hash_of(basket: &GroupedBasket) -> u64 {
    let lengths = basket
        .iter()
        .map(|g| g.0.borrow().len())
        .collect::<Vec<_>>();
    let mut hasher = DefaultHasher::new();
    lengths.hash(&mut hasher);
    hasher.finish()
}

pub fn lowest_price(books: &[Book]) -> Price {
    DecomposeGroups::new(books)
        .map(|gb| basket_price(&gb))
        .min()
        .unwrap_or(0)
}

struct DecomposeGroups {
    prev_states: HashSet<u64>,
    next: Option<GroupedBasket>,
}

impl Iterator for DecomposeGroups {
    type Item = GroupedBasket;
    fn next(&mut self) -> Option<Self::Item> {
        // our goal here: produce a stream of valid groups, differentiated by their
        // counts, from most compact to most dispersed.
        //
        // Algorithm:
        //  - Start with the most compact groups possible
        //  - If the number of groups == 0 or the max population of any group == 1, return None
        //  - For every item in the most populous group:
        //      - Try removing it and adding it to a smaller group.
        //          - Can any smaller group accept it? if yes, move it there and return
        //  - If it cannot be added to any smaller group, try the next item from this set
        //  - If no item from the most populous group can be added to any smaller group,
        //    then move the last item from the most populous group into a new group, alone,
        //    and return
        let return_value = self.next.clone();
        if let Some(groups) = mem::replace(&mut self.next, None) {
            if !(groups.is_empty() || groups.iter().all(|g| g.0.borrow().len() == 1)) {
                let mut hypothetical;
                for mpg_book in groups[0].0.borrow().iter() {
                    for (idx, other_group) in groups[1..].iter().enumerate() {
                        if !other_group.0.borrow().contains(mpg_book) {
                            hypothetical = groups.clone();
                            hypothetical[0].0.borrow_mut().remove(mpg_book);
                            hypothetical[1 + idx].0.borrow_mut().insert(*mpg_book);
                            hypothetical.sort();
                            let hypothetical_hash = hash_of(&hypothetical);
                            if !self.prev_states.contains(&hypothetical_hash) {
                                self.prev_states.insert(hypothetical_hash);
                                mem::replace(&mut self.next, Some(hypothetical));
                                return return_value;
                            }
                        }
                    }
                }
                // we've gone through all the items of the most populous group,
                // and none of them can be added to any other existing group.
                // We need to create a new group;
                let book = {
                    let backing_bt = groups[0].0.borrow();
                    let mut book_iter = backing_bt.iter();
                    book_iter.next().unwrap().clone()
                };
                hypothetical = groups.clone();
                hypothetical[0].0.borrow_mut().remove(&book);
                hypothetical.push(Group::new_containing(book));
                hypothetical.sort();
                self.prev_states.insert(hash_of(&hypothetical));
                mem::replace(&mut self.next, Some(hypothetical));
            }
        }
        return_value
    }
}

impl DecomposeGroups {
    fn new(books: &[Book]) -> DecomposeGroups {
        let mut book_groups = GroupedBasket::new();
        'nextbook: for book in books {
            for Group(book_group) in book_groups.iter() {
                if !book_group.borrow().contains(&book) {
                    book_group.borrow_mut().insert(*book);
                    continue 'nextbook;
                }
            }
            // if we're here, we still haven't found a place for the book.
            // better add it to a new group
            book_groups.push(Group::new_containing(*book));
        }
        book_groups.sort();

        DecomposeGroups {
            next: Some(book_groups),
            prev_states: HashSet::new(),
        }
    }
}
<|endoftext|>


<commit_before>use crate::{error::{Error,
                    Result},
            PRODUCT,
            VERSION};
use habitat_common::{self,
                     command::package::install::{InstallHookMode,
                                                 InstallMode,
                                                 InstallSource,
                                                 LocalPackageUsage},
                     outputln,
                     ui::UIWriter};
use habitat_core::{env as henv,
                   fs::{self,
                        FS_ROOT_PATH},
                   package::{PackageIdent,
                             PackageInstall},
                   ChannelIdent,
                   AUTH_TOKEN_ENVVAR};
use std::path::Path;

static LOGKEY: &'static str = "UT";

/// Helper function for use in the Supervisor to handle lower-level
/// arguments needed for installing a package.
pub fn install<T>(ui: &mut T,
                  url: &str,
                  install_source: &InstallSource,
                  channel: &ChannelIdent)
                  -> Result<PackageInstall>
    where T: UIWriter
{
    let fs_root_path = Path::new(&*FS_ROOT_PATH);
    let auth_token = match henv::var(AUTH_TOKEN_ENVVAR) {
        Ok(v) => Some(v),
        Err(_) => None,
    };

    habitat_common::command::package::install::start(ui,
                                                     url,
                                                     // We currently need this to be an option due
                                                     // to how
                                                     // the depot
                                                     // client is written. Anything that calls the
                                                     // current
                                                     // function, though, should always have a
                                                     // channel. We
                                                     // should
                                                     // push this "Option-ness" as far down the
                                                     // stack as we
                                                     // can,
                                                     // with the ultimate goal of eliminating it
                                                     // altogether.
                                                     channel,
                                                     install_source,
                                                     PRODUCT,
                                                     VERSION,
                                                     fs_root_path,
                                                     &fs::cache_artifact_path(None::<String>),
                                                     auth_token.as_ref().map(String::as_str),
                                                     // TODO fn: pass through and enable offline
                                                     // install
                                                     // mode
                                                     &InstallMode::default(),
                                                     // TODO (CM): pass through and enable
                                                     // ignore-local
                                                     // mode
                                                     &LocalPackageUsage::default(),
                                                     // Install hooks are run when the supervisor
                                                     // loads the
                                                     // package
                                                     // in add_service so it is repetitive to run
                                                     // them here
                                                     InstallHookMode::Ignore).map_err(Error::from)
}

/// Given an InstallSource, install a new package only if an existing
/// one that can satisfy the package identifier is not already
/// present.
///
/// Return the PackageInstall corresponding to the package that was
/// installed, or was pre-existing.
pub fn satisfy_or_install<T>(ui: &mut T,
                             install_source: &InstallSource,
                             bldr_url: &str,
                             channel: &ChannelIdent)
                             -> Result<PackageInstall>
    where T: UIWriter
{
    match installed(install_source) {
        Some(package) => Ok(package),
        None => install(ui, bldr_url, install_source, channel),
    }.and_then(|installed| {
         if installed.is_runnable() {
             Ok(installed)
         } else {
             outputln!("Can't start non-runnable service: {}", installed.ident());
             Err(Error::PackageNotRunnable(installed.ident().clone()))
         }
     })
}

/// Returns an installed package for the given ident, if one is present.
pub fn installed<T>(ident: T) -> Option<PackageInstall>
    where T: AsRef<PackageIdent>
{
    let fs_root_path = Path::new(&*FS_ROOT_PATH);
    PackageInstall::load(ident.as_ref(), Some(fs_root_path)).ok()
}
<commit_msg>[PR Feedback] Reformat for readability<commit_after>use crate::{error::{Error,
                    Result},
            PRODUCT,
            VERSION};
use habitat_common::{command::package::install::{self as install_cmd,
                                                 InstallHookMode,
                                                 InstallMode,
                                                 InstallSource,
                                                 LocalPackageUsage},
                     outputln,
                     ui::UIWriter};
use habitat_core::{env as henv,
                   fs::{self,
                        FS_ROOT_PATH},
                   package::{PackageIdent,
                             PackageInstall},
                   ChannelIdent,
                   AUTH_TOKEN_ENVVAR};
use std::path::Path;

static LOGKEY: &'static str = "UT";

/// Helper function for use in the Supervisor to handle lower-level
/// arguments needed for installing a package.
pub fn install<T>(ui: &mut T,
                  url: &str,
                  install_source: &InstallSource,
                  channel: &ChannelIdent)
                  -> Result<PackageInstall>
    where T: UIWriter
{
    let fs_root_path = Path::new(&*FS_ROOT_PATH);
    let auth_token = match henv::var(AUTH_TOKEN_ENVVAR) {
        Ok(v) => Some(v),
        Err(_) => None,
    };
    install_cmd::start(ui,
                       url,
                       channel,
                       install_source,
                       PRODUCT,
                       VERSION,
                       fs_root_path,
                       &fs::cache_artifact_path(None::<String>),
                       auth_token.as_ref().map(String::as_str),
                       &InstallMode::default(),
                       &LocalPackageUsage::default(),
                       // Install hooks are run when the supervisor
                       // loads the package in add_service so it is
                       // repetitive to run them here
                       InstallHookMode::Ignore).map_err(Error::from)
}

/// Given an InstallSource, install a new package only if an existing
/// one that can satisfy the package identifier is not already
/// present.
///
/// Return the PackageInstall corresponding to the package that was
/// installed, or was pre-existing.
pub fn satisfy_or_install<T>(ui: &mut T,
                             install_source: &InstallSource,
                             bldr_url: &str,
                             channel: &ChannelIdent)
                             -> Result<PackageInstall>
    where T: UIWriter
{
    match installed(install_source) {
        Some(package) => Ok(package),
        None => install(ui, bldr_url, install_source, channel),
    }.and_then(|installed| {
         if installed.is_runnable() {
             Ok(installed)
         } else {
             outputln!("Can't start non-runnable service: {}", installed.ident());
             Err(Error::PackageNotRunnable(installed.ident().clone()))
         }
     })
}

/// Returns an installed package for the given ident, if one is present.
pub fn installed<T>(ident: T) -> Option<PackageInstall>
    where T: AsRef<PackageIdent>
{
    let fs_root_path = Path::new(&*FS_ROOT_PATH);
    PackageInstall::load(ident.as_ref(), Some(fs_root_path)).ok()
}
<|endoftext|>