<commit_before>// Copyright (c) 2018 Chef Software Inc. and/or applicable contributors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use clap;
use std::fs;
use std::io::Write;
use std::path::PathBuf;

use common::ui::{Status, UIWriter, UI};
use export_docker;
use export_docker::Result;
use export_k8s::{Manifest, ManifestJson, PersistentStorage};

use chartfile::ChartFile;
use deps::Deps;
use values::Values;

pub struct Chart<'a> {
    chartdir: PathBuf,
    chartfile: ChartFile,
    manifest_template: Option<ManifestJson>,
    values: Values,
    deps: Deps,
    ui: &'a mut UI,
}

impl<'a> Chart<'a> {
    pub fn new_for_cli_matches(ui: &'a mut UI, matches: &clap::ArgMatches) -> Result<Self> {
        let image = if !matches.is_present("NO_DOCKER_IMAGE") {
            export_docker::export_for_cli_matches(ui, &matches)?
        } else {
            None
        };
        let manifest = Manifest::new_from_cli_matches(ui, &matches, image)?;
        let chartfile = ChartFile::new_from_cli_matches(&matches, &manifest.pkg_ident)?;
        let deps = Deps::new_for_cli_matches(&matches);

        let mut chartdir = PathBuf::new();
        if let Some(o) = matches.value_of_os("OUTPUTDIR") {
            chartdir.push(o);
        }
        chartdir.push(&chartfile.name);

        Ok(Self::new_for_manifest(
            manifest, chartdir, chartfile, deps, ui,
        ))
    }

    fn new_for_manifest(
        manifest: Manifest,
        chartdir: PathBuf,
        chartfile: ChartFile,
        deps: Deps,
        ui: &'a mut UI,
    ) -> Self {
        let mut manifest_template = ManifestJson {
            value: json!({
            "metadata_name": "{{.Values.metadataName}}",
            "service_name": "{{.Values.serviceName}}",
            "image": "{{.Values.imageName}}",
            "count": "{{.Values.instanceCount}}",
            "service_topology": "{{.Values.serviceTopology}}",
            "service_group": manifest.service_group
                .as_ref()
                .map(|_| "{{.Values.serviceGroup}}"),
            "config": manifest.config
                .as_ref()
                .map(|_| "{{.Values.config}}"),
            "ring_secret_name": manifest.ring_secret_name
                .as_ref()
                .map(|_| "{{.Values.ringSecretName}}"),
            "persistent_storage": manifest.persistent_storage
                .as_ref()
                .map(|_| {
                    PersistentStorage {
                        size: "{{.Values.persistentStorageSize}}".to_string(),
                        path: "{{.Values.persistentStoragePath}}".to_string(),
                        class: "{{.Values.persistentStorageClass}}".to_string(),
                    }.to_json()
                }),
            }),
        };

        let mut values = Values::new();
        values.add_entry("metadataName", &manifest.metadata_name);
        values.add_entry("serviceName", &manifest.pkg_ident.name);
        values.add_entry("imageName", &manifest.image);
        values.add_entry("instanceCount", &manifest.count.to_string());
        values.add_entry("serviceTopology", &manifest.service_topology.to_string());
        if let Some(ref group) = manifest.service_group {
            values.add_entry("serviceGroup", group);
        }
        if let Some(ref config) = manifest.config {
            values.add_entry("config", config);
        }
        if let Some(ref name) = manifest.ring_secret_name {
            values.add_entry("ringSecretName", name);
        }
        if let Some(ref persistent_storage) = manifest.persistent_storage {
            values.add_entry("persistentStorageSize", &persistent_storage.size);
            values.add_entry("persistentStoragePath", &persistent_storage.path);
            values.add_entry("persistentStorageClass", &persistent_storage.class);
        }

        let mut binds = Vec::new();
        for (i, bind) in manifest.binds.iter().enumerate() {
            let name_var = format!("bindName{}", i);
            let service_var = format!("bindService{}", i);
            let group_var = format!("bindGroup{}", i);

            values.add_entry(&name_var, &bind.name);
            values.add_entry(&service_var, &bind.service_group.service());
            values.add_entry(&group_var, &bind.service_group.group());

            let json = json!({
                "name": format!("{{{{.Values.{}}}}}", name_var),
                "service": format!("{{{{.Values.{}}}}}", service_var),
                "group": format!("{{{{.Values.{}}}}}", group_var),
            });

            binds.push(json);
        }
        manifest_template.value["binds"] = json!(binds);

        Chart {
            chartdir: chartdir,
            chartfile: chartfile,
            manifest_template: Some(manifest_template),
            values: values,
            deps: deps,
            ui: ui,
        }
    }

    pub fn generate(mut self) -> Result<()> {
        self.ui.status(
            Status::Creating,
            format!("directory `{}`", self.chartdir.display()),
        )?;
        fs::create_dir_all(&self.chartdir)?;

        self.generate_chartfile()?;
        self.generate_values()?;
        self.generate_manifest_template()?;
        self.generate_deps()?;

        self.download_deps()
    }

    fn generate_chartfile(&mut self) -> Result<()> {
        let mut write = self.create_file("Chart.yaml")?;
        let out = self.chartfile.into_string()?;

        write.write(out.as_bytes())?;

        Ok(())
    }

    fn generate_manifest_template(&mut self) -> Result<()> {
        let mut path = self.chartdir.clone();
        path.push("templates");
        self.ui
            .status(Status::Creating, format!("directory `{}`", path.display()))?;
        fs::create_dir_all(&path)?;

        path.push("habitat.yaml");
        self.ui
            .status(Status::Creating, format!("file `{}`", path.display()))?;
        let mut write = fs::File::create(path)?;
        let out: String = self.manifest_template
            .take()
            .expect("generate_manifest_template() called more than once")
            .into();

        write.write(out.as_bytes())?;

        Ok(())
    }

    fn generate_values(&mut self) -> Result<()> {
        let mut write = self.create_file("values.yaml")?;
        self.values.generate(&mut write)?;

        Ok(())
    }

    fn generate_deps(&mut self) -> Result<()> {
        let mut write = self.create_file("requirements.yaml")?;
        self.deps.generate(&mut write)?;

        Ok(())
    }

    fn download_deps(&mut self) -> Result<()> {
        self.deps.download(&self.chartdir, self.ui)
    }

    fn create_file(&mut self, name: &str) -> Result<fs::File> {
        let mut path = self.chartdir.clone();
        path.push(name);
        self.ui
            .status(Status::Creating, format!("file `{}`", path.display()))?;

        fs::File::create(path).map_err(From::from)
    }
}
<commit_msg>pkg-export-helm: Handle environment variable fields in manifest<commit_after>// Copyright (c) 2018 Chef Software Inc. and/or applicable contributors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use clap;
use std::fs;
use std::io::Write;
use std::path::PathBuf;

use common::ui::{Status, UIWriter, UI};
use export_docker;
use export_docker::Result;
use export_k8s::{Manifest, ManifestJson, PersistentStorage};

use chartfile::ChartFile;
use deps::Deps;
use values::Values;

pub struct Chart<'a> {
    chartdir: PathBuf,
    chartfile: ChartFile,
    manifest_template: Option<ManifestJson>,
    values: Values,
    deps: Deps,
    ui: &'a mut UI,
}

impl<'a> Chart<'a> {
    pub fn new_for_cli_matches(ui: &'a mut UI, matches: &clap::ArgMatches) -> Result<Self> {
        let image = if !matches.is_present("NO_DOCKER_IMAGE") {
            export_docker::export_for_cli_matches(ui, &matches)?
        } else {
            None
        };
        let manifest = Manifest::new_from_cli_matches(ui, &matches, image)?;
        let chartfile = ChartFile::new_from_cli_matches(&matches, &manifest.pkg_ident)?;
        let deps = Deps::new_for_cli_matches(&matches);

        let mut chartdir = PathBuf::new();
        if let Some(o) = matches.value_of_os("OUTPUTDIR") {
            chartdir.push(o);
        }
        chartdir.push(&chartfile.name);

        Ok(Self::new_for_manifest(
            manifest, chartdir, chartfile, deps, ui,
        ))
    }

    fn new_for_manifest(
        manifest: Manifest,
        chartdir: PathBuf,
        chartfile: ChartFile,
        deps: Deps,
        ui: &'a mut UI,
    ) -> Self {
        let mut manifest_template = ManifestJson {
            value: json!({
            "metadata_name": "{{.Values.metadataName}}",
            "service_name": "{{.Values.serviceName}}",
            "image": "{{.Values.imageName}}",
            "count": "{{.Values.instanceCount}}",
            "service_topology": "{{.Values.serviceTopology}}",
            "service_group": manifest.service_group
                .as_ref()
                .map(|_| "{{.Values.serviceGroup}}"),
            "config": manifest.config
                .as_ref()
                .map(|_| "{{.Values.config}}"),
            "ring_secret_name": manifest.ring_secret_name
                .as_ref()
                .map(|_| "{{.Values.ringSecretName}}"),
            "persistent_storage": manifest.persistent_storage
                .as_ref()
                .map(|_| {
                    PersistentStorage {
                        size: "{{.Values.persistentStorageSize}}".to_string(),
                        path: "{{.Values.persistentStoragePath}}".to_string(),
                        class: "{{.Values.persistentStorageClass}}".to_string(),
                    }.to_json()
                }),
            }),
        };

        let mut values = Values::new();
        values.add_entry("metadataName", &manifest.metadata_name);
        values.add_entry("serviceName", &manifest.pkg_ident.name);
        values.add_entry("imageName", &manifest.image);
        values.add_entry("instanceCount", &manifest.count.to_string());
        values.add_entry("serviceTopology", &manifest.service_topology.to_string());
        if let Some(ref group) = manifest.service_group {
            values.add_entry("serviceGroup", group);
        }
        if let Some(ref config) = manifest.config {
            values.add_entry("config", config);
        }
        if let Some(ref name) = manifest.ring_secret_name {
            values.add_entry("ringSecretName", name);
        }
        if let Some(ref persistent_storage) = manifest.persistent_storage {
            values.add_entry("persistentStorageSize", &persistent_storage.size);
            values.add_entry("persistentStoragePath", &persistent_storage.path);
            values.add_entry("persistentStorageClass", &persistent_storage.class);
        }

        let mut binds = Vec::new();
        for (i, bind) in manifest.binds.iter().enumerate() {
            let name_var = format!("bindName{}", i);
            let service_var = format!("bindService{}", i);
            let group_var = format!("bindGroup{}", i);

            values.add_entry(&name_var, &bind.name);
            values.add_entry(&service_var, &bind.service_group.service());
            values.add_entry(&group_var, &bind.service_group.group());

            let json = json!({
                "name": format!("{{{{.Values.{}}}}}", name_var),
                "service": format!("{{{{.Values.{}}}}}", service_var),
                "group": format!("{{{{.Values.{}}}}}", group_var),
            });

            binds.push(json);
        }
        manifest_template.value["binds"] = json!(binds);

        let mut environment = Vec::new();
        for (i, envvar) in manifest.environment.iter().enumerate() {
            let name_var = format!("envName{}", i);
            let value_var = format!("envValue{}", i);

            values.add_entry(&name_var, &envvar.name);
            values.add_entry(&value_var, &envvar.value);

            let json = json!({
                "name": format!("{{{{.Values.{}}}}}", name_var),
                "value": format!("{{{{.Values.{}}}}}", value_var),
            });

            environment.push(json);
        }
        manifest_template.value["environment"] = json!(environment);

        Chart {
            chartdir: chartdir,
            chartfile: chartfile,
            manifest_template: Some(manifest_template),
            values: values,
            deps: deps,
            ui: ui,
        }
    }

    pub fn generate(mut self) -> Result<()> {
        self.ui.status(
            Status::Creating,
            format!("directory `{}`", self.chartdir.display()),
        )?;
        fs::create_dir_all(&self.chartdir)?;

        self.generate_chartfile()?;
        self.generate_values()?;
        self.generate_manifest_template()?;
        self.generate_deps()?;

        self.download_deps()
    }

    fn generate_chartfile(&mut self) -> Result<()> {
        let mut write = self.create_file("Chart.yaml")?;
        let out = self.chartfile.into_string()?;

        write.write(out.as_bytes())?;

        Ok(())
    }

    fn generate_manifest_template(&mut self) -> Result<()> {
        let mut path = self.chartdir.clone();
        path.push("templates");
        self.ui
            .status(Status::Creating, format!("directory `{}`", path.display()))?;
        fs::create_dir_all(&path)?;

        path.push("habitat.yaml");
        self.ui
            .status(Status::Creating, format!("file `{}`", path.display()))?;
        let mut write = fs::File::create(path)?;
        let out: String = self.manifest_template
            .take()
            .expect("generate_manifest_template() called more than once")
            .into();

        write.write(out.as_bytes())?;

        Ok(())
    }

    fn generate_values(&mut self) -> Result<()> {
        let mut write = self.create_file("values.yaml")?;
        self.values.generate(&mut write)?;

        Ok(())
    }

    fn generate_deps(&mut self) -> Result<()> {
        let mut write = self.create_file("requirements.yaml")?;
        self.deps.generate(&mut write)?;

        Ok(())
    }

    fn download_deps(&mut self) -> Result<()> {
        self.deps.download(&self.chartdir, self.ui)
    }

    fn create_file(&mut self, name: &str) -> Result<fs::File> {
        let mut path = self.chartdir.clone();
        path.push(name);
        self.ui
            .status(Status::Creating, format!("file `{}`", path.display()))?;

        fs::File::create(path).map_err(From::from)
    }
}
<|endoftext|>


<commit_before>
use prelude::*;

use fixedbitset::FixedBitSet;
use std::collections::HashSet;
use std::marker::PhantomData;

use visit::{
    GraphBase,
    IntoNeighbors,
    IntoNodeIdentifiers,
    IntoNodeReferences,
    IntoNeighborsDirected,
    NodeIndexable,
    Visitable,
    VisitMap,
    GraphProp,
    IntoEdges,
    IntoEdgeReferences,
};
use visit::{Data, NodeCompactIndexable, NodeCount};

/// A graph filter for nodes.
pub trait FilterNode<N>
{
    fn include_node(&self, node: N) -> bool { let _ = node; true }
}

impl<F, N> FilterNode<N> for F
    where F: Fn(N) -> bool,
{
    fn include_node(&self, n: N) -> bool {
        (*self)(n)
    }
}

/// This filter includes the nodes that are contained in the set.
impl<N> FilterNode<N> for FixedBitSet
    where FixedBitSet: VisitMap<N>,
{
    fn include_node(&self, n: N) -> bool {
        self.is_visited(&n)
    }
}

/// This filter includes the nodes that are contained in the set.
impl<N, S> FilterNode<N> for HashSet<N, S>
    where HashSet<N, S>: VisitMap<N>,
{
    fn include_node(&self, n: N) -> bool {
        self.is_visited(&n)
    }
}

/// A node-filtered adaptor of a graph.
#[derive(Copy, Clone, Debug)]
pub struct NodeFiltered<G, F>(pub G, pub F);

impl<F, G> NodeFiltered<G, F>
    where G: GraphBase,
          F: Fn(G::NodeId) -> bool,
{
    /// Create an `NodeFiltered` adaptor from the closure `filter`.
    pub fn from_fn(graph: G, filter: F) -> Self {
        NodeFiltered(graph, filter)
    }
}

impl<G, F> GraphBase for NodeFiltered<G, F> where G: GraphBase {
    type NodeId = G::NodeId;
    type EdgeId = G::EdgeId;
}

impl<'a, G, F> IntoNeighbors for &'a NodeFiltered<G, F>
    where G: IntoNeighbors,
          F: FilterNode<G::NodeId>,
{
    type Neighbors = NodeFilteredNeighbors<'a, G::Neighbors, F>;
    fn neighbors(self, n: G::NodeId) -> Self::Neighbors {
        NodeFilteredNeighbors {
            include_source: self.1.include_node(n),
            iter: self.0.neighbors(n),
            f: &self.1,
        }
    }
}

/// A filtered neighbors iterator.
pub struct NodeFilteredNeighbors<'a, I, F: 'a>
{
    include_source: bool,
    iter: I,
    f: &'a F,
}

impl<'a, I, F> Iterator for NodeFilteredNeighbors<'a, I, F>
    where I: Iterator,
          I::Item: Copy,
          F: FilterNode<I::Item>,
{
    type Item = I::Item;
    fn next(&mut self) -> Option<Self::Item> {
        let f = self.f;
        if !self.include_source {
            None
        } else {
            (&mut self.iter).filter(move |&target| f.include_node(target)).next()
        }
    }
}

impl<'a, G, F> IntoNeighborsDirected for &'a NodeFiltered<G, F>
    where G: IntoNeighborsDirected,
          F: FilterNode<G::NodeId>,
{
    type NeighborsDirected = NodeFilteredNeighbors<'a, G::NeighborsDirected, F>;
    fn neighbors_directed(self, n: G::NodeId, dir: Direction)
        -> Self::NeighborsDirected {
        NodeFilteredNeighbors {
            include_source: self.1.include_node(n),
            iter: self.0.neighbors_directed(n, dir),
            f: &self.1,
        }
    }
}

impl<'a, G, F> IntoNodeIdentifiers for &'a NodeFiltered<G, F>
    where G: IntoNodeIdentifiers,
          F: FilterNode<G::NodeId>,
{
    type NodeIdentifiers = NodeFilteredNeighbors<'a, G::NodeIdentifiers, F>;
    fn node_identifiers(self) -> Self::NodeIdentifiers {
        NodeFilteredNeighbors {
            include_source: true,
            iter: self.0.node_identifiers(),
            f: &self.1,
        }
    }
}

macro_rules! access0 {
    ($e:expr) => ($e.0)
}

NodeIndexable!{delegate_impl [[G, F], G, NodeFiltered<G, F>, access0]}
GraphProp!{delegate_impl [[G, F], G, NodeFiltered<G, F>, access0]}
Visitable!{delegate_impl [[G, F], G, NodeFiltered<G, F>, access0]}

/// A graph filter for edges
pub trait FilterEdge<Edge>
{
    /// The default implementation is to include all edges
    fn include_edge(&self, edge: Edge) -> bool { let _ = edge; true }
}

impl<F, N> FilterEdge<N> for F
    where F: Fn(N) -> bool,
{
    fn include_edge(&self, n: N) -> bool {
        (*self)(n)
    }
}

/// An edge-filtered adaptor of a graph.
///
/// The adaptor may filter out edges. The filter implements the trait
/// `FilterEdge`. Closures of type `Fn(G::EdgeRef) -> bool` already
/// implement this trait.
///
/// The filter may use edge source, target, id, and weight to select whether to
/// include the edge or not.
#[derive(Copy, Clone, Debug)]
pub struct EdgeFiltered<G, F>(pub G, pub F);

impl<F, G> EdgeFiltered<G, F>
    where G: IntoEdgeReferences,
          F: Fn(G::EdgeRef) -> bool,
{
    /// Create an `EdgeFiltered` adaptor from the closure `filter`.
    pub fn from_fn(graph: G, filter: F) -> Self {
        EdgeFiltered(graph, filter)
    }
}

impl<G, F> GraphBase for EdgeFiltered<G, F> where G: GraphBase {
    type NodeId = G::NodeId;
    type EdgeId = G::EdgeId;
}

impl<'a, G, F> IntoNeighbors for &'a EdgeFiltered<G, F>
    where G: IntoEdges,
          F: FilterEdge<G::EdgeRef>,
{
    type Neighbors = EdgeFilteredNeighbors<'a, G, F>;
    fn neighbors(self, n: G::NodeId) -> Self::Neighbors {
        EdgeFilteredNeighbors {
            iter: self.0.edges(n),
            f: &self.1,
        }
    }
}

/// A filtered neighbors iterator.
pub struct EdgeFilteredNeighbors<'a, G, F: 'a>
    where G: IntoEdges,
{
    iter: G::Edges,
    f: &'a F,
}

impl<'a, G, F> Iterator for EdgeFilteredNeighbors<'a, G, F>
    where F: FilterEdge<G::EdgeRef>,
          G: IntoEdges,
{
    type Item = G::NodeId;
    fn next(&mut self) -> Option<Self::Item> {
        let f = self.f;
        (&mut self.iter).filter_map(move |edge| {
            if f.include_edge(edge) {
                Some(edge.target())
            } else { None }
        }).next()
    }
}

impl<'a, G, F> IntoEdgeReferences for &'a EdgeFiltered<G, F>
    where G: IntoEdgeReferences,
          F: FilterEdge<G::EdgeRef>,
{
    type EdgeRef = G::EdgeRef;
    type EdgeReferences = EdgeFilteredEdges<'a, G, G::EdgeReferences, F>;
    fn edge_references(self) -> Self::EdgeReferences {
        EdgeFilteredEdges {
            graph: PhantomData,
            iter: self.0.edge_references(),
            f: &self.1,
        }
    }
}

impl<'a, G, F> IntoEdges for &'a EdgeFiltered<G, F>
    where G: IntoEdges,
          F: FilterEdge<G::EdgeRef>,
{
    type Edges = EdgeFilteredEdges<'a, G, G::Edges, F>;
    fn edges(self, n: G::NodeId) -> Self::Edges {
        EdgeFilteredEdges {
            graph: PhantomData,
            iter: self.0.edges(n),
            f: &self.1,
        }
    }
}

/// A filtered edges iterator
pub struct EdgeFilteredEdges<'a, G, I, F: 'a>
{
    graph: PhantomData<G>,
    iter: I,
    f: &'a F,
}

impl<'a, G, I, F> Iterator for EdgeFilteredEdges<'a, G, I, F>
    where F: FilterEdge<G::EdgeRef>,
          G: IntoEdgeReferences,
          I: Iterator<Item=G::EdgeRef>,
{
    type Item = I::Item;
    fn next(&mut self) -> Option<Self::Item> {
        let f = self.f;
        (&mut self.iter).filter(move |&edge| f.include_edge(edge)).next()
    }
}

Data!{delegate_impl [[G, F], G, EdgeFiltered<G, F>, access0]}
GraphProp!{delegate_impl [[G, F], G, EdgeFiltered<G, F>, access0]}
IntoNodeIdentifiers!{delegate_impl [['a, G, F], G, &'a EdgeFiltered<G, F>, access0]}
IntoNodeReferences!{delegate_impl [['a, G, F], G, &'a EdgeFiltered<G, F>, access0]}
NodeCompactIndexable!{delegate_impl [[G, F], G, EdgeFiltered<G, F>, access0]}
NodeCount!{delegate_impl [[G, F], G, EdgeFiltered<G, F>, access0]}
NodeIndexable!{delegate_impl [[G, F], G, EdgeFiltered<G, F>, access0]}
Visitable!{delegate_impl [[G, F], G, EdgeFiltered<G, F>, access0]}
<commit_msg>Implement IntoEdges for NodeFiltered<commit_after>
use prelude::*;

use fixedbitset::FixedBitSet;
use std::collections::HashSet;
use std::marker::PhantomData;

use visit::{
    GraphBase,
    IntoNeighbors,
    IntoNodeIdentifiers,
    IntoNodeReferences,
    IntoNeighborsDirected,
    NodeIndexable,
    Visitable,
    VisitMap,
    GraphProp,
    IntoEdges,
    IntoEdgeReferences,
};
use visit::{Data, NodeCompactIndexable, NodeCount};

/// A graph filter for nodes.
pub trait FilterNode<N>
{
    fn include_node(&self, node: N) -> bool { let _ = node; true }
}

impl<F, N> FilterNode<N> for F
    where F: Fn(N) -> bool,
{
    fn include_node(&self, n: N) -> bool {
        (*self)(n)
    }
}

/// This filter includes the nodes that are contained in the set.
impl<N> FilterNode<N> for FixedBitSet
    where FixedBitSet: VisitMap<N>,
{
    fn include_node(&self, n: N) -> bool {
        self.is_visited(&n)
    }
}

/// This filter includes the nodes that are contained in the set.
impl<N, S> FilterNode<N> for HashSet<N, S>
    where HashSet<N, S>: VisitMap<N>,
{
    fn include_node(&self, n: N) -> bool {
        self.is_visited(&n)
    }
}

/// A node-filtered adaptor of a graph.
#[derive(Copy, Clone, Debug)]
pub struct NodeFiltered<G, F>(pub G, pub F);

impl<F, G> NodeFiltered<G, F>
    where G: GraphBase,
          F: Fn(G::NodeId) -> bool,
{
    /// Create an `NodeFiltered` adaptor from the closure `filter`.
    pub fn from_fn(graph: G, filter: F) -> Self {
        NodeFiltered(graph, filter)
    }
}

impl<G, F> GraphBase for NodeFiltered<G, F> where G: GraphBase {
    type NodeId = G::NodeId;
    type EdgeId = G::EdgeId;
}

impl<'a, G, F> IntoNeighbors for &'a NodeFiltered<G, F>
    where G: IntoNeighbors,
          F: FilterNode<G::NodeId>,
{
    type Neighbors = NodeFilteredNeighbors<'a, G::Neighbors, F>;
    fn neighbors(self, n: G::NodeId) -> Self::Neighbors {
        NodeFilteredNeighbors {
            include_source: self.1.include_node(n),
            iter: self.0.neighbors(n),
            f: &self.1,
        }
    }
}

/// A filtered neighbors iterator.
pub struct NodeFilteredNeighbors<'a, I, F: 'a>
{
    include_source: bool,
    iter: I,
    f: &'a F,
}

impl<'a, I, F> Iterator for NodeFilteredNeighbors<'a, I, F>
    where I: Iterator,
          I::Item: Copy,
          F: FilterNode<I::Item>,
{
    type Item = I::Item;
    fn next(&mut self) -> Option<Self::Item> {
        let f = self.f;
        if !self.include_source {
            None
        } else {
            (&mut self.iter).filter(move |&target| f.include_node(target)).next()
        }
    }
}

impl<'a, G, F> IntoNeighborsDirected for &'a NodeFiltered<G, F>
    where G: IntoNeighborsDirected,
          F: FilterNode<G::NodeId>,
{
    type NeighborsDirected = NodeFilteredNeighbors<'a, G::NeighborsDirected, F>;
    fn neighbors_directed(self, n: G::NodeId, dir: Direction)
        -> Self::NeighborsDirected {
        NodeFilteredNeighbors {
            include_source: self.1.include_node(n),
            iter: self.0.neighbors_directed(n, dir),
            f: &self.1,
        }
    }
}

impl<'a, G, F> IntoNodeIdentifiers for &'a NodeFiltered<G, F>
    where G: IntoNodeIdentifiers,
          F: FilterNode<G::NodeId>,
{
    type NodeIdentifiers = NodeFilteredNeighbors<'a, G::NodeIdentifiers, F>;
    fn node_identifiers(self) -> Self::NodeIdentifiers {
        NodeFilteredNeighbors {
            include_source: true,
            iter: self.0.node_identifiers(),
            f: &self.1,
        }
    }
}

impl<'a, G, F> IntoEdgeReferences for &'a NodeFiltered<G, F>
    where G: IntoEdgeReferences,
          F: FilterNode<G::NodeId>,
{
    type EdgeRef = G::EdgeRef;
    type EdgeReferences = NodeFilteredEdgeReferences<'a, G, G::EdgeReferences, F>;
    fn edge_references(self) -> Self::EdgeReferences {
        NodeFilteredEdgeReferences {
            graph: PhantomData,
            iter: self.0.edge_references(),
            f: &self.1,
        }
    }
}

/// A filtered iterator
pub struct NodeFilteredEdgeReferences<'a, G, I, F: 'a>
{
    graph: PhantomData<G>,
    iter: I,
    f: &'a F,
}

impl<'a, G, I, F> Iterator for NodeFilteredEdgeReferences<'a, G, I, F>
    where F: FilterNode<G::NodeId>,
          G: IntoEdgeReferences,
          I: Iterator<Item=G::EdgeRef>,
{
    type Item = I::Item;
    fn next(&mut self) -> Option<Self::Item> {
        let f = self.f;
        (&mut self.iter).filter(move |&edge|
            f.include_node(edge.source()) && f.include_node(edge.target())
        ).next()
    }
}

impl<'a, G, F> IntoEdges for &'a NodeFiltered<G, F>
    where G: IntoEdges,
          F: FilterNode<G::NodeId>,
{
    type Edges = NodeFilteredEdges<'a, G, G::Edges, F>;
    fn edges(self, a: G::NodeId) -> Self::Edges {
        NodeFilteredEdges {
            graph: PhantomData,
            include_source: self.1.include_node(a),
            iter: self.0.edges(a),
            f: &self.1,
        }
    }
}

/// A filtered iterator
pub struct NodeFilteredEdges<'a, G, I, F: 'a>
{
    graph: PhantomData<G>,
    include_source: bool,
    iter: I,
    f: &'a F,
}

impl<'a, G, I, F> Iterator for NodeFilteredEdges<'a, G, I, F>
    where F: FilterNode<G::NodeId>,
          G: IntoEdges,
          I: Iterator<Item=G::EdgeRef>,
{
    type Item = I::Item;
    fn next(&mut self) -> Option<Self::Item> {
        if !self.include_source {
            None
        } else {
            let f = self.f;
            (&mut self.iter).filter(move |&edge|
                                    f.include_node(edge.target())).next()
        }
    }
}

macro_rules! access0 {
    ($e:expr) => ($e.0)
}

Data!{delegate_impl [[G, F], G, NodeFiltered<G, F>, access0]}
NodeIndexable!{delegate_impl [[G, F], G, NodeFiltered<G, F>, access0]}
GraphProp!{delegate_impl [[G, F], G, NodeFiltered<G, F>, access0]}
Visitable!{delegate_impl [[G, F], G, NodeFiltered<G, F>, access0]}

/// A graph filter for edges
pub trait FilterEdge<Edge>
{
    /// The default implementation is to include all edges
    fn include_edge(&self, edge: Edge) -> bool { let _ = edge; true }
}

impl<F, N> FilterEdge<N> for F
    where F: Fn(N) -> bool,
{
    fn include_edge(&self, n: N) -> bool {
        (*self)(n)
    }
}

/// An edge-filtered adaptor of a graph.
///
/// The adaptor may filter out edges. The filter implements the trait
/// `FilterEdge`. Closures of type `Fn(G::EdgeRef) -> bool` already
/// implement this trait.
///
/// The filter may use edge source, target, id, and weight to select whether to
/// include the edge or not.
#[derive(Copy, Clone, Debug)]
pub struct EdgeFiltered<G, F>(pub G, pub F);

impl<F, G> EdgeFiltered<G, F>
    where G: IntoEdgeReferences,
          F: Fn(G::EdgeRef) -> bool,
{
    /// Create an `EdgeFiltered` adaptor from the closure `filter`.
    pub fn from_fn(graph: G, filter: F) -> Self {
        EdgeFiltered(graph, filter)
    }
}

impl<G, F> GraphBase for EdgeFiltered<G, F> where G: GraphBase {
    type NodeId = G::NodeId;
    type EdgeId = G::EdgeId;
}

impl<'a, G, F> IntoNeighbors for &'a EdgeFiltered<G, F>
    where G: IntoEdges,
          F: FilterEdge<G::EdgeRef>,
{
    type Neighbors = EdgeFilteredNeighbors<'a, G, F>;
    fn neighbors(self, n: G::NodeId) -> Self::Neighbors {
        EdgeFilteredNeighbors {
            iter: self.0.edges(n),
            f: &self.1,
        }
    }
}

/// A filtered neighbors iterator.
pub struct EdgeFilteredNeighbors<'a, G, F: 'a>
    where G: IntoEdges,
{
    iter: G::Edges,
    f: &'a F,
}

impl<'a, G, F> Iterator for EdgeFilteredNeighbors<'a, G, F>
    where F: FilterEdge<G::EdgeRef>,
          G: IntoEdges,
{
    type Item = G::NodeId;
    fn next(&mut self) -> Option<Self::Item> {
        let f = self.f;
        (&mut self.iter).filter_map(move |edge| {
            if f.include_edge(edge) {
                Some(edge.target())
            } else { None }
        }).next()
    }
}

impl<'a, G, F> IntoEdgeReferences for &'a EdgeFiltered<G, F>
    where G: IntoEdgeReferences,
          F: FilterEdge<G::EdgeRef>,
{
    type EdgeRef = G::EdgeRef;
    type EdgeReferences = EdgeFilteredEdges<'a, G, G::EdgeReferences, F>;
    fn edge_references(self) -> Self::EdgeReferences {
        EdgeFilteredEdges {
            graph: PhantomData,
            iter: self.0.edge_references(),
            f: &self.1,
        }
    }
}

impl<'a, G, F> IntoEdges for &'a EdgeFiltered<G, F>
    where G: IntoEdges,
          F: FilterEdge<G::EdgeRef>,
{
    type Edges = EdgeFilteredEdges<'a, G, G::Edges, F>;
    fn edges(self, n: G::NodeId) -> Self::Edges {
        EdgeFilteredEdges {
            graph: PhantomData,
            iter: self.0.edges(n),
            f: &self.1,
        }
    }
}

/// A filtered edges iterator
pub struct EdgeFilteredEdges<'a, G, I, F: 'a>
{
    graph: PhantomData<G>,
    iter: I,
    f: &'a F,
}

impl<'a, G, I, F> Iterator for EdgeFilteredEdges<'a, G, I, F>
    where F: FilterEdge<G::EdgeRef>,
          G: IntoEdgeReferences,
          I: Iterator<Item=G::EdgeRef>,
{
    type Item = I::Item;
    fn next(&mut self) -> Option<Self::Item> {
        let f = self.f;
        (&mut self.iter).filter(move |&edge| f.include_edge(edge)).next()
    }
}

Data!{delegate_impl [[G, F], G, EdgeFiltered<G, F>, access0]}
GraphProp!{delegate_impl [[G, F], G, EdgeFiltered<G, F>, access0]}
IntoNodeIdentifiers!{delegate_impl [['a, G, F], G, &'a EdgeFiltered<G, F>, access0]}
IntoNodeReferences!{delegate_impl [['a, G, F], G, &'a EdgeFiltered<G, F>, access0]}
NodeCompactIndexable!{delegate_impl [[G, F], G, EdgeFiltered<G, F>, access0]}
NodeCount!{delegate_impl [[G, F], G, EdgeFiltered<G, F>, access0]}
NodeIndexable!{delegate_impl [[G, F], G, EdgeFiltered<G, F>, access0]}
Visitable!{delegate_impl [[G, F], G, EdgeFiltered<G, F>, access0]}
<|endoftext|>


<commit_before>extern crate futuremio;
extern crate net2;
#[macro_use]
extern crate futures;
extern crate httparse;
extern crate time;
#[macro_use]
extern crate log;
extern crate ssl;

use std::io::{self, Read, Write};
use std::net::SocketAddr;
use std::sync::Arc;
use std::thread;

use futuremio::{Loop, LoopHandle, TcpStream, TcpListener, IoFuture};
use futures::Future;
use futures::io::{TaskIo, Ready};
use futures::stream::Stream;

mod request;
pub use self::request::{Request, RequestHeaders};

mod response;
pub use self::response::Response;

mod io2;
pub use io2::{Parse, Serialize};
use io2::{ParseStream, StreamWriter};

mod date;

pub trait Service<Req, Resp>: Send + Sync + 'static
    where Req: Send + 'static,
          Resp: Send + 'static
{
    type Fut: Future<Item = Resp>;

    fn process(&self, req: Req) -> Self::Fut;
}

impl<Req, Resp, Fut, F> Service<Req, Resp> for F
    where F: Fn(Req) -> Fut + Send + Sync + 'static,
          Fut: Future<Item = Resp>,
          Req: Send + 'static,
          Resp: Send + 'static
{
    type Fut = Fut;

    fn process(&self, req: Req) -> Fut {
        (self)(req)
    }
}

pub struct Server {
    addr: SocketAddr,
    workers: u32,
    ssl: Option<Box<Fn() -> io::Result<ssl::ServerContext> + Send + Sync>>,
}

struct ServerData<S> {
    service: S,
    ssl: Option<Box<Fn() -> io::Result<ssl::ServerContext> + Send + Sync>>,
}

impl Server {
    pub fn new(addr: &SocketAddr) -> Server {
        Server {
            addr: *addr,
            workers: 1,
            ssl: None,
        }
    }

    pub fn workers(&mut self, workers: u32) -> &mut Server {
        if cfg!(unix) {
            self.workers = workers;
        }
        self
    }

    pub fn ssl<F>(&mut self, ssl: F) -> &mut Server
        where F: Fn() -> io::Result<ssl::ServerContext> + Send + Sync + 'static,
    {
        self.ssl = Some(Box::new(ssl));
        self
    }

    pub fn serve<Req, Resp, S>(&mut self, s: S) -> io::Result<()>
        where Req: Parse,
              Resp: Serialize,
              S: Service<Req, Resp>,
              <S::Fut as Future>::Error: From<Req::Error> + From<io::Error>, // TODO: simplify this?
    {
        let data = Arc::new(ServerData {
            service: s,
            ssl: self.ssl.take(),
        });

        let threads = (0..self.workers - 1).map(|i| {
            let mut lp = Loop::new().unwrap();
            let data = data.clone();
            let listener = self.listener(lp.handle());
            thread::Builder::new().name(format!("worker{}", i)).spawn(move || {
                lp.run(listener.and_then(move |l| {
                    l.incoming().for_each(move |(stream, _)| {
                        handle(stream, data.clone());
                        Ok(()) // TODO: error handling
                    })
                }))
            }).unwrap()
        }).collect::<Vec<_>>();

        let mut lp = Loop::new().unwrap();
        let listener = self.listener(lp.handle());
        lp.run(listener.and_then(move |l| {
            l.incoming().for_each(move |(stream, _)| {
                handle(stream, data.clone());
                Ok(()) // TODO: error handling
            })
        })).unwrap();

        for thread in threads {
            thread.join().unwrap().unwrap();
        }

        Ok(())
    }

    fn listener(&self, handle: LoopHandle) -> Box<IoFuture<TcpListener>> {
        let listener = (|| {
            let listener = try!(net2::TcpBuilder::new_v4());
            try!(self.configure_tcp(&listener));
            try!(listener.reuse_address(true));
            try!(listener.bind(&self.addr));
            listener.listen(1024)
        })();

        match listener {
            Ok(l) => TcpListener::from_listener(l, &self.addr, handle),
            Err(e) => futures::failed(e).boxed()
        }
    }

    #[cfg(unix)]
    fn configure_tcp(&self, tcp: &net2::TcpBuilder) -> io::Result<()> {
        use net2::unix::*;

        if self.workers > 1 {
            try!(tcp.reuse_port(true));
        }

        Ok(())
    }

    #[cfg(windows)]
    fn configure_tcp(&self, _tcp: &net2::TcpBuilder) -> io::Result<()> {
        Ok(())
    }
}

trait IoStream: Read + Write + Stream<Item=Ready, Error=io::Error> {}

impl<T: ?Sized> IoStream for T
    where T: Read + Write + Stream<Item=Ready, Error=io::Error>
{}

fn handle<Req, Resp, S>(stream: TcpStream, data: Arc<ServerData<S>>)
    where Req: Parse,
          Resp: Serialize,
          S: Service<Req, Resp>,
          <S::Fut as Future>::Error: From<Req::Error> + From<io::Error>,
{
    let io = match data.ssl {
        Some(ref ssl) => {
            // TODO: don't unwrap here
            Box::new(ssl().unwrap().handshake(stream).unwrap()) as
                Box<IoStream<Item=Ready, Error=io::Error>>
        }
        None => Box::new(stream),
    };
    let io = TaskIo::new(io).map_err(From::from).and_then(|io| {
        let (reader, writer) = io.split();

        let input = ParseStream::new(reader).map_err(From::from);
        let responses = input.and_then(move |req| data.service.process(req));
        StreamWriter::new(writer, responses)
    });

    // Crucially use `.forget()` here instead of returning the future, allows
    // processing multiple separate connections concurrently.
    io.forget();
}
<commit_msg>Fix compile of http crate<commit_after>extern crate futuremio;
extern crate net2;
#[macro_use]
extern crate futures;
extern crate httparse;
extern crate time;
#[macro_use]
extern crate log;
extern crate ssl;

use std::io::{self, Read, Write};
use std::net::SocketAddr;
use std::sync::Arc;
use std::thread;

use futuremio::{Loop, LoopHandle, TcpStream, TcpListener, IoFuture};
use futures::Future;
use futures::io::{TaskIo, Ready};
use futures::stream::Stream;

mod request;
pub use self::request::{Request, RequestHeaders};

mod response;
pub use self::response::Response;

mod io2;
pub use io2::{Parse, Serialize};
use io2::{ParseStream, StreamWriter};

mod date;

pub trait Service<Req, Resp>: Send + Sync + 'static
    where Req: Send + 'static,
          Resp: Send + 'static
{
    type Fut: Future<Item = Resp>;

    fn process(&self, req: Req) -> Self::Fut;
}

impl<Req, Resp, Fut, F> Service<Req, Resp> for F
    where F: Fn(Req) -> Fut + Send + Sync + 'static,
          Fut: Future<Item = Resp>,
          Req: Send + 'static,
          Resp: Send + 'static
{
    type Fut = Fut;

    fn process(&self, req: Req) -> Fut {
        (self)(req)
    }
}

pub struct Server {
    addr: SocketAddr,
    workers: u32,
    ssl: Option<Box<Fn() -> io::Result<ssl::ServerContext> + Send + Sync>>,
}

struct ServerData<S> {
    service: S,
    ssl: Option<Box<Fn() -> io::Result<ssl::ServerContext> + Send + Sync>>,
}

impl Server {
    pub fn new(addr: &SocketAddr) -> Server {
        Server {
            addr: *addr,
            workers: 1,
            ssl: None,
        }
    }

    pub fn workers(&mut self, workers: u32) -> &mut Server {
        if cfg!(unix) {
            self.workers = workers;
        }
        self
    }

    pub fn ssl<F>(&mut self, ssl: F) -> &mut Server
        where F: Fn() -> io::Result<ssl::ServerContext> + Send + Sync + 'static,
    {
        self.ssl = Some(Box::new(ssl));
        self
    }

    pub fn serve<Req, Resp, S>(&mut self, s: S) -> io::Result<()>
        where Req: Parse,
              Resp: Serialize,
              S: Service<Req, Resp>,
              <S::Fut as Future>::Error: From<Req::Error> + From<io::Error>, // TODO: simplify this?
    {
        let data = Arc::new(ServerData {
            service: s,
            ssl: self.ssl.take(),
        });

        let threads = (0..self.workers - 1).map(|i| {
            let mut lp = Loop::new().unwrap();
            let data = data.clone();
            let listener = self.listener(lp.handle());
            thread::Builder::new().name(format!("worker{}", i)).spawn(move || {
                lp.run(listener.and_then(move |l| {
                    l.incoming().for_each(move |(stream, _)| {
                        handle(stream, data.clone());
                        Ok(()) // TODO: error handling
                    })
                }))
            }).unwrap()
        }).collect::<Vec<_>>();

        let mut lp = Loop::new().unwrap();
        let listener = self.listener(lp.handle());
        lp.run(listener.and_then(move |l| {
            l.incoming().for_each(move |(stream, _)| {
                handle(stream, data.clone());
                Ok(()) // TODO: error handling
            })
        })).unwrap();

        for thread in threads {
            thread.join().unwrap().unwrap();
        }

        Ok(())
    }

    fn listener(&self, handle: LoopHandle) -> Box<IoFuture<TcpListener>> {
        let listener = (|| {
            let listener = try!(net2::TcpBuilder::new_v4());
            try!(self.configure_tcp(&listener));
            try!(listener.reuse_address(true));
            try!(listener.bind(&self.addr));
            listener.listen(1024)
        })();

        match listener {
            Ok(l) => TcpListener::from_listener(l, &self.addr, handle),
            Err(e) => futures::failed(e).boxed()
        }
    }

    #[cfg(unix)]
    fn configure_tcp(&self, tcp: &net2::TcpBuilder) -> io::Result<()> {
        use net2::unix::*;

        if self.workers > 1 {
            try!(tcp.reuse_port(true));
        }

        Ok(())
    }

    #[cfg(windows)]
    fn configure_tcp(&self, _tcp: &net2::TcpBuilder) -> io::Result<()> {
        Ok(())
    }
}

trait IoStream: Read + Write + Stream<Item=Ready, Error=io::Error> {}

impl<T: ?Sized> IoStream for T
    where T: Read + Write + Stream<Item=Ready, Error=io::Error>
{}

fn handle<Req, Resp, S>(stream: TcpStream, data: Arc<ServerData<S>>)
    where Req: Parse,
          Resp: Serialize,
          S: Service<Req, Resp>,
          <S::Fut as Future>::Error: From<Req::Error> + From<io::Error>,
{
    let io = match data.ssl {
        Some(ref ssl) => {
            ssl().unwrap().handshake(stream).map(|b| {
                Box::new(b) as
                    Box<IoStream<Item=Ready, Error=io::Error>>
            }).boxed()
        }
        None => {
            let stream = Box::new(stream) as
                    Box<IoStream<Item=Ready, Error=io::Error>>;
            futures::finished(stream).boxed()
        }
    };
    let io = io.and_then(|io| TaskIo::new(io)).map_err(From::from).and_then(|io| {
        let (reader, writer) = io.split();

        let input = ParseStream::new(reader).map_err(From::from);
        let responses = input.and_then(move |req| data.service.process(req));
        StreamWriter::new(writer, responses)
    });

    // Crucially use `.forget()` here instead of returning the future, allows
    // processing multiple separate connections concurrently.
    io.forget();
}
<|endoftext|>


<commit_before>
/// Define a trait as usual, and a macro that can be used to instantiate
/// implementations of it.
///
/// Well almost: There *must* be markers of `@section type`, `@section self`
/// and `@section self_ref` before the associated types, `self` methods
/// and `&self` methods respectively.
macro_rules! trait_template {
    ($(#[$doc:meta])* pub trait $name:ident $($methods:tt)*) => {
        macro_rules! $name {
            ($m:ident $extra:tt) => {
                $m! {
                    $extra
                    pub trait $name $($methods)*
                }
            }
        }
        $(#[$doc])*
        remove_sections! { []
            pub trait $name $($methods)*
        }
    }
}

macro_rules! remove_sections_inner {
    ([$($stack:tt)*]) => {
        $($stack)*
    };
    ([$($stack:tt)*] @section $x:ident $($t:tt)*) => {
        remove_sections_inner!([$($stack)*] $($t)*);
    };
    ([$($stack:tt)*] $t:tt $($tail:tt)*) => {
        remove_sections_inner!([$($stack)* $t] $($tail)*);
    };
}

// recurse once into { }, but not more
macro_rules! remove_sections {
    ([$($stack:tt)*]) => {
        $($stack)*
    };
    ([$($stack:tt)*] @section $x:ident $($t:tt)*) => {
        remove_sections!([$($stack)*] $($t)*);
    };
    ([$($stack:tt)*] { $($tail:tt)* }) => {
        $($stack)* {
            remove_sections_inner!([] $($tail)*);
        }
    };
    ([$($stack:tt)*] $t:tt $($tail:tt)*) => {
        remove_sections!([$($stack)* $t] $($tail)*);
    };
}

macro_rules! deref {
    ($e:expr) => (*$e);
}
macro_rules! deref_twice {
    ($e:expr) => (**$e);
}

/// Implement a trait by delegation. By default as if we are delegating
/// from &G to G.
macro_rules! delegate_impl {
    ([] $($rest:tt)*) => {
        delegate_impl! { [['a, G], G, &'a G, deref] $($rest)* }
    };
    ([[$($param:tt)*], $self_type:ident, $self_wrap:ty, $self_map:ident]
     pub trait $name:ident $(: $sup:ident)* $(+ $more_sup:ident)* {
        $(
        @section type
        $(
            $(#[$_attr1:meta])*
            type $assoc_name:ident $(: $bound:ty)*;
        )+
        )*
        $(
        @section self
        $(
            $(#[$_attr2:meta])*
            fn $fname_self:ident(self $(,$arg2:ident : $argty2:ty)*) -> $ret2:ty;
        )+
        )*
        $(
        @section self_ref
        $(
            $(#[$_attr3:meta])*
            fn $fname:ident(&self $(,$arg:ident : $argty:ty)*) -> $ret:ty;
        )+
        )*
        $(
        @section self_mut
        $(
            $(#[$_attr4:meta])*
            fn $fname_mut:ident(&mut self $(,$arg4:ident : $argty4:ty)*) -> $ret4:ty;
        )+
        )*
        $(
        @section ignore
        $($tail:tt)*
        )*
    }) => {
        impl<$($param)*> $name for $self_wrap where $self_type: $name {
            $(
            $(
                type $assoc_name = $self_type::$assoc_name;
            )*
            )*
            $(
            $(
                fn $fname_self(self $(,$arg2: $argty2)*) -> $ret2 {
                    $self_map!(self).$fname_self($($arg2),*)
                }
            )*
            )*
            $(
            $(
                fn $fname(&self $(,$arg: $argty)*) -> $ret {
                    $self_map!(self).$fname($($arg),*)
                }
            )*
            )*
            $(
            $(
                fn $fname_mut(&mut self $(,$arg4: $argty4)*) -> $ret4 {
                    $self_map!(self).$fname_mut($($arg4),*)
                }
            )*
            )*
        }
    }
}

<commit_msg>visit: Fix docs for templated traits<commit_after>
/// Define a trait as usual, and a macro that can be used to instantiate
/// implementations of it.
///
/// Well almost: There *must* be markers of `@section type`, `@section self`
/// and `@section self_ref` before the associated types, `self` methods
/// and `&self` methods respectively.
macro_rules! trait_template {
    ($(#[$doc:meta])* pub trait $name:ident $($methods:tt)*) => {
        macro_rules! $name {
            ($m:ident $extra:tt) => {
                $m! {
                    $extra
                    pub trait $name $($methods)*
                }
            }
        }
        remove_sections! { []
            $(#[$doc])*
            pub trait $name $($methods)*
        }
    }
}

macro_rules! remove_sections_inner {
    ([$($stack:tt)*]) => {
        $($stack)*
    };
    ([$($stack:tt)*] @section $x:ident $($t:tt)*) => {
        remove_sections_inner!([$($stack)*] $($t)*);
    };
    ([$($stack:tt)*] $t:tt $($tail:tt)*) => {
        remove_sections_inner!([$($stack)* $t] $($tail)*);
    };
}

// recurse once into { }, but not more
macro_rules! remove_sections {
    ([$($stack:tt)*]) => {
        $($stack)*
    };
    ([$($stack:tt)*] @section $x:ident $($t:tt)*) => {
        remove_sections!([$($stack)*] $($t)*);
    };
    ([$($stack:tt)*] { $($tail:tt)* }) => {
        $($stack)* {
            remove_sections_inner!([] $($tail)*);
        }
    };
    ([$($stack:tt)*] $t:tt $($tail:tt)*) => {
        remove_sections!([$($stack)* $t] $($tail)*);
    };
}

macro_rules! deref {
    ($e:expr) => (*$e);
}
macro_rules! deref_twice {
    ($e:expr) => (**$e);
}

/// Implement a trait by delegation. By default as if we are delegating
/// from &G to G.
macro_rules! delegate_impl {
    ([] $($rest:tt)*) => {
        delegate_impl! { [['a, G], G, &'a G, deref] $($rest)* }
    };
    ([[$($param:tt)*], $self_type:ident, $self_wrap:ty, $self_map:ident]
     pub trait $name:ident $(: $sup:ident)* $(+ $more_sup:ident)* {
        $(
        @section type
        $(
            $(#[$_attr1:meta])*
            type $assoc_name:ident $(: $bound:ty)*;
        )+
        )*
        $(
        @section self
        $(
            $(#[$_attr2:meta])*
            fn $fname_self:ident(self $(,$arg2:ident : $argty2:ty)*) -> $ret2:ty;
        )+
        )*
        $(
        @section self_ref
        $(
            $(#[$_attr3:meta])*
            fn $fname:ident(&self $(,$arg:ident : $argty:ty)*) -> $ret:ty;
        )+
        )*
        $(
        @section self_mut
        $(
            $(#[$_attr4:meta])*
            fn $fname_mut:ident(&mut self $(,$arg4:ident : $argty4:ty)*) -> $ret4:ty;
        )+
        )*
        $(
        @section ignore
        $($tail:tt)*
        )*
    }) => {
        impl<$($param)*> $name for $self_wrap where $self_type: $name {
            $(
            $(
                type $assoc_name = $self_type::$assoc_name;
            )*
            )*
            $(
            $(
                fn $fname_self(self $(,$arg2: $argty2)*) -> $ret2 {
                    $self_map!(self).$fname_self($($arg2),*)
                }
            )*
            )*
            $(
            $(
                fn $fname(&self $(,$arg: $argty)*) -> $ret {
                    $self_map!(self).$fname($($arg),*)
                }
            )*
            )*
            $(
            $(
                fn $fname_mut(&mut self $(,$arg4: $argty4)*) -> $ret4 {
                    $self_map!(self).$fname_mut($($arg4),*)
                }
            )*
            )*
        }
    }
}

<|endoftext|>


<commit_before>use std::ops::{Deref, DerefMut};

use super::GcManaged;

/// Heap-allocated box holding a GC'ed value.
pub struct GcBox<T: GcManaged + ?Sized> {
    marked: bool,
    value: T,
}

impl<T: GcManaged> GcBox<T> {
    pub fn new(value: T) -> Self {
        Self {
            marked: false,
            value,
        }
    }
}

impl<T: GcManaged + ?Sized> GcBox<T> {
    pub fn is_marked(&self) -> bool {
        self.marked
    }

    pub fn mark(&mut self) {
        self.marked = true;
    }

    pub fn unmark(&mut self) {
        self.marked = false;
    }
}

/// Pointer to a box with dynamically-checked mutability.
#[derive(Debug)]
pub struct GcPtr<T: GcManaged> {
    boxed: *mut GcBox<T>,
}

impl<T: GcManaged> GcPtr<T> {
    pub fn new(boxed: *mut GcBox<T>) -> Self {
        Self { boxed }
    }

    pub fn mark(&self) {
        unsafe {
            (*self.boxed).mark();
        }
    }
}

impl<T: GcManaged> Clone for GcPtr<T> {
    fn clone(&self) -> Self {
        Self { boxed: self.boxed }
    }
}

impl<T: GcManaged> Deref for GcPtr<T> {
    type Target = T;

    fn deref(&self) -> &T {
        let value = unsafe { &(*self.boxed).value };
        value
    }
}

impl<T: GcManaged> DerefMut for GcPtr<T> {
    fn deref_mut(&mut self) -> &mut T {
        let value = unsafe { &mut (*self.boxed).value };
        value
    }
}
<commit_msg>Add sample `Drop` implementation for `GcBox`<commit_after>use std::ops::{Deref, DerefMut};

use super::GcManaged;

/// Heap-allocated box holding a GC'ed value.
pub struct GcBox<T: GcManaged + ?Sized> {
    marked: bool,
    value: T,
}

impl<T: GcManaged> GcBox<T> {
    pub fn new(value: T) -> Self {
        Self {
            marked: false,
            value,
        }
    }
}

impl<T: GcManaged + ?Sized> GcBox<T> {
    pub fn is_marked(&self) -> bool {
        self.marked
    }

    pub fn mark(&mut self) {
        self.marked = true;
    }

    pub fn unmark(&mut self) {
        self.marked = false;
    }
}

// impl<T: GcManaged + ?Sized> Drop for GcBox<T> {
//     fn drop(&mut self) {
//         println!("GC: drop {:p}", self);
//     }
// }

/// Pointer to a box with dynamically-checked mutability.
#[derive(Debug)]
pub struct GcPtr<T: GcManaged> {
    boxed: *mut GcBox<T>,
}

impl<T: GcManaged> GcPtr<T> {
    pub fn new(boxed: *mut GcBox<T>) -> Self {
        Self { boxed }
    }

    pub fn mark(&self) {
        unsafe {
            (*self.boxed).mark();
        }
    }
}

impl<T: GcManaged> Clone for GcPtr<T> {
    fn clone(&self) -> Self {
        Self { boxed: self.boxed }
    }
}

impl<T: GcManaged> Deref for GcPtr<T> {
    type Target = T;

    fn deref(&self) -> &T {
        let value = unsafe { &(*self.boxed).value };
        value
    }
}

impl<T: GcManaged> DerefMut for GcPtr<T> {
    fn deref_mut(&mut self) -> &mut T {
        let value = unsafe { &mut (*self.boxed).value };
        value
    }
}
<|endoftext|>


<commit_before>extern crate libanalysis;
extern crate relative_path;
extern crate test_utils;

use std::{
    collections::HashMap,
    path::{Path},
};

use relative_path::RelativePath;
use libanalysis::{AnalysisHost, FileId, FileResolver, JobHandle, CrateGraph, CrateId};
use test_utils::assert_eq_dbg;

struct FileMap(&'static [(u32, &'static str)]);

impl FileMap {
    fn path(&self, id: FileId) -> &'static Path {
        let s = self.0.iter()
            .find(|it| it.0 == id.0)
            .unwrap()
            .1;
        Path::new(s)
    }
}

impl FileResolver for FileMap {
    fn file_stem(&self, id: FileId) -> String {
        self.path(id).file_stem().unwrap().to_str().unwrap().to_string()
    }
    fn resolve(&self, id: FileId, rel: &RelativePath) -> Option<FileId> {
        let path = {
            if rel.starts_with("..") {
                rel.strip_prefix("..").unwrap()
                    .to_path(&self.path(id).parent().unwrap())
            } else {
                rel.to_path(self.path(id))
            }
        };
        let path = &path.to_str().unwrap()[1..];
        let path = RelativePath::new(&path[0..]).normalize();
        let &(id, _) = self.0.iter()
            .find(|it| path == RelativePath::new(&it.1[0..]).normalize())?;
        Some(FileId(id))
    }
}

#[test]
fn test_resolve_module() {
    let mut world = AnalysisHost::new();
    world.change_file(FileId(1), Some("mod foo;".to_string()));
    world.change_file(FileId(2), Some("".to_string()));

    let snap = world.analysis(FileMap(&[
        (1, "/lib.rs"),
        (2, "/foo.rs"),
    ]));
    let (_handle, token) = JobHandle::new();
    let symbols = snap.approximately_resolve_symbol(FileId(1), 4.into(), &token);
    assert_eq_dbg(
        r#"[(FileId(2), FileSymbol { name: "foo", node_range: [0; 0), kind: MODULE })]"#,
        &symbols,
    );

    let snap = world.analysis(FileMap(&[
        (1, "/lib.rs"),
        (2, "/foo/mod.rs")
    ]));
    let symbols = snap.approximately_resolve_symbol(FileId(1), 4.into(), &token);
    assert_eq_dbg(
        r#"[(FileId(2), FileSymbol { name: "foo", node_range: [0; 0), kind: MODULE })]"#,
        &symbols,
    );
}

#[test]
fn test_unresolved_module_diagnostic() {
    let mut world = AnalysisHost::new();
    world.change_file(FileId(1), Some("mod foo;".to_string()));

    let snap = world.analysis(FileMap(&[(1, "/lib.rs")]));
    let diagnostics = snap.diagnostics(FileId(1));
    assert_eq_dbg(
        r#"[Diagnostic {
            message: "unresolved module",
            range: [4; 7),
            fix: Some(SourceChange {
                label: "create module",
                source_file_edits: [],
                file_system_edits: [CreateFile { anchor: FileId(1), path: "../foo.rs" }],
                cursor_position: None }) }]"#,
        &diagnostics,
    );
}

#[test]
fn test_unresolved_module_diagnostic_no_diag_for_inline_mode() {
    let mut world = AnalysisHost::new();
    world.change_file(FileId(1), Some("mod foo {}".to_string()));

    let snap = world.analysis(FileMap(&[(1, "/lib.rs")]));
    let diagnostics = snap.diagnostics(FileId(1));
    assert_eq_dbg(
        r#"[]"#,
        &diagnostics,
    );
}

#[test]
fn test_resolve_parent_module() {
    let mut world = AnalysisHost::new();
    world.change_file(FileId(1), Some("mod foo;".to_string()));
    world.change_file(FileId(2), Some("".to_string()));

    let snap = world.analysis(FileMap(&[
        (1, "/lib.rs"),
        (2, "/foo.rs"),
    ]));
    let symbols = snap.parent_module(FileId(2));
    assert_eq_dbg(
        r#"[(FileId(1), FileSymbol { name: "foo", node_range: [0; 8), kind: MODULE })]"#,
        &symbols,
    );
}

#[test]
fn test_resolve_crate_root() {
    let mut world = AnalysisHost::new();
    world.change_file(FileId(1), Some("mod foo;".to_string()));
    world.change_file(FileId(2), Some("".to_string()));

    let snap = world.analysis(FileMap(&[
        (1, "/lib.rs"),
        (2, "/foo.rs"),
    ]));
    assert!(snap.crate_for(FileId(2)).is_empty());

    let crate_graph = CrateGraph {
        crate_roots: {
            let mut m = HashMap::new();
            m.insert(CrateId(1), FileId(1));
            m
        },
    };
    world.set_crate_graph(crate_graph);

    let snap = world.analysis(FileMap(&[
        (1, "/lib.rs"),
        (2, "/foo.rs"),
    ]));
    assert_eq!(
        snap.crate_for(FileId(2)),
        vec![CrateId(1)],
    );
}
<commit_msg>less hacky paths<commit_after>extern crate libanalysis;
extern crate relative_path;
extern crate test_utils;

use std::{
    collections::HashMap,
    path::{Path},
};

use relative_path::{RelativePath, RelativePathBuf};
use libanalysis::{AnalysisHost, FileId, FileResolver, JobHandle, CrateGraph, CrateId};
use test_utils::assert_eq_dbg;

struct FileMap(&'static [(u32, &'static str)]);

impl FileMap {
    fn path(&self, id: FileId) -> &'static Path {
        let s = self.0.iter()
            .find(|it| it.0 == id.0)
            .unwrap()
            .1;
        Path::new(s)
    }
}

impl FileResolver for FileMap {
    fn file_stem(&self, id: FileId) -> String {
        self.path(id).file_stem().unwrap().to_str().unwrap().to_string()
    }
    fn resolve(&self, id: FileId, rel: &RelativePath) -> Option<FileId> {
        let path = rel.to_path(self.path(id));
        let path = path.strip_prefix("/").unwrap();
        let path = RelativePathBuf::from_path(&path).unwrap().normalize();
        let &(id, _) = self.0.iter()
            .find(|it| {
                let p = Path::new(it.1).strip_prefix("/").unwrap();
                let p = RelativePathBuf::from_path(p).unwrap();
                path == p
            })?;
        Some(FileId(id))
    }
}

#[test]
fn test_resolve_module() {
    let mut world = AnalysisHost::new();
    world.change_file(FileId(1), Some("mod foo;".to_string()));
    world.change_file(FileId(2), Some("".to_string()));

    let snap = world.analysis(FileMap(&[
        (1, "/lib.rs"),
        (2, "/foo.rs"),
    ]));
    let (_handle, token) = JobHandle::new();
    let symbols = snap.approximately_resolve_symbol(FileId(1), 4.into(), &token);
    assert_eq_dbg(
        r#"[(FileId(2), FileSymbol { name: "foo", node_range: [0; 0), kind: MODULE })]"#,
        &symbols,
    );

    let snap = world.analysis(FileMap(&[
        (1, "/lib.rs"),
        (2, "/foo/mod.rs")
    ]));
    let symbols = snap.approximately_resolve_symbol(FileId(1), 4.into(), &token);
    assert_eq_dbg(
        r#"[(FileId(2), FileSymbol { name: "foo", node_range: [0; 0), kind: MODULE })]"#,
        &symbols,
    );
}

#[test]
fn test_unresolved_module_diagnostic() {
    let mut world = AnalysisHost::new();
    world.change_file(FileId(1), Some("mod foo;".to_string()));

    let snap = world.analysis(FileMap(&[(1, "/lib.rs")]));
    let diagnostics = snap.diagnostics(FileId(1));
    assert_eq_dbg(
        r#"[Diagnostic {
            message: "unresolved module",
            range: [4; 7),
            fix: Some(SourceChange {
                label: "create module",
                source_file_edits: [],
                file_system_edits: [CreateFile { anchor: FileId(1), path: "../foo.rs" }],
                cursor_position: None }) }]"#,
        &diagnostics,
    );
}

#[test]
fn test_unresolved_module_diagnostic_no_diag_for_inline_mode() {
    let mut world = AnalysisHost::new();
    world.change_file(FileId(1), Some("mod foo {}".to_string()));

    let snap = world.analysis(FileMap(&[(1, "/lib.rs")]));
    let diagnostics = snap.diagnostics(FileId(1));
    assert_eq_dbg(
        r#"[]"#,
        &diagnostics,
    );
}

#[test]
fn test_resolve_parent_module() {
    let mut world = AnalysisHost::new();
    world.change_file(FileId(1), Some("mod foo;".to_string()));
    world.change_file(FileId(2), Some("".to_string()));

    let snap = world.analysis(FileMap(&[
        (1, "/lib.rs"),
        (2, "/foo.rs"),
    ]));
    let symbols = snap.parent_module(FileId(2));
    assert_eq_dbg(
        r#"[(FileId(1), FileSymbol { name: "foo", node_range: [0; 8), kind: MODULE })]"#,
        &symbols,
    );
}

#[test]
fn test_resolve_crate_root() {
    let mut world = AnalysisHost::new();
    world.change_file(FileId(1), Some("mod foo;".to_string()));
    world.change_file(FileId(2), Some("".to_string()));

    let snap = world.analysis(FileMap(&[
        (1, "/lib.rs"),
        (2, "/foo.rs"),
    ]));
    assert!(snap.crate_for(FileId(2)).is_empty());

    let crate_graph = CrateGraph {
        crate_roots: {
            let mut m = HashMap::new();
            m.insert(CrateId(1), FileId(1));
            m
        },
    };
    world.set_crate_graph(crate_graph);

    let snap = world.analysis(FileMap(&[
        (1, "/lib.rs"),
        (2, "/foo.rs"),
    ]));
    assert_eq!(
        snap.crate_for(FileId(2)),
        vec![CrateId(1)],
    );
}
<|endoftext|>


<commit_before>#![cfg(test)]
#![allow(non_upper_case_globals)]
#![allow(dead_code)]
extern crate core;
extern crate brotli_decompressor;
use brotli_decompressor::{CustomRead, CustomWrite};
use super::brotli::BrotliResult;
use super::brotli::BrotliState;
use super::brotli::enc::BrotliEncoderParams;
use super::brotli::concat::BroCatli;
use brotli::BrotliDecompressStream;
use std::io::{Read, Write};
use super::integration_tests::{Buffer, UnlimitedBuffer};
static RANDOM_THEN_UNICODE : &'static [u8] = include_bytes!("../../testdata/random_then_unicode");
static ALICE: &'static[u8]  = include_bytes!("../../testdata/alice29.txt");
static UKKONOOA: &'static[u8]  = include_bytes!("../../testdata/ukkonooa");
static ASYOULIKE: &'static[u8] = include_bytes!("../../testdata/asyoulik.txt");
static BACKWARD65536: &'static [u8] = include_bytes!("../../testdata/backward65536");
static DICTWORD: &'static [u8] = include_bytes!("../../testdata/ends_with_truncated_dictionary");
static RANDOM10K: &'static [u8] = include_bytes!("../../testdata/random_org_10k.bin");
static RANDOMTHENUNICODE: &'static [u8] = include_bytes!("../../testdata/random_then_unicode");
static QUICKFOX: &'static [u8] = include_bytes!("../../testdata/quickfox_repeated");
static EMPTY: &'static [u8] = &[];

fn concat(files:&mut [UnlimitedBuffer],
          brotli_files:&mut [UnlimitedBuffer],
          window_override:Option<u8>,
          bs: usize) {
  let mut obuffer = vec![0u8; bs];
  let mut ibuffer = vec![0u8; bs];
  let mut ooffset = 0usize;
  let mut ioffset = 0usize;
  let mut uboutput = UnlimitedBuffer::new(&[]);
  let mut output = super::IoWriterWrapper(&mut uboutput);
  let mut bro_cat_li = match window_override {
    Some(ws) => BroCatli::new_with_window_size(ws),
    None => BroCatli::new(),
  };
  for (index, brotli) in brotli_files.iter_mut().enumerate() {
    bro_cat_li.new_brotli_file();
    let mut input = super::IoReaderWrapper(brotli);
    loop {
      ioffset = 0;
      match input.read(&mut ibuffer[..]) {
        Err(e) => panic!(e),
        Ok(cur_read) => {
          if cur_read == 0 {
            break;
          }
          loop {
            match bro_cat_li.stream(&ibuffer[..cur_read], &mut ioffset,
                                    &mut obuffer[..], &mut ooffset) {
              BrotliResult::ResultFailure => {
                panic!(index);
              },
              BrotliResult::NeedsMoreOutput => {
                match output.write(&obuffer[..ooffset]) {
                  Err(why) => panic!("couldn't write: {:}", why),
                  Ok(count) => {assert_eq!(count, ooffset);},
                }
                ooffset = 0;
              },
              BrotliResult::NeedsMoreInput => {
                break;
              },
              BrotliResult::ResultSuccess => {
                panic!("Unexpected state: Success when streaming before finish");
              }
            }

          }
        }
      }
    }
    loop {
        match bro_cat_li.finish(&mut obuffer[..], &mut ooffset) {
            BrotliResult::NeedsMoreOutput => {
                match output.write(&obuffer[..ooffset]) {
                    Err(why) => panic!("couldn't write\n{:}", why),
                    Ok(count) => {assert_eq!(count, ooffset);},
                }
                ooffset = 0;
            },
            BrotliResult::NeedsMoreInput => {
                panic!("Unexpected EOF");
            },
            BrotliResult::ResultSuccess => {
                if ooffset != 0 {
                    match output.write(&obuffer[..ooffset]) {
                        Err(why) => panic!("couldn't write\n{:}", why),
                        Ok(count) => {assert_eq!(count, ooffset);},
                    }
                }
                break;
            }
            BrotliResult::ResultFailure => {
                panic!("Failed to terminate concatenation")
            }
        }
    }
  }
}

fn concat_many_subsets(files:&mut [UnlimitedBuffer],
                       brotli_files:&mut [UnlimitedBuffer],
                       window_override:Option<u8>) {
  let test_plans:[(usize,usize);4] = [(brotli_files.len(), 4096 * 1024), (4, 1), (3, 3),  (2, 4096)];
  for (plan, bs) in test_plans.iter() {
    for index in 0..(brotli_files.len() - (plan - 1)) {
      let file_subset = &mut files[index..(index+plan)];
      let brotli_subset = &mut brotli_files[index..(index+plan)];
      concat(file_subset, brotli_subset, window_override, *bs);
    }
  }
}

#[cfg(debug_assertions)]
fn light_debug_test(params: &mut BrotliEncoderParams) {
    params.quality = 5;
}

#[cfg(not(debug_assertions))]
fn light_debug_test(params: &mut BrotliEncoderParams) {
}

#[test]
fn test_concat() {
    let mut files = [
        UnlimitedBuffer::new(ALICE),
        UnlimitedBuffer::new(RANDOM_THEN_UNICODE),
        UnlimitedBuffer::new(UKKONOOA),
        UnlimitedBuffer::new(ASYOULIKE),
        UnlimitedBuffer::new(BACKWARD65536),
        UnlimitedBuffer::new(DICTWORD),
        UnlimitedBuffer::new(RANDOM10K),
        UnlimitedBuffer::new(RANDOMTHENUNICODE),
        UnlimitedBuffer::new(QUICKFOX),
        UnlimitedBuffer::new(EMPTY),
    ];
    let mut params0 = BrotliEncoderParams::default();
    light_debug_test(&mut params0);
    let mut params1 = params0.clone();
    params1.quality = 9;
    params1.q9_5 = true;
    params1.magic_number = true;
    let mut params2 = params0.clone();
    params2.quality = 9;
    let mut params3 = params0.clone();
    params3.quality = 9;
    params3.lgwin = 16;
    params3.magic_number = true;
    let mut params4 = params0.clone();
    params4.quality = 8;
    params4.lgwin = 14;
    let mut params4 = params0.clone();
    params4.quality = 1;
    params4.lgwin = 10;
    let mut params5 = params0.clone();
    params5.quality = 0;
    params5.lgwin = 10;
    params5.magic_number = true;
    params0.lgwin = 26;
    params0.large_window = true;

    let mut options = [
        params0,
        params1,
        params2,
        params3,
        params4,
        params5,
        ];
    for option in options.iter_mut() {
        let mut ufiles = [
            UnlimitedBuffer::new(&[]),
            UnlimitedBuffer::new(&[]),
            UnlimitedBuffer::new(&[]),
            UnlimitedBuffer::new(&[]),
            UnlimitedBuffer::new(&[]),
            UnlimitedBuffer::new(&[]),
            UnlimitedBuffer::new(&[]),
            UnlimitedBuffer::new(&[]),
            UnlimitedBuffer::new(&[]),
            UnlimitedBuffer::new(&[]),
        ];
        let mut first = true;
        for (src, dst) in files.iter_mut().zip(ufiles.iter_mut()) {
            if first && false {
                option.appendable = true;
            } else {
                option.appendable = false;
                option.catable = true;
            }
            super::compress(src, dst, 4096, option).unwrap();
        }
        concat_many_subsets(&mut files[..], &mut ufiles[..], None);
    }
    let mut ufiles = [
      UnlimitedBuffer::new(&[]),
      UnlimitedBuffer::new(&[]),
      UnlimitedBuffer::new(&[]),
      UnlimitedBuffer::new(&[]),
      UnlimitedBuffer::new(&[]),
      UnlimitedBuffer::new(&[]),
      UnlimitedBuffer::new(&[]),
      UnlimitedBuffer::new(&[]),
      UnlimitedBuffer::new(&[]),
      UnlimitedBuffer::new(&[]),
    ];
    for (index, (src, dst)) in files.iter_mut().zip(ufiles.iter_mut()).enumerate() {
          options[index % options.len()].catable = true;
          options[index % options.len()].appendable = false;
          super::compress(src, dst, 4096, &options[index % options.len()]).unwrap();
    }
    concat_many_subsets(&mut files[..], &mut ufiles[..], None);
    concat_many_subsets(&mut files[..], &mut ufiles[..], Some(28));
}
<commit_msg>only test for first file being appendable...we can look for failures in other cases<commit_after>#![cfg(test)]
#![allow(non_upper_case_globals)]
#![allow(dead_code)]
extern crate core;
extern crate brotli_decompressor;
use brotli_decompressor::{CustomRead, CustomWrite};
use super::brotli::BrotliResult;
use super::brotli::BrotliState;
use super::brotli::enc::BrotliEncoderParams;
use super::brotli::concat::BroCatli;
use brotli::BrotliDecompressStream;
use std::io::{Read, Write};
use super::integration_tests::{Buffer, UnlimitedBuffer};
static RANDOM_THEN_UNICODE : &'static [u8] = include_bytes!("../../testdata/random_then_unicode");
static ALICE: &'static[u8]  = include_bytes!("../../testdata/alice29.txt");
static UKKONOOA: &'static[u8]  = include_bytes!("../../testdata/ukkonooa");
static ASYOULIKE: &'static[u8] = include_bytes!("../../testdata/asyoulik.txt");
static BACKWARD65536: &'static [u8] = include_bytes!("../../testdata/backward65536");
static DICTWORD: &'static [u8] = include_bytes!("../../testdata/ends_with_truncated_dictionary");
static RANDOM10K: &'static [u8] = include_bytes!("../../testdata/random_org_10k.bin");
static RANDOMTHENUNICODE: &'static [u8] = include_bytes!("../../testdata/random_then_unicode");
static QUICKFOX: &'static [u8] = include_bytes!("../../testdata/quickfox_repeated");
static EMPTY: &'static [u8] = &[];

fn concat(files:&mut [UnlimitedBuffer],
          brotli_files:&mut [UnlimitedBuffer],
          window_override:Option<u8>,
          bs: usize) {
  let mut obuffer = vec![0u8; bs];
  let mut ibuffer = vec![0u8; bs];
  let mut ooffset = 0usize;
  let mut ioffset = 0usize;
  let mut uboutput = UnlimitedBuffer::new(&[]);
  let mut output = super::IoWriterWrapper(&mut uboutput);
  let mut bro_cat_li = match window_override {
    Some(ws) => BroCatli::new_with_window_size(ws),
    None => BroCatli::new(),
  };
  for (index, brotli) in brotli_files.iter_mut().enumerate() {
    bro_cat_li.new_brotli_file();
    let mut input = super::IoReaderWrapper(brotli);
    loop {
      ioffset = 0;
      match input.read(&mut ibuffer[..]) {
        Err(e) => panic!(e),
        Ok(cur_read) => {
          if cur_read == 0 {
            break;
          }
          loop {
            match bro_cat_li.stream(&ibuffer[..cur_read], &mut ioffset,
                                    &mut obuffer[..], &mut ooffset) {
              BrotliResult::ResultFailure => {
                panic!(index);
              },
              BrotliResult::NeedsMoreOutput => {
                match output.write(&obuffer[..ooffset]) {
                  Err(why) => panic!("couldn't write: {:}", why),
                  Ok(count) => {assert_eq!(count, ooffset);},
                }
                ooffset = 0;
              },
              BrotliResult::NeedsMoreInput => {
                break;
              },
              BrotliResult::ResultSuccess => {
                panic!("Unexpected state: Success when streaming before finish");
              }
            }

          }
        }
      }
    }
    loop {
        match bro_cat_li.finish(&mut obuffer[..], &mut ooffset) {
            BrotliResult::NeedsMoreOutput => {
                match output.write(&obuffer[..ooffset]) {
                    Err(why) => panic!("couldn't write\n{:}", why),
                    Ok(count) => {assert_eq!(count, ooffset);},
                }
                ooffset = 0;
            },
            BrotliResult::NeedsMoreInput => {
                panic!("Unexpected EOF");
            },
            BrotliResult::ResultSuccess => {
                if ooffset != 0 {
                    match output.write(&obuffer[..ooffset]) {
                        Err(why) => panic!("couldn't write\n{:}", why),
                        Ok(count) => {assert_eq!(count, ooffset);},
                    }
                }
                break;
            }
            BrotliResult::ResultFailure => {
                panic!("Failed to terminate concatenation")
            }
        }
    }
  }
}

fn concat_many_subsets(files:&mut [UnlimitedBuffer],
                       brotli_files:&mut [UnlimitedBuffer],
                       window_override:Option<u8>) {
  let test_plans:[(usize,usize);4] = [(brotli_files.len(), 4096 * 1024), (4, 1), (3, 3),  (2, 4096)];
  for (plan, bs) in test_plans.iter() {
    for index in 0..(brotli_files.len() - (plan - 1)) {
      let file_subset = &mut files[index..(index+plan)];
      let brotli_subset = &mut brotli_files[index..(index+plan)];
      concat(file_subset, brotli_subset, window_override, *bs);
    }
  }
}

#[cfg(debug_assertions)]
fn light_debug_test(params: &mut BrotliEncoderParams) {
    params.quality = 5;
}

#[cfg(not(debug_assertions))]
fn light_debug_test(params: &mut BrotliEncoderParams) {
}

#[test]
fn test_concat() {
    let mut files = [
        UnlimitedBuffer::new(ALICE),
        UnlimitedBuffer::new(RANDOM_THEN_UNICODE),
        UnlimitedBuffer::new(UKKONOOA),
        UnlimitedBuffer::new(ASYOULIKE),
        UnlimitedBuffer::new(BACKWARD65536),
        UnlimitedBuffer::new(DICTWORD),
        UnlimitedBuffer::new(RANDOM10K),
        UnlimitedBuffer::new(RANDOMTHENUNICODE),
        UnlimitedBuffer::new(QUICKFOX),
        UnlimitedBuffer::new(EMPTY),
    ];
    let mut params0 = BrotliEncoderParams::default();
    light_debug_test(&mut params0);
    let mut params1 = params0.clone();
    params1.quality = 9;
    params1.q9_5 = true;
    params1.magic_number = true;
    let mut params2 = params0.clone();
    params2.quality = 9;
    let mut params3 = params0.clone();
    params3.quality = 9;
    params3.lgwin = 16;
    params3.magic_number = true;
    let mut params4 = params0.clone();
    params4.quality = 8;
    params4.lgwin = 14;
    let mut params4 = params0.clone();
    params4.quality = 1;
    params4.lgwin = 10;
    let mut params5 = params0.clone();
    params5.quality = 0;
    params5.lgwin = 10;
    params5.magic_number = true;
    params0.lgwin = 26;
    params0.large_window = true;

    let mut options = [
        params0,
        params1,
        params2,
        params3,
        params4,
        params5,
        ];
    for option in options.iter_mut() {
        let mut ufiles = [
            UnlimitedBuffer::new(&[]),
            UnlimitedBuffer::new(&[]),
            UnlimitedBuffer::new(&[]),
            UnlimitedBuffer::new(&[]),
            UnlimitedBuffer::new(&[]),
            UnlimitedBuffer::new(&[]),
            UnlimitedBuffer::new(&[]),
            UnlimitedBuffer::new(&[]),
            UnlimitedBuffer::new(&[]),
            UnlimitedBuffer::new(&[]),
        ];
        let mut first = true;
        for (src, dst) in files.iter_mut().zip(ufiles.iter_mut()) {
            if first {
                option.appendable = true;
            } else {
                option.appendable = false;
                option.catable = true;
            }
            super::compress(src, dst, 4096, option).unwrap();
            first = false;
        }
        concat_many_subsets(&mut files[..], &mut ufiles[..], None);
    }
    let mut ufiles = [
      UnlimitedBuffer::new(&[]),
      UnlimitedBuffer::new(&[]),
      UnlimitedBuffer::new(&[]),
      UnlimitedBuffer::new(&[]),
      UnlimitedBuffer::new(&[]),
      UnlimitedBuffer::new(&[]),
      UnlimitedBuffer::new(&[]),
      UnlimitedBuffer::new(&[]),
      UnlimitedBuffer::new(&[]),
      UnlimitedBuffer::new(&[]),
    ];
    for (index, (src, dst)) in files.iter_mut().zip(ufiles.iter_mut()).enumerate() {
          options[index % options.len()].catable = true;
          options[index % options.len()].appendable = false;
          super::compress(src, dst, 4096, &options[index % options.len()]).unwrap();
    }
    concat_many_subsets(&mut files[..], &mut ufiles[..], None);
    concat_many_subsets(&mut files[..], &mut ufiles[..], Some(28));
}
<|endoftext|>


<commit_before>#![feature(convert)] // as_ref

extern crate school;

fn stringvec_to_strvec(v: &Vec<String>) -> Vec<&str> {
    v.iter().map(|s| s.as_ref()).collect()
}

#[test]
fn test_add_student() {
    let mut s = school::School::new();
    s.add(2, "Aimee");
    assert_eq!(s.grades(), vec!(2));
    assert_eq!(s.grade(2).map(|v| stringvec_to_strvec(v)),
                Some(vec!("Aimee")))
}

#[test]
fn test_add_more_students_in_same_class() {
    let mut s = school::School::new();
    s.add(2, "James");
    s.add(2, "Blair");
    s.add(2, "Paul");
    assert_eq!(s.grades(), vec!(2));
    assert_eq!(s.grade(2).map(|v| stringvec_to_strvec(v)),
               Some(vec!("Blair", "James", "Paul")));
}

#[test]
fn test_add_students_to_different_grades() {
    let mut s = school::School::new();
    s.add(3, "Chelsea");
    s.add(7, "Logan");
    assert_eq!(s.grades(), vec!(3, 7));
    assert_eq!(s.grade(3).map(|v| stringvec_to_strvec(v)),
               Some(vec!("Chelsea")));
    assert_eq!(s.grade(7).map(|v| stringvec_to_strvec(v)),
               Some(vec!("Logan")));
}

#[test]
fn test_get_students_in_a_non_existent_grade() {
    let s = school::School::new();
    assert_eq!(s.grade(1), None);
}
<commit_msg>Remove feature flag<commit_after>extern crate school;

fn stringvec_to_strvec(v: &Vec<String>) -> Vec<&str> {
    v.iter().map(|s| s.as_ref()).collect()
}

#[test]
fn test_add_student() {
    let mut s = school::School::new();
    s.add(2, "Aimee");
    assert_eq!(s.grades(), vec!(2));
    assert_eq!(s.grade(2).map(|v| stringvec_to_strvec(v)),
                Some(vec!("Aimee")))
}

#[test]
fn test_add_more_students_in_same_class() {
    let mut s = school::School::new();
    s.add(2, "James");
    s.add(2, "Blair");
    s.add(2, "Paul");
    assert_eq!(s.grades(), vec!(2));
    assert_eq!(s.grade(2).map(|v| stringvec_to_strvec(v)),
               Some(vec!("Blair", "James", "Paul")));
}

#[test]
fn test_add_students_to_different_grades() {
    let mut s = school::School::new();
    s.add(3, "Chelsea");
    s.add(7, "Logan");
    assert_eq!(s.grades(), vec!(3, 7));
    assert_eq!(s.grade(3).map(|v| stringvec_to_strvec(v)),
               Some(vec!("Chelsea")));
    assert_eq!(s.grade(7).map(|v| stringvec_to_strvec(v)),
               Some(vec!("Logan")));
}

#[test]
fn test_get_students_in_a_non_existent_grade() {
    let s = school::School::new();
    assert_eq!(s.grade(1), None);
}
<|endoftext|>


<commit_before>extern crate xml;
extern crate clap;

mod polyfill;

use std::fs::File;
use std::io::BufReader;
use std::str::FromStr;

use xml::reader::{EventReader, XmlEvent};
use clap::{Arg, App};

fn matching_element_id<'a>(ids: &str, attr: &'a Vec<xml::attribute::OwnedAttribute>) -> Option<&'a str> {
    let id_attr = match attr.iter().find(|ref a| a.name.local_name == "id") {
        Some(a) => a,
        None => return None
    };

    if ids.is_empty() || ids.split(',').any(|i| id_attr.value == i) {
        Some(&id_attr.value)
    }
    else { None }
}

fn emit_path(d: &str, id: &str, drawnode: &str, color: &str) {
    // Fill a vec with all verts
    let mut n = 0;
    let mut verts = Vec::with_capacity(d.len() / 5);
    {
        let mut exprs = d.split(' ');
        let mut current_pos = [0.0, 0.0];
        verts.push(current_pos);
        while let Some(expr) = exprs.next() {
            if expr == "m" {
                if n == 0 {
                    // Skip the starting point
                    exprs.next();
                    continue;
                }
                else { panic!("'m' showing up more than once???") }
            }
            else if expr == "z" {
                break
            }
            else if !expr.contains(',') {
                panic!("Unsupported expression: {}", expr);
            }

            let mut xy = expr.split(',');
            let x = xy.next().expect("Invalid pair");
            let y = xy.next().expect("Invalid pair");
            current_pos = [
                current_pos[0] + f64::from_str(x).expect("Failed to parse float"),
                current_pos[1] - f64::from_str(y).expect("Failed to parse float")
            ];
            verts.push(current_pos);

            n = n + 1;
        }
    }

    // Triangulation and c++ code emission
    println!("// Triangles for {}", id);
    let triangles = polyfill::triangle_indices(&verts, polyfill::TANGENTIAL);
    for t in triangles {
        println!(
            "{}->drawTriangle(Vec2({},{}), Vec2({},{}), Vec2({},{}), {});",
            drawnode,
            verts[t[0]][0],verts[t[0]][1],
            verts[t[1]][0],verts[t[1]][1],
            verts[t[2]][0],verts[t[2]][1],
            color
        );
    }
}

fn main() {
    let app: App = App::new("grayfx")
        .version("0.0")
        .author("Nigel Baillie <metreckk@gmail.com>")
        .about("Converts Inkscape SVGs into C++ rendering and/or physics code for Gray")
        .arg(Arg::with_name("input")
            .help("the svg file to parse")
            .takes_value(true)
            .index(1)
            .required(true))
        .arg(Arg::with_name("ids")
            .short("id")
            .help("comma-separated ids of the elements to process")
            .required(false))
        .arg(Arg::with_name("color")
            .short("c")
            .help("expression to use for color")
            .default_value("Color4f::WHITE"));
    let matches = app.get_matches();

    let file = File::open(matches.value_of("input").unwrap()).unwrap();
    let file = BufReader::new(file);

    let ids = matches.value_of("ids").unwrap_or("");
    let color = matches.value_of("color").unwrap();

    let parser = EventReader::new(file);
    for xmlevent in parser {
        match xmlevent {
            // <path> elements:
            Ok(XmlEvent::StartElement { name, attributes, .. }) => {
                if let Some(id) = matching_element_id(ids, &attributes) {
                    if name.local_name == "path" {
                        let d_attr = attributes.iter().find(|ref a| a.name.local_name == "d")
                            .expect(&format!("Path with id={} doesn't have a `d` attribute", id));

                        emit_path(&d_attr.value, id, "draw", color);
                    }
                }
            }
            /*
            Ok(XmlEvent::EndElement { name }) => {
                println!("END {}", name);
            }
            */
            Err(e) => {
                println!("// Error: {}", e);
                break;
            }
            _ => {}
        }
    }
}
<commit_msg>process elements in order of ID<commit_after>extern crate xml;
extern crate clap;

mod polyfill;

use std::fs::File;
use std::io::BufReader;
use std::str::FromStr;
use std::collections::HashMap;

use xml::reader::{EventReader, XmlEvent};
use clap::{Arg, App};

fn matching_element_id<'a>(ids: &str, attr: &'a Vec<xml::attribute::OwnedAttribute>) -> Option<&'a str> {
    let id_attr = match attr.iter().find(|ref a| a.name.local_name == "id") {
        Some(a) => a,
        None => return None
    };

    if ids.is_empty() || ids.split(',').any(|i| id_attr.value == i) {
        Some(&id_attr.value)
    }
    else { None }
}

fn emit_path(d: &str, id: &str, drawnode: &str, color: &str) {
    // Fill a vec with all verts
    let mut n = 0;
    let mut verts = Vec::with_capacity(d.len() / 5);
    {
        let mut exprs = d.split(' ');
        let mut current_pos = [0.0, 0.0];
        verts.push(current_pos);
        while let Some(expr) = exprs.next() {
            if expr == "m" {
                if n == 0 {
                    // Skip the starting point
                    exprs.next();
                    continue;
                }
                else { panic!("'m' showing up more than once???") }
            }
            else if expr == "z" {
                break
            }
            else if !expr.contains(',') {
                panic!("Unsupported expression: {}", expr);
            }

            let mut xy = expr.split(',');
            let x = xy.next().expect("Invalid pair");
            let y = xy.next().expect("Invalid pair");
            current_pos = [
                current_pos[0] + f64::from_str(x).expect("Failed to parse float"),
                current_pos[1] - f64::from_str(y).expect("Failed to parse float")
            ];
            verts.push(current_pos);

            n = n + 1;
        }
    }

    // Triangulation and c++ code emission
    println!("// Triangles for {}", id);
    let triangles = polyfill::triangle_indices(&verts, polyfill::TANGENTIAL);
    for t in triangles {
        println!(
            "{}->drawTriangle(Vec2({},{}), Vec2({},{}), Vec2({},{}), {});",
            drawnode,
            verts[t[0]][0],verts[t[0]][1],
            verts[t[1]][0],verts[t[1]][1],
            verts[t[2]][0],verts[t[2]][1],
            color
        );
    }
}

fn main() {
    let app: App = App::new("grayfx")
        .version("0.0")
        .author("Nigel Baillie <metreckk@gmail.com>")
        .about("Converts Inkscape SVGs into C++ rendering and/or physics code for Gray")
        .arg(Arg::with_name("input")
            .help("the svg file to parse")
            .short("f")
            .takes_value(true)
            .index(1)
            .required(true))
        .arg(Arg::with_name("ids")
            .short("i")
            .help("comma-separated ids of the elements to process")
            .takes_value(true)
            .required(false))
        .arg(Arg::with_name("color")
            .short("c")
            .help("expression to use for color")
            .default_value("Color4f::WHITE"));
    let matches = app.get_matches();

    let file = File::open(matches.value_of("input").unwrap()).unwrap();
    let file = BufReader::new(file);

    let ids = matches.value_of("ids").unwrap_or("");
    let color = matches.value_of("color").unwrap();

    let ids_count = if ids.is_empty() {
        0
    } else {
        ids.chars().fold(1, |n, c| if c == ',' { n + 1 } else { n })
    };

    // === Parse XML ===
    let mut matching_elements = HashMap::<String, (String, Vec<xml::attribute::OwnedAttribute>)>::new();
    let parser = EventReader::new(file);
    'parse_xml: for xmlevent in parser {
        match xmlevent {
            // <path> elements:
            Ok(XmlEvent::StartElement { name, attributes, .. }) => {
                if let Some(id) = matching_element_id(ids, &attributes) {
                    matching_elements.insert(id.to_string(), (name.local_name, attributes.clone()));

                    // Duck out early if possible
                    if ids_count > 0 && matching_elements.len() >= ids_count {
                        break 'parse_xml;
                    }
                }
            }
            /*
            Ok(XmlEvent::EndElement { name }) => {
                println!("END {}", name);
            }
            */
            Err(e) => {
                println!("// Error: {}", e);
                break;
            }
            _ => {}
        }
    }

    // === Now process elements that matched, in specified order ===
    let process_element = |id: String, el: &(String, Vec<xml::attribute::OwnedAttribute>)| {
        match el {
            &(ref name, ref attributes) => {
                if name == "path" {
                    let d_attr = attributes.iter().find(|ref a| a.name.local_name == "d")
                        .expect(&format!("Path with id={} doesn't have a `d` attribute", id));

                    emit_path(&d_attr.value, &id, "draw", color);
                }
                else if name == "circle" {
                    panic!("Unimplemented TODO!!!");
                }
            }
        }
    };

    if ids_count > 0 {
        let each_id = ids.split(',');
        for id in each_id { process_element(id.to_string(), &matching_elements[id]) }
    }
    else {
        for (ref id, ref element) in matching_elements {
            process_element(id.clone(), &element)
        }
    }
}
<|endoftext|>


<commit_before>/// Check if an expression matches a refutable pattern.
///
/// Syntax: `matches!(` *expression* `,` *pattern* `)`
///
/// Return a boolean, true if the expression matches the pattern, false otherwise.
///
/// # Examples
///
/// ```
/// #[macro_use]
/// extern crate matches;
///
/// pub enum Foo<T> {
///     A,
///     B(T),
/// }
///
/// impl<T> Foo<T> {
///     pub fn is_a(&self) -> bool {
///         matches!(*self, Foo::A)
///     }
///
///     pub fn is_b(&self) -> bool {
///         matches!(*self, Foo::B(_))
///     }
/// }
///
/// # fn main() { }
/// ```
#[macro_export]
macro_rules! matches {
    ($expression:expr, $($pattern:tt)+) => {
        match $expression {
            $($pattern)+ => true,
            _ => false
        }
    }
}

/// Assert that an expression matches a refutable pattern.
///
/// Syntax: `assert_matches!(` *expression* `,` *pattern* `)`
///
/// Panic with a message that shows the expression if it does not match the
/// pattern.
///
/// # Examples
///
/// ```
/// #[macro_use]
/// extern crate matches;
///
/// fn main() {
///     let data = [1, 2, 3];
///     assert_matches!(data.get(1), Some(_));
/// }
/// ```
#[macro_export]
macro_rules! assert_matches {
    ($expression:expr, $($pattern:tt)+) => {
        match $expression {
            $($pattern)+ => (),
            ref e => panic!("assertion failed: `{:?}` does not match `{}`", e, stringify!($($pattern)+)),
        }
    }
}

/// Assert that an expression matches a refutable pattern using debug assertions.
///
/// Syntax: `debug_assert_matches!(` *expression* `,` *pattern* `)`
///
/// If debug assertions are enabled, panic with a message that shows the
/// expression if it does not match the pattern.
///
/// When debug assertions are not enabled, this macro does nothing.
///
/// # Examples
///
/// ```
/// #[macro_use]
/// extern crate matches;
///
/// fn main() {
///     let data = [1, 2, 3];
///     debug_assert_matches!(data.get(1), Some(_));
/// }
/// ```
#[macro_export]
macro_rules! debug_assert_matches {
    ($($arg:tt)*) => (if cfg!(debug_assertions) { assert_matches!($($arg)*); })
}

#[test]
fn matches_works() {
    let foo = Some("-12");
    assert!(matches!(foo, Some(bar) if
        matches!(bar.as_bytes()[0], b'+' | b'-') &&
        matches!(bar.as_bytes()[1], b'0'...b'9')
    ));
}

#[test]
fn assert_matches_works() {
    let foo = Some("-12");
    assert_matches!(foo, Some(bar) if
        matches!(bar.as_bytes()[0], b'+' | b'-') &&
        matches!(bar.as_bytes()[1], b'0'...b'9')
    );
}

#[test]
#[should_panic(expected = "assertion failed: `Some(\"-AB\")` does not match ")]
fn assert_matches_panics() {
    let foo = Some("-AB");
    assert_matches!(foo, Some(bar) if
        matches!(bar.as_bytes()[0], b'+' | b'-') &&
        matches!(bar.as_bytes()[1], b'0'...b'9')
    );
}
<commit_msg>Revert "matches: Remove _matches_tt_as_expr_hack, it is redundant in Rust 1.12+"<commit_after>/// Check if an expression matches a refutable pattern.
///
/// Syntax: `matches!(` *expression* `,` *pattern* `)`
///
/// Return a boolean, true if the expression matches the pattern, false otherwise.
///
/// # Examples
///
/// ```
/// #[macro_use]
/// extern crate matches;
///
/// pub enum Foo<T> {
///     A,
///     B(T),
/// }
///
/// impl<T> Foo<T> {
///     pub fn is_a(&self) -> bool {
///         matches!(*self, Foo::A)
///     }
///
///     pub fn is_b(&self) -> bool {
///         matches!(*self, Foo::B(_))
///     }
/// }
///
/// # fn main() { }
/// ```
#[macro_export]
macro_rules! matches {
    ($expression:expr, $($pattern:tt)+) => {
        _matches_tt_as_expr_hack! {
            match $expression {
                $($pattern)+ => true,
                _ => false
            }
        }
    }
}

/// Work around "error: unexpected token: `an interpolated tt`", whatever that means.
#[macro_export]
macro_rules! _matches_tt_as_expr_hack {
    ($value:expr) => ($value)
}

/// Assert that an expression matches a refutable pattern.
///
/// Syntax: `assert_matches!(` *expression* `,` *pattern* `)`
///
/// Panic with a message that shows the expression if it does not match the
/// pattern.
///
/// # Examples
///
/// ```
/// #[macro_use]
/// extern crate matches;
///
/// fn main() {
///     let data = [1, 2, 3];
///     assert_matches!(data.get(1), Some(_));
/// }
/// ```
#[macro_export]
macro_rules! assert_matches {
    ($expression:expr, $($pattern:tt)+) => {
        _matches_tt_as_expr_hack! {
            match $expression {
                $($pattern)+ => (),
                ref e => panic!("assertion failed: `{:?}` does not match `{}`", e, stringify!($($pattern)+)),
            }
        }
    }
}

/// Assert that an expression matches a refutable pattern using debug assertions.
///
/// Syntax: `debug_assert_matches!(` *expression* `,` *pattern* `)`
///
/// If debug assertions are enabled, panic with a message that shows the
/// expression if it does not match the pattern.
///
/// When debug assertions are not enabled, this macro does nothing.
///
/// # Examples
///
/// ```
/// #[macro_use]
/// extern crate matches;
///
/// fn main() {
///     let data = [1, 2, 3];
///     debug_assert_matches!(data.get(1), Some(_));
/// }
/// ```
#[macro_export]
macro_rules! debug_assert_matches {
    ($($arg:tt)*) => (if cfg!(debug_assertions) { assert_matches!($($arg)*); })
}

#[test]
fn matches_works() {
    let foo = Some("-12");
    assert!(matches!(foo, Some(bar) if
        matches!(bar.as_bytes()[0], b'+' | b'-') &&
        matches!(bar.as_bytes()[1], b'0'...b'9')
    ));
}

#[test]
fn assert_matches_works() {
    let foo = Some("-12");
    assert_matches!(foo, Some(bar) if
        matches!(bar.as_bytes()[0], b'+' | b'-') &&
        matches!(bar.as_bytes()[1], b'0'...b'9')
    );
}

#[test]
#[should_panic(expected = "assertion failed: `Some(\"-AB\")` does not match ")]
fn assert_matches_panics() {
    let foo = Some("-AB");
    assert_matches!(foo, Some(bar) if
        matches!(bar.as_bytes()[0], b'+' | b'-') &&
        matches!(bar.as_bytes()[1], b'0'...b'9')
    );
}
<|endoftext|>