<commit_before><commit_msg>2019: Day 8, part 2.<commit_after>use std::io;

mod digits;
mod errors;

const IMAGE_WIDTH: usize = 25;
const IMAGE_HEIGHT: usize = 6;

type Pixels = Vec<Color>;

#[derive(Debug)]
struct Image {
    width: usize,
    height: usize,
    pixels: Pixels,
}

impl Image {
    fn of_size(width: usize, height: usize) -> Self {
        let size = width * height;
        let mut pixels = Vec::new();
        pixels.resize(size, Color::Transparent);
        Image {
            width,
            height,
            pixels,
        }
    }

    fn print(&self) {
        self.pixels.chunks(self.width).for_each(|row| {
            row.iter().for_each(|pixel| pixel.print());
            println!();
        });
    }
}

struct Layer<'a>(&'a [Color]);

impl Layer<'_> {
    fn apply_to(&self, image: Image) -> Image {
        let pixels = self
            .0
            .iter()
            .zip(image.pixels.into_iter())
            .map(|(layer_pixel, image_pixel)| layer_pixel.paint_onto(image_pixel))
            .collect();
        Image { pixels, ..image }
    }
}

#[derive(Debug, Clone, Copy)]
enum Color {
    Black,
    White,
    Transparent,
}

impl Color {
    fn decode(value: u32) -> Self {
        match value {
            0 => Self::Black,
            1 => Self::White,
            2 => Self::Transparent,
            _ => panic!("Invalid color value: {}", value),
        }
    }

    fn paint_onto(&self, other: Self) -> Self {
        match (self, other) {
            (Self::Black, _) => Self::Black,
            (Self::White, _) => Self::White,
            (Self::Transparent, other) => other,
        }
    }

    fn print(&self) {
        match self {
            Self::Black => print!(" "),
            Self::White => print!("✦"),
            Self::Transparent => panic!("Can't print transparent colors!"),
        }
    }
}

fn main() -> io::Result<()> {
    let mut input = String::new();
    io::stdin().read_line(&mut input)?;

    let image_size = IMAGE_WIDTH * IMAGE_HEIGHT;

    let pixels: Pixels = input
        .trim()
        .chars()
        .map(|c| {
            c.to_digit(10)
                .map(Color::decode)
                .ok_or(errors::io(&format!("Invalid digit: {}", c)))
        })
        .collect::<io::Result<_>>()?;

    let image = pixels
        .chunks(image_size)
        .rev()
        .fold(Image::of_size(IMAGE_WIDTH, IMAGE_HEIGHT), |image, layer| {
            Layer(layer).apply_to(image)
        });

    image.print();

    Ok(())
}
<|endoftext|>


<commit_before>use std::collections::HashMap;
use std::sync::Arc;
use std::fmt::Write;
use super::command::InternalCommand;
use super::{Command, CommandGroup, CommandOrAlias};
use ::client::Context;
use ::model::Message;
use ::utils::Colour;

fn error_embed(ctx: &mut Context, message: &Message, input: &str) {
    let _ = ctx.send_message(message.channel_id, |m| m
        .embed(|e| e
            .colour(Colour::dark_red())
            .description(input)));
}

fn remove_aliases(cmds: &HashMap<String, CommandOrAlias>) -> HashMap<&String, &InternalCommand> {
    let mut result = HashMap::new();

    for (n, v) in cmds {
        if let CommandOrAlias::Command(ref cmd) = *v {
            result.insert(n, cmd);
        }
    }

    result
}

pub fn with_embeds(ctx: &mut Context,
                   message: &Message,
                   groups: HashMap<String, Arc<CommandGroup>>,
                   args: Vec<String>) -> Result<(), String> {
    if !args.is_empty() {
        let name = args.join(" ");

        for (group_name, group) in groups {
            let mut found: Option<(&String, &InternalCommand)> = None;

            for (command_name, command) in &group.commands {
                let with_prefix = if let Some(ref prefix) = group.prefix {
                    format!("{} {}", prefix, command_name)
                } else {
                    command_name.to_owned()
                };

                if name == with_prefix || name == *command_name {
                    match *command {
                        CommandOrAlias::Command(ref cmd) => {
                            found = Some((command_name, cmd));
                        },
                        CommandOrAlias::Alias(ref name) => {
                            error_embed(ctx, message, &format!("Did you mean \"{}\"?", name));
                            return Ok(());
                        }
                    }
                }
            }

            if let Some((command_name, command)) = found {
                if !command.help_available {
                    error_embed(ctx, message, "**Error**: No help available.");

                    return Ok(());
                }

                let _ = ctx.send_message(message.channel_id, |m| {
                    m.embed(|e| {
                        let mut embed = e.colour(Colour::rosewater())
                            .title(command_name);
                        if let Some(ref desc) = command.desc {
                            embed = embed.description(desc);
                        }

                        if let Some(ref usage) = command.usage {
                            embed = embed.field(|f| f
                                .name("Usage")
                                .value(&format!("`{} {}`", command_name, usage)));
                        }

                        if let Some(ref example) = command.example {
                            embed = embed.field(|f| f
                                .name("Sample usage")
                                .value(&format!("`{} {}`", command_name, example)));
                        }

                        if group_name != "Ungrouped" {
                            embed = embed.field(|f| f
                                .name("Group")
                                .value(&group_name));
                        }

                        let available = if command.dm_only {
                            "Only in DM"
                        } else if command.guild_only {
                            "Only in guilds"
                        } else {
                            "In DM and guilds"
                        };

                        embed = embed.field(|f| f
                            .name("Available")
                            .value(available));

                        embed
                    })
                });

                return Ok(());
            }
        }

        let error_msg = format!("**Error**: Command `{}` not found.", name);
        error_embed(ctx, message, &error_msg);

        return Ok(());
    }

    let _ = ctx.send_message(message.channel_id, |m| {
        m.embed(|mut e| {
            e = e.colour(Colour::rosewater())
                .description("To get help with an individual command, pass its \
                              name as an argument to this command.");

            for (group_name, group) in groups {
                let mut desc = String::new();

                if let Some(ref x) = group.prefix {
                    let _ = write!(desc, "Prefix: {}\n", x);
                }

                desc.push_str("Commands:\n");

                let mut no_commands = true;

                for (n, cmd) in remove_aliases(&group.commands) {
                    if cmd.help_available {
                        let _ = write!(desc, "`{}`\n", n);

                        no_commands = false;
                    }
                }

                if no_commands {
                    let _ = write!(desc, "*[No commands]*");
                }

                e = e.field(|f| f.name(&group_name).value(&desc));
            }

            e
        })
    });

    Ok(())
}

pub fn plain(ctx: &mut Context,
             _: &Message,
             groups: HashMap<String, Arc<CommandGroup>>,
             args: Vec<String>) -> Result<(), String> {
    if !args.is_empty() {
        let name = args.join(" ");

        for (group_name, group) in groups {
            let mut found: Option<(&String, &Command)> = None;

            for (command_name, command) in &group.commands {
                let with_prefix = if let Some(ref prefix) = group.prefix {
                    format!("{} {}", prefix, command_name)
                } else {
                    command_name.to_owned()
                };

                if name == with_prefix || name == *command_name  {
                    match *command {
                        CommandOrAlias::Command(ref cmd) => {
                            found = Some((command_name, cmd));
                        },
                        CommandOrAlias::Alias(ref name) => {
                            let _ = ctx.say(&format!("Did you mean {:?}?", name));
                            return Ok(());
                        }
                    }
                }
            }

            if let Some((command_name, command)) = found {
                if !command.help_available {
                    let _ = ctx.say("**Error**: No help available.");
                    return Ok(());
                }

                let mut result = format!("**{}**\n", command_name);

                if let Some(ref desc) = command.desc {
                    let _ = write!(result, "**Description:** {}\n", desc);
                }

                if let Some(ref usage) = command.usage {
                    let _ = write!(result, "**Usage:** `{} {}`\n", command_name, usage);
                }

                if let Some(ref example) = command.example {
                    let _ = write!(result, "**Sample usage:** `{} {}`\n", command_name, example);
                }

                if group_name != "Ungrouped" {
                    let _ = write!(result, "**Group:** {}\n", group_name);
                }

                result.push_str("**Available:** ");
                result.push_str(if command.dm_only {
                    "Only in DM"
                } else if command.guild_only {
                    "Only in guilds"
                } else {
                    "In DM and guilds"
                });
                result.push_str("\n");

                let _ = ctx.say(&result);

                return Ok(());
            }
        }

        let _ = ctx.say(&format!("**Error**: Command `{}` not found.", name));

        return Ok(());
    }

    let mut result = "**Commands**\nTo get help with an individual command, pass its \
                      name as an argument to this command.\n\n"
        .to_string();

    for (group_name, group) in groups {
        let _ = write!(result, "**{}:** ", group_name);

        if let Some(ref x) = group.prefix {
            let _ = write!(result, "(prefix: `{}`): ", x);
        }

        let mut no_commands = true;

        for (n, cmd) in remove_aliases(&group.commands) {
            if cmd.help_available {
                let _ = write!(result, "`{}` ", n);

                no_commands = false;
            }
        }

        if no_commands {
            result.push_str("*[No Commands]*");
        }

        result.push('\n');
    }

    let _ = ctx.say(&result);

    Ok(())
}
<commit_msg>Relisting 'Commands:' is redundant in embed help<commit_after>use std::collections::HashMap;
use std::sync::Arc;
use std::fmt::Write;
use super::command::InternalCommand;
use super::{Command, CommandGroup, CommandOrAlias};
use ::client::Context;
use ::model::Message;
use ::utils::Colour;

fn error_embed(ctx: &mut Context, message: &Message, input: &str) {
    let _ = ctx.send_message(message.channel_id, |m| m
        .embed(|e| e
            .colour(Colour::dark_red())
            .description(input)));
}

fn remove_aliases(cmds: &HashMap<String, CommandOrAlias>) -> HashMap<&String, &InternalCommand> {
    let mut result = HashMap::new();

    for (n, v) in cmds {
        if let CommandOrAlias::Command(ref cmd) = *v {
            result.insert(n, cmd);
        }
    }

    result
}

pub fn with_embeds(ctx: &mut Context,
                   message: &Message,
                   groups: HashMap<String, Arc<CommandGroup>>,
                   args: Vec<String>) -> Result<(), String> {
    if !args.is_empty() {
        let name = args.join(" ");

        for (group_name, group) in groups {
            let mut found: Option<(&String, &InternalCommand)> = None;

            for (command_name, command) in &group.commands {
                let with_prefix = if let Some(ref prefix) = group.prefix {
                    format!("{} {}", prefix, command_name)
                } else {
                    command_name.to_owned()
                };

                if name == with_prefix || name == *command_name {
                    match *command {
                        CommandOrAlias::Command(ref cmd) => {
                            found = Some((command_name, cmd));
                        },
                        CommandOrAlias::Alias(ref name) => {
                            error_embed(ctx, message, &format!("Did you mean \"{}\"?", name));
                            return Ok(());
                        }
                    }
                }
            }

            if let Some((command_name, command)) = found {
                if !command.help_available {
                    error_embed(ctx, message, "**Error**: No help available.");

                    return Ok(());
                }

                let _ = ctx.send_message(message.channel_id, |m| {
                    m.embed(|e| {
                        let mut embed = e.colour(Colour::rosewater())
                            .title(command_name);
                        if let Some(ref desc) = command.desc {
                            embed = embed.description(desc);
                        }

                        if let Some(ref usage) = command.usage {
                            embed = embed.field(|f| f
                                .name("Usage")
                                .value(&format!("`{} {}`", command_name, usage)));
                        }

                        if let Some(ref example) = command.example {
                            embed = embed.field(|f| f
                                .name("Sample usage")
                                .value(&format!("`{} {}`", command_name, example)));
                        }

                        if group_name != "Ungrouped" {
                            embed = embed.field(|f| f
                                .name("Group")
                                .value(&group_name));
                        }

                        let available = if command.dm_only {
                            "Only in DM"
                        } else if command.guild_only {
                            "Only in guilds"
                        } else {
                            "In DM and guilds"
                        };

                        embed = embed.field(|f| f
                            .name("Available")
                            .value(available));

                        embed
                    })
                });

                return Ok(());
            }
        }

        let error_msg = format!("**Error**: Command `{}` not found.", name);
        error_embed(ctx, message, &error_msg);

        return Ok(());
    }

    let _ = ctx.send_message(message.channel_id, |m| {
        m.embed(|mut e| {
            e = e.colour(Colour::rosewater())
                .description("To get help with an individual command, pass its \
                              name as an argument to this command.");

            for (group_name, group) in groups {
                let mut desc = String::new();

                if let Some(ref x) = group.prefix {
                    let _ = write!(desc, "Prefix: {}\n", x);
                }

                let mut no_commands = true;

                for (n, cmd) in remove_aliases(&group.commands) {
                    if cmd.help_available {
                        let _ = write!(desc, "`{}`\n", n);

                        no_commands = false;
                    }
                }

                if no_commands {
                    let _ = write!(desc, "*[No commands]*");
                }

                e = e.field(|f| f.name(&group_name).value(&desc));
            }

            e
        })
    });

    Ok(())
}

pub fn plain(ctx: &mut Context,
             _: &Message,
             groups: HashMap<String, Arc<CommandGroup>>,
             args: Vec<String>) -> Result<(), String> {
    if !args.is_empty() {
        let name = args.join(" ");

        for (group_name, group) in groups {
            let mut found: Option<(&String, &Command)> = None;

            for (command_name, command) in &group.commands {
                let with_prefix = if let Some(ref prefix) = group.prefix {
                    format!("{} {}", prefix, command_name)
                } else {
                    command_name.to_owned()
                };

                if name == with_prefix || name == *command_name  {
                    match *command {
                        CommandOrAlias::Command(ref cmd) => {
                            found = Some((command_name, cmd));
                        },
                        CommandOrAlias::Alias(ref name) => {
                            let _ = ctx.say(&format!("Did you mean {:?}?", name));
                            return Ok(());
                        }
                    }
                }
            }

            if let Some((command_name, command)) = found {
                if !command.help_available {
                    let _ = ctx.say("**Error**: No help available.");
                    return Ok(());
                }

                let mut result = format!("**{}**\n", command_name);

                if let Some(ref desc) = command.desc {
                    let _ = write!(result, "**Description:** {}\n", desc);
                }

                if let Some(ref usage) = command.usage {
                    let _ = write!(result, "**Usage:** `{} {}`\n", command_name, usage);
                }

                if let Some(ref example) = command.example {
                    let _ = write!(result, "**Sample usage:** `{} {}`\n", command_name, example);
                }

                if group_name != "Ungrouped" {
                    let _ = write!(result, "**Group:** {}\n", group_name);
                }

                result.push_str("**Available:** ");
                result.push_str(if command.dm_only {
                    "Only in DM"
                } else if command.guild_only {
                    "Only in guilds"
                } else {
                    "In DM and guilds"
                });
                result.push_str("\n");

                let _ = ctx.say(&result);

                return Ok(());
            }
        }

        let _ = ctx.say(&format!("**Error**: Command `{}` not found.", name));

        return Ok(());
    }

    let mut result = "**Commands**\nTo get help with an individual command, pass its \
                      name as an argument to this command.\n\n"
        .to_string();

    for (group_name, group) in groups {
        let _ = write!(result, "**{}:** ", group_name);

        if let Some(ref x) = group.prefix {
            let _ = write!(result, "(prefix: `{}`): ", x);
        }

        let mut no_commands = true;

        for (n, cmd) in remove_aliases(&group.commands) {
            if cmd.help_available {
                let _ = write!(result, "`{}` ", n);

                no_commands = false;
            }
        }

        if no_commands {
            result.push_str("*[No Commands]*");
        }

        result.push('\n');
    }

    let _ = ctx.say(&result);

    Ok(())
}
<|endoftext|>


<commit_before><commit_msg>delete<commit_after><|endoftext|>


<commit_before><commit_msg>chore: associated function<commit_after><|endoftext|>


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

//! A graph module for use in dataflow, region resolution, and elsewhere.
//!
//! # Interface details
//!
//! You customize the graph by specifying a "node data" type `N` and an
//! "edge data" type `E`. You can then later gain access (mutable or
//! immutable) to these "user-data" bits. Currently, you can only add
//! nodes or edges to the graph. You cannot remove or modify them once
//! added. This could be changed if we have a need.
//!
//! # Implementation details
//!
//! The main tricky thing about this code is the way that edges are
//! stored. The edges are stored in a central array, but they are also
//! threaded onto two linked lists for each node, one for incoming edges
//! and one for outgoing edges. Note that every edge is a member of some
//! incoming list and some outgoing list.  Basically you can load the
//! first index of the linked list from the node data structures (the
//! field `first_edge`) and then, for each edge, load the next index from
//! the field `next_edge`). Each of those fields is an array that should
//! be indexed by the direction (see the type `Direction`).

use bitvec::BitVector;
use std::fmt::{Formatter, Error, Debug};
use std::usize;
use snapshot_vec::{SnapshotVec, SnapshotVecDelegate};

#[cfg(test)]
mod tests;

pub struct Graph<N, E> {
    nodes: SnapshotVec<Node<N>>,
    edges: SnapshotVec<Edge<E>>,
}

pub struct Node<N> {
    first_edge: [EdgeIndex; 2], // see module comment
    pub data: N,
}

pub struct Edge<E> {
    next_edge: [EdgeIndex; 2], // see module comment
    source: NodeIndex,
    target: NodeIndex,
    pub data: E,
}

impl<N> SnapshotVecDelegate for Node<N> {
    type Value = Node<N>;
    type Undo = ();

    fn reverse(_: &mut Vec<Node<N>>, _: ()) {}
}

impl<N> SnapshotVecDelegate for Edge<N> {
    type Value = Edge<N>;
    type Undo = ();

    fn reverse(_: &mut Vec<Edge<N>>, _: ()) {}
}

impl<E: Debug> Debug for Edge<E> {
    fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
        write!(f,
               "Edge {{ next_edge: [{:?}, {:?}], source: {:?}, target: {:?}, data: {:?} }}",
               self.next_edge[0],
               self.next_edge[1],
               self.source,
               self.target,
               self.data)
    }
}

#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)]
pub struct NodeIndex(pub usize);

#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)]
pub struct EdgeIndex(pub usize);

pub const INVALID_EDGE_INDEX: EdgeIndex = EdgeIndex(usize::MAX);

// Use a private field here to guarantee no more instances are created:
#[derive(Copy, Clone, Debug, PartialEq)]
pub struct Direction {
    repr: usize,
}

pub const OUTGOING: Direction = Direction { repr: 0 };

pub const INCOMING: Direction = Direction { repr: 1 };

impl NodeIndex {
    /// Returns unique id (unique with respect to the graph holding associated node).
    pub fn node_id(&self) -> usize {
        self.0
    }
}

impl EdgeIndex {
    /// Returns unique id (unique with respect to the graph holding associated edge).
    pub fn edge_id(&self) -> usize {
        self.0
    }
}

impl<N: Debug, E: Debug> Graph<N, E> {
    pub fn new() -> Graph<N, E> {
        Graph {
            nodes: SnapshotVec::new(),
            edges: SnapshotVec::new(),
        }
    }

    // # Simple accessors

    #[inline]
    pub fn all_nodes(&self) -> &[Node<N>] {
        &self.nodes
    }

    #[inline]
    pub fn len_nodes(&self) -> usize {
        self.nodes.len()
    }

    #[inline]
    pub fn all_edges(&self) -> &[Edge<E>] {
        &self.edges
    }

    #[inline]
    pub fn len_edges(&self) -> usize {
        self.edges.len()
    }

    // # Node construction

    pub fn next_node_index(&self) -> NodeIndex {
        NodeIndex(self.nodes.len())
    }

    pub fn add_node(&mut self, data: N) -> NodeIndex {
        let idx = self.next_node_index();
        self.nodes.push(Node {
            first_edge: [INVALID_EDGE_INDEX, INVALID_EDGE_INDEX],
            data: data,
        });
        idx
    }

    pub fn mut_node_data(&mut self, idx: NodeIndex) -> &mut N {
        &mut self.nodes[idx.0].data
    }

    pub fn node_data(&self, idx: NodeIndex) -> &N {
        &self.nodes[idx.0].data
    }

    pub fn node(&self, idx: NodeIndex) -> &Node<N> {
        &self.nodes[idx.0]
    }

    // # Edge construction and queries

    pub fn next_edge_index(&self) -> EdgeIndex {
        EdgeIndex(self.edges.len())
    }

    pub fn add_edge(&mut self, source: NodeIndex, target: NodeIndex, data: E) -> EdgeIndex {
        debug!("graph: add_edge({:?}, {:?}, {:?})", source, target, data);

        let idx = self.next_edge_index();

        // read current first of the list of edges from each node
        let source_first = self.nodes[source.0].first_edge[OUTGOING.repr];
        let target_first = self.nodes[target.0].first_edge[INCOMING.repr];

        // create the new edge, with the previous firsts from each node
        // as the next pointers
        self.edges.push(Edge {
            next_edge: [source_first, target_first],
            source: source,
            target: target,
            data: data,
        });

        // adjust the firsts for each node target be the next object.
        self.nodes[source.0].first_edge[OUTGOING.repr] = idx;
        self.nodes[target.0].first_edge[INCOMING.repr] = idx;

        return idx;
    }

    pub fn mut_edge_data(&mut self, idx: EdgeIndex) -> &mut E {
        &mut self.edges[idx.0].data
    }

    pub fn edge_data(&self, idx: EdgeIndex) -> &E {
        &self.edges[idx.0].data
    }

    pub fn edge(&self, idx: EdgeIndex) -> &Edge<E> {
        &self.edges[idx.0]
    }

    pub fn first_adjacent(&self, node: NodeIndex, dir: Direction) -> EdgeIndex {
        //! Accesses the index of the first edge adjacent to `node`.
        //! This is useful if you wish to modify the graph while walking
        //! the linked list of edges.

        self.nodes[node.0].first_edge[dir.repr]
    }

    pub fn next_adjacent(&self, edge: EdgeIndex, dir: Direction) -> EdgeIndex {
        //! Accesses the next edge in a given direction.
        //! This is useful if you wish to modify the graph while walking
        //! the linked list of edges.

        self.edges[edge.0].next_edge[dir.repr]
    }

    // # Iterating over nodes, edges

    pub fn each_node<'a, F>(&'a self, mut f: F) -> bool
        where F: FnMut(NodeIndex, &'a Node<N>) -> bool
    {
        //! Iterates over all edges defined in the graph.
        self.nodes.iter().enumerate().all(|(i, node)| f(NodeIndex(i), node))
    }

    pub fn each_edge<'a, F>(&'a self, mut f: F) -> bool
        where F: FnMut(EdgeIndex, &'a Edge<E>) -> bool
    {
        //! Iterates over all edges defined in the graph
        self.edges.iter().enumerate().all(|(i, edge)| f(EdgeIndex(i), edge))
    }

    pub fn outgoing_edges(&self, source: NodeIndex) -> AdjacentEdges<N, E> {
        self.adjacent_edges(source, OUTGOING)
    }

    pub fn incoming_edges(&self, source: NodeIndex) -> AdjacentEdges<N, E> {
        self.adjacent_edges(source, INCOMING)
    }

    pub fn adjacent_edges(&self, source: NodeIndex, direction: Direction) -> AdjacentEdges<N, E> {
        let first_edge = self.node(source).first_edge[direction.repr];
        AdjacentEdges {
            graph: self,
            direction: direction,
            next: first_edge,
        }
    }

    pub fn successor_nodes(&self, source: NodeIndex) -> AdjacentTargets<N, E> {
        self.outgoing_edges(source).targets()
    }

    pub fn predecessor_nodes(&self, target: NodeIndex) -> AdjacentSources<N, E> {
        self.incoming_edges(target).sources()
    }

    // # Fixed-point iteration
    //
    // A common use for graphs in our compiler is to perform
    // fixed-point iteration. In this case, each edge represents a
    // constraint, and the nodes themselves are associated with
    // variables or other bitsets. This method facilitates such a
    // computation.

    pub fn iterate_until_fixed_point<'a, F>(&'a self, mut op: F)
        where F: FnMut(usize, EdgeIndex, &'a Edge<E>) -> bool
    {
        let mut iteration = 0;
        let mut changed = true;
        while changed {
            changed = false;
            iteration += 1;
            for (i, edge) in self.edges.iter().enumerate() {
                changed |= op(iteration, EdgeIndex(i), edge);
            }
        }
    }

    pub fn depth_traverse<'a>(&'a self,
                              start: NodeIndex,
                              direction: Direction)
                              -> DepthFirstTraversal<'a, N, E> {
        DepthFirstTraversal::with_start_node(self, start, direction)
    }
}

// # Iterators

pub struct AdjacentEdges<'g, N, E>
    where N: 'g,
          E: 'g
{
    graph: &'g Graph<N, E>,
    direction: Direction,
    next: EdgeIndex,
}

impl<'g, N, E> AdjacentEdges<'g, N, E> {
    fn targets(self) -> AdjacentTargets<'g, N, E> {
        AdjacentTargets { edges: self }
    }

    fn sources(self) -> AdjacentSources<'g, N, E> {
        AdjacentSources { edges: self }
    }
}

impl<'g, N: Debug, E: Debug> Iterator for AdjacentEdges<'g, N, E> {
    type Item = (EdgeIndex, &'g Edge<E>);

    fn next(&mut self) -> Option<(EdgeIndex, &'g Edge<E>)> {
        let edge_index = self.next;
        if edge_index == INVALID_EDGE_INDEX {
            return None;
        }

        let edge = self.graph.edge(edge_index);
        self.next = edge.next_edge[self.direction.repr];
        Some((edge_index, edge))
    }
}

pub struct AdjacentTargets<'g, N: 'g, E: 'g>
    where N: 'g,
          E: 'g
{
    edges: AdjacentEdges<'g, N, E>,
}

impl<'g, N: Debug, E: Debug> Iterator for AdjacentTargets<'g, N, E> {
    type Item = NodeIndex;

    fn next(&mut self) -> Option<NodeIndex> {
        self.edges.next().map(|(_, edge)| edge.target)
    }
}

pub struct AdjacentSources<'g, N: 'g, E: 'g>
    where N: 'g,
          E: 'g
{
    edges: AdjacentEdges<'g, N, E>,
}

impl<'g, N: Debug, E: Debug> Iterator for AdjacentSources<'g, N, E> {
    type Item = NodeIndex;

    fn next(&mut self) -> Option<NodeIndex> {
        self.edges.next().map(|(_, edge)| edge.source)
    }
}

pub struct DepthFirstTraversal<'g, N: 'g, E: 'g> {
    graph: &'g Graph<N, E>,
    stack: Vec<NodeIndex>,
    visited: BitVector,
    direction: Direction,
}

impl<'g, N: Debug, E: Debug> DepthFirstTraversal<'g, N, E> {
    pub fn new(graph: &'g Graph<N, E>, direction: Direction) -> Self {
        let visited = BitVector::new(graph.len_nodes());
        DepthFirstTraversal {
            graph: graph,
            stack: vec![],
            visited: visited,
            direction: direction
        }
    }

    pub fn with_start_node(graph: &'g Graph<N, E>,
                           start_node: NodeIndex,
                           direction: Direction)
                           -> Self {
        let mut visited = BitVector::new(graph.len_nodes());
        visited.insert(start_node.node_id());
        DepthFirstTraversal {
            graph: graph,
            stack: vec![start_node],
            visited: visited,
            direction: direction
        }
    }

    pub fn reset(&mut self, start_node: NodeIndex) {
        self.stack.truncate(0);
        self.stack.push(start_node);
        self.visited.clear();
        self.visited.insert(start_node.node_id());
    }

    fn visit(&mut self, node: NodeIndex) {
        if self.visited.insert(node.node_id()) {
            self.stack.push(node);
        }
    }
}

impl<'g, N: Debug, E: Debug> Iterator for DepthFirstTraversal<'g, N, E> {
    type Item = NodeIndex;

    fn next(&mut self) -> Option<NodeIndex> {
        let next = self.stack.pop();
        if let Some(idx) = next {
            for (_, edge) in self.graph.adjacent_edges(idx, self.direction) {
                let target = edge.source_or_target(self.direction);
                self.visit(target);
            }
        }
        next
    }
}

pub fn each_edge_index<F>(max_edge_index: EdgeIndex, mut f: F)
    where F: FnMut(EdgeIndex) -> bool
{
    let mut i = 0;
    let n = max_edge_index.0;
    while i < n {
        if !f(EdgeIndex(i)) {
            return;
        }
        i += 1;
    }
}

impl<E> Edge<E> {
    pub fn source(&self) -> NodeIndex {
        self.source
    }

    pub fn target(&self) -> NodeIndex {
        self.target
    }

    pub fn source_or_target(&self, direction: Direction) -> NodeIndex {
        if direction == OUTGOING {
            self.target
        } else {
            self.source
        }
    }
}
<commit_msg>Rollup merge of #37286 - srinivasreddy:graph, r=nrc<commit_after>// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! A graph module for use in dataflow, region resolution, and elsewhere.
//!
//! # Interface details
//!
//! You customize the graph by specifying a "node data" type `N` and an
//! "edge data" type `E`. You can then later gain access (mutable or
//! immutable) to these "user-data" bits. Currently, you can only add
//! nodes or edges to the graph. You cannot remove or modify them once
//! added. This could be changed if we have a need.
//!
//! # Implementation details
//!
//! The main tricky thing about this code is the way that edges are
//! stored. The edges are stored in a central array, but they are also
//! threaded onto two linked lists for each node, one for incoming edges
//! and one for outgoing edges. Note that every edge is a member of some
//! incoming list and some outgoing list.  Basically you can load the
//! first index of the linked list from the node data structures (the
//! field `first_edge`) and then, for each edge, load the next index from
//! the field `next_edge`). Each of those fields is an array that should
//! be indexed by the direction (see the type `Direction`).

use bitvec::BitVector;
use std::fmt::{Formatter, Error, Debug};
use std::usize;
use snapshot_vec::{SnapshotVec, SnapshotVecDelegate};

#[cfg(test)]
mod tests;

pub struct Graph<N, E> {
    nodes: SnapshotVec<Node<N>>,
    edges: SnapshotVec<Edge<E>>,
}

pub struct Node<N> {
    first_edge: [EdgeIndex; 2], // see module comment
    pub data: N,
}

pub struct Edge<E> {
    next_edge: [EdgeIndex; 2], // see module comment
    source: NodeIndex,
    target: NodeIndex,
    pub data: E,
}

impl<N> SnapshotVecDelegate for Node<N> {
    type Value = Node<N>;
    type Undo = ();

    fn reverse(_: &mut Vec<Node<N>>, _: ()) {}
}

impl<N> SnapshotVecDelegate for Edge<N> {
    type Value = Edge<N>;
    type Undo = ();

    fn reverse(_: &mut Vec<Edge<N>>, _: ()) {}
}

impl<E: Debug> Debug for Edge<E> {
    fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
        write!(f,
               "Edge {{ next_edge: [{:?}, {:?}], source: {:?}, target: {:?}, data: {:?} }}",
               self.next_edge[0],
               self.next_edge[1],
               self.source,
               self.target,
               self.data)
    }
}

#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)]
pub struct NodeIndex(pub usize);

#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)]
pub struct EdgeIndex(pub usize);

pub const INVALID_EDGE_INDEX: EdgeIndex = EdgeIndex(usize::MAX);

// Use a private field here to guarantee no more instances are created:
#[derive(Copy, Clone, Debug, PartialEq)]
pub struct Direction {
    repr: usize,
}

pub const OUTGOING: Direction = Direction { repr: 0 };

pub const INCOMING: Direction = Direction { repr: 1 };

impl NodeIndex {
    /// Returns unique id (unique with respect to the graph holding associated node).
    pub fn node_id(&self) -> usize {
        self.0
    }
}

impl EdgeIndex {
    /// Returns unique id (unique with respect to the graph holding associated edge).
    pub fn edge_id(&self) -> usize {
        self.0
    }
}

impl<N: Debug, E: Debug> Graph<N, E> {
    pub fn new() -> Graph<N, E> {
        Graph {
            nodes: SnapshotVec::new(),
            edges: SnapshotVec::new(),
        }
    }

    // # Simple accessors

    #[inline]
    pub fn all_nodes(&self) -> &[Node<N>] {
        &self.nodes
    }

    #[inline]
    pub fn len_nodes(&self) -> usize {
        self.nodes.len()
    }

    #[inline]
    pub fn all_edges(&self) -> &[Edge<E>] {
        &self.edges
    }

    #[inline]
    pub fn len_edges(&self) -> usize {
        self.edges.len()
    }

    // # Node construction

    pub fn next_node_index(&self) -> NodeIndex {
        NodeIndex(self.nodes.len())
    }

    pub fn add_node(&mut self, data: N) -> NodeIndex {
        let idx = self.next_node_index();
        self.nodes.push(Node {
            first_edge: [INVALID_EDGE_INDEX, INVALID_EDGE_INDEX],
            data: data,
        });
        idx
    }

    pub fn mut_node_data(&mut self, idx: NodeIndex) -> &mut N {
        &mut self.nodes[idx.0].data
    }

    pub fn node_data(&self, idx: NodeIndex) -> &N {
        &self.nodes[idx.0].data
    }

    pub fn node(&self, idx: NodeIndex) -> &Node<N> {
        &self.nodes[idx.0]
    }

    // # Edge construction and queries

    pub fn next_edge_index(&self) -> EdgeIndex {
        EdgeIndex(self.edges.len())
    }

    pub fn add_edge(&mut self, source: NodeIndex, target: NodeIndex, data: E) -> EdgeIndex {
        debug!("graph: add_edge({:?}, {:?}, {:?})", source, target, data);

        let idx = self.next_edge_index();

        // read current first of the list of edges from each node
        let source_first = self.nodes[source.0].first_edge[OUTGOING.repr];
        let target_first = self.nodes[target.0].first_edge[INCOMING.repr];

        // create the new edge, with the previous firsts from each node
        // as the next pointers
        self.edges.push(Edge {
            next_edge: [source_first, target_first],
            source: source,
            target: target,
            data: data,
        });

        // adjust the firsts for each node target be the next object.
        self.nodes[source.0].first_edge[OUTGOING.repr] = idx;
        self.nodes[target.0].first_edge[INCOMING.repr] = idx;

        return idx;
    }

    pub fn mut_edge_data(&mut self, idx: EdgeIndex) -> &mut E {
        &mut self.edges[idx.0].data
    }

    pub fn edge_data(&self, idx: EdgeIndex) -> &E {
        &self.edges[idx.0].data
    }

    pub fn edge(&self, idx: EdgeIndex) -> &Edge<E> {
        &self.edges[idx.0]
    }

    pub fn first_adjacent(&self, node: NodeIndex, dir: Direction) -> EdgeIndex {
        //! Accesses the index of the first edge adjacent to `node`.
        //! This is useful if you wish to modify the graph while walking
        //! the linked list of edges.

        self.nodes[node.0].first_edge[dir.repr]
    }

    pub fn next_adjacent(&self, edge: EdgeIndex, dir: Direction) -> EdgeIndex {
        //! Accesses the next edge in a given direction.
        //! This is useful if you wish to modify the graph while walking
        //! the linked list of edges.

        self.edges[edge.0].next_edge[dir.repr]
    }

    // # Iterating over nodes, edges

    pub fn each_node<'a, F>(&'a self, mut f: F) -> bool
        where F: FnMut(NodeIndex, &'a Node<N>) -> bool
    {
        //! Iterates over all edges defined in the graph.
        self.nodes.iter().enumerate().all(|(i, node)| f(NodeIndex(i), node))
    }

    pub fn each_edge<'a, F>(&'a self, mut f: F) -> bool
        where F: FnMut(EdgeIndex, &'a Edge<E>) -> bool
    {
        //! Iterates over all edges defined in the graph
        self.edges.iter().enumerate().all(|(i, edge)| f(EdgeIndex(i), edge))
    }

    pub fn outgoing_edges(&self, source: NodeIndex) -> AdjacentEdges<N, E> {
        self.adjacent_edges(source, OUTGOING)
    }

    pub fn incoming_edges(&self, source: NodeIndex) -> AdjacentEdges<N, E> {
        self.adjacent_edges(source, INCOMING)
    }

    pub fn adjacent_edges(&self, source: NodeIndex, direction: Direction) -> AdjacentEdges<N, E> {
        let first_edge = self.node(source).first_edge[direction.repr];
        AdjacentEdges {
            graph: self,
            direction: direction,
            next: first_edge,
        }
    }

    pub fn successor_nodes(&self, source: NodeIndex) -> AdjacentTargets<N, E> {
        self.outgoing_edges(source).targets()
    }

    pub fn predecessor_nodes(&self, target: NodeIndex) -> AdjacentSources<N, E> {
        self.incoming_edges(target).sources()
    }

    // # Fixed-point iteration
    //
    // A common use for graphs in our compiler is to perform
    // fixed-point iteration. In this case, each edge represents a
    // constraint, and the nodes themselves are associated with
    // variables or other bitsets. This method facilitates such a
    // computation.

    pub fn iterate_until_fixed_point<'a, F>(&'a self, mut op: F)
        where F: FnMut(usize, EdgeIndex, &'a Edge<E>) -> bool
    {
        let mut iteration = 0;
        let mut changed = true;
        while changed {
            changed = false;
            iteration += 1;
            for (i, edge) in self.edges.iter().enumerate() {
                changed |= op(iteration, EdgeIndex(i), edge);
            }
        }
    }

    pub fn depth_traverse<'a>(&'a self,
                              start: NodeIndex,
                              direction: Direction)
                              -> DepthFirstTraversal<'a, N, E> {
        DepthFirstTraversal::with_start_node(self, start, direction)
    }
}

// # Iterators

pub struct AdjacentEdges<'g, N, E>
    where N: 'g,
          E: 'g
{
    graph: &'g Graph<N, E>,
    direction: Direction,
    next: EdgeIndex,
}

impl<'g, N, E> AdjacentEdges<'g, N, E> {
    fn targets(self) -> AdjacentTargets<'g, N, E> {
        AdjacentTargets { edges: self }
    }

    fn sources(self) -> AdjacentSources<'g, N, E> {
        AdjacentSources { edges: self }
    }
}

impl<'g, N: Debug, E: Debug> Iterator for AdjacentEdges<'g, N, E> {
    type Item = (EdgeIndex, &'g Edge<E>);

    fn next(&mut self) -> Option<(EdgeIndex, &'g Edge<E>)> {
        let edge_index = self.next;
        if edge_index == INVALID_EDGE_INDEX {
            return None;
        }

        let edge = self.graph.edge(edge_index);
        self.next = edge.next_edge[self.direction.repr];
        Some((edge_index, edge))
    }
}

pub struct AdjacentTargets<'g, N: 'g, E: 'g>
    where N: 'g,
          E: 'g
{
    edges: AdjacentEdges<'g, N, E>,
}

impl<'g, N: Debug, E: Debug> Iterator for AdjacentTargets<'g, N, E> {
    type Item = NodeIndex;

    fn next(&mut self) -> Option<NodeIndex> {
        self.edges.next().map(|(_, edge)| edge.target)
    }
}

pub struct AdjacentSources<'g, N: 'g, E: 'g>
    where N: 'g,
          E: 'g
{
    edges: AdjacentEdges<'g, N, E>,
}

impl<'g, N: Debug, E: Debug> Iterator for AdjacentSources<'g, N, E> {
    type Item = NodeIndex;

    fn next(&mut self) -> Option<NodeIndex> {
        self.edges.next().map(|(_, edge)| edge.source)
    }
}

pub struct DepthFirstTraversal<'g, N: 'g, E: 'g> {
    graph: &'g Graph<N, E>,
    stack: Vec<NodeIndex>,
    visited: BitVector,
    direction: Direction,
}

impl<'g, N: Debug, E: Debug> DepthFirstTraversal<'g, N, E> {
    pub fn new(graph: &'g Graph<N, E>, direction: Direction) -> Self {
        let visited = BitVector::new(graph.len_nodes());
        DepthFirstTraversal {
            graph: graph,
            stack: vec![],
            visited: visited,
            direction: direction,
        }
    }

    pub fn with_start_node(graph: &'g Graph<N, E>,
                           start_node: NodeIndex,
                           direction: Direction)
                           -> Self {
        let mut visited = BitVector::new(graph.len_nodes());
        visited.insert(start_node.node_id());
        DepthFirstTraversal {
            graph: graph,
            stack: vec![start_node],
            visited: visited,
            direction: direction,
        }
    }

    pub fn reset(&mut self, start_node: NodeIndex) {
        self.stack.truncate(0);
        self.stack.push(start_node);
        self.visited.clear();
        self.visited.insert(start_node.node_id());
    }

    fn visit(&mut self, node: NodeIndex) {
        if self.visited.insert(node.node_id()) {
            self.stack.push(node);
        }
    }
}

impl<'g, N: Debug, E: Debug> Iterator for DepthFirstTraversal<'g, N, E> {
    type Item = NodeIndex;

    fn next(&mut self) -> Option<NodeIndex> {
        let next = self.stack.pop();
        if let Some(idx) = next {
            for (_, edge) in self.graph.adjacent_edges(idx, self.direction) {
                let target = edge.source_or_target(self.direction);
                self.visit(target);
            }
        }
        next
    }
}

pub fn each_edge_index<F>(max_edge_index: EdgeIndex, mut f: F)
    where F: FnMut(EdgeIndex) -> bool
{
    let mut i = 0;
    let n = max_edge_index.0;
    while i < n {
        if !f(EdgeIndex(i)) {
            return;
        }
        i += 1;
    }
}

impl<E> Edge<E> {
    pub fn source(&self) -> NodeIndex {
        self.source
    }

    pub fn target(&self) -> NodeIndex {
        self.target
    }

    pub fn source_or_target(&self, direction: Direction) -> NodeIndex {
        if direction == OUTGOING {
            self.target
        } else {
            self.source
        }
    }
}
<|endoftext|>


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

use std::collections::HashSet;
use std::collections::hash_map::RandomState;
use std::iter::FromIterator;
use std::path::Path;
use std::path::PathBuf;
use std::vec::Vec;

use devicemapper::consts::SECTOR_SIZE;
use devicemapper::DM;
use devicemapper::{DataBlocks, Sectors, Segment};
use devicemapper::LinearDev;
use devicemapper::{ThinPoolDev, ThinPoolStatus, ThinPoolWorkingStatus};
use time::now;
use uuid::Uuid;
use serde_json;

use super::super::consts::IEC::Mi;
use super::super::engine::{Filesystem, HasName, HasUuid, Pool};
use super::super::errors::{EngineError, EngineResult, ErrorEnum};
use super::super::structures::Table;
use super::super::types::{FilesystemUuid, RenameAction, Redundancy};

use super::blockdevmgr::BlockDevMgr;
use super::device::wipe_sectors;
use super::dmdevice::{FlexRole, ThinPoolRole, format_flex_name, format_thinpool_name};
use super::filesystem::{StratFilesystem, FilesystemStatus};
use super::mdv::MetadataVol;
use super::metadata::MIN_MDA_SECTORS;
use super::serde_structs::{FlexDevsSave, PoolSave, Recordable, ThinPoolDevSave};

const DATA_BLOCK_SIZE: Sectors = Sectors(2048);
const META_LOWATER: u64 = 512;
const DATA_LOWATER: DataBlocks = DataBlocks(512);

const INITIAL_META_SIZE: Sectors = Sectors(16 * Mi / SECTOR_SIZE as u64);
const INITIAL_DATA_SIZE: Sectors = Sectors(512 * Mi / SECTOR_SIZE as u64);
const INITIAL_MDV_SIZE: Sectors = Sectors(16 * Mi / SECTOR_SIZE as u64);

#[derive(Debug)]
pub struct StratPool {
    name: String,
    pool_uuid: Uuid,
    pub block_devs: BlockDevMgr,
    pub filesystems: Table<StratFilesystem>,
    redundancy: Redundancy,
    thin_pool: ThinPoolDev,
    mdv: MetadataVol,
}

impl StratPool {
    /// Initialize a Stratis Pool.
    /// 1. Initialize the block devices specified by paths.
    /// 2. Set up thinpool device to back filesystems.
    pub fn initialize(name: &str,
                      dm: &DM,
                      paths: &[&Path],
                      redundancy: Redundancy,
                      force: bool)
                      -> EngineResult<StratPool> {
        let pool_uuid = Uuid::new_v4();

        let mut block_mgr =
            try!(BlockDevMgr::initialize(&pool_uuid, paths, MIN_MDA_SECTORS, force));

        if block_mgr.avail_space() < StratPool::min_initial_size() {
            let avail_size = block_mgr.avail_space().bytes();
            try!(block_mgr.destroy_all());
            return Err(EngineError::Engine(ErrorEnum::Invalid,
                                           format!("Space on pool must be at least {} bytes, \
                                                   available space is only {} bytes",
                                                   StratPool::min_initial_size().bytes(),
                                                   avail_size)));

        }

        let meta_regions = block_mgr
            .alloc_space(INITIAL_META_SIZE)
            .expect("blockmgr must not fail, already checked for space");
        let device_name = format_flex_name(&pool_uuid, FlexRole::ThinMeta);
        let meta_dev = try!(LinearDev::new(&device_name, dm, meta_regions));

        // When constructing a thin-pool, Stratis reserves the first N
        // sectors on a block device by creating a linear device with a
        // starting offset. DM writes the super block in the first block.
        // DM requires this first block to be zeros when the meta data for
        // the thin-pool is initially created. If we don't zero the
        // superblock DM issue error messages because it triggers code paths
        // that are trying to re-adopt the device with the attributes that
        // have been passed.
        try!(wipe_sectors(&try!(meta_dev.devnode()), Sectors(0), INITIAL_META_SIZE));

        let data_regions = block_mgr
            .alloc_space(INITIAL_DATA_SIZE)
            .expect("blockmgr must not fail, already checked for space");
        let device_name = format_flex_name(&pool_uuid, FlexRole::ThinData);
        let data_dev = try!(LinearDev::new(&device_name, dm, data_regions));
        let length = try!(data_dev.size());

        let device_name = format_thinpool_name(&pool_uuid, ThinPoolRole::Pool);
        // TODO Fix hard coded data blocksize and low water mark.
        let thinpool_dev = try!(ThinPoolDev::new(&device_name,
                                                 dm,
                                                 length,
                                                 DATA_BLOCK_SIZE,
                                                 DataBlocks(256000),
                                                 meta_dev,
                                                 data_dev));

        let mdv_regions = block_mgr
            .alloc_space(INITIAL_MDV_SIZE)
            .expect("blockmgr must not fail, already checked for space");
        let device_name = format_flex_name(&pool_uuid, FlexRole::MetadataVolume);
        let mdv_dev = try!(LinearDev::new(&device_name, dm, mdv_regions));
        let mdv = try!(MetadataVol::initialize(&pool_uuid, mdv_dev));

        let mut pool = StratPool {
            name: name.to_owned(),
            pool_uuid: pool_uuid,
            block_devs: block_mgr,
            filesystems: Table::new(),
            redundancy: redundancy,
            thin_pool: thinpool_dev,
            mdv: mdv,
        };

        try!(pool.write_metadata());

        Ok(pool)
    }

    /// Minimum initial size for a pool.
    pub fn min_initial_size() -> Sectors {
        INITIAL_META_SIZE + INITIAL_DATA_SIZE + INITIAL_MDV_SIZE
    }

    // TODO: Check current time against global last updated, and use
    // alternate time value if earlier, as described in SWDD
    fn write_metadata(&mut self) -> EngineResult<()> {
        let data = try!(serde_json::to_string(&try!(self.record())));
        self.block_devs
            .save_state(&now().to_timespec(), data.as_bytes())
    }

    pub fn check(&mut self) -> () {
        let dm = DM::new().expect("Could not get DM handle");

        if let Err(e) = self.mdv.check() {
            error!("MDV error: {}", e);
            return;
        }

        let result = match self.thin_pool.status(&dm) {
            Ok(r) => r,
            Err(_) => {
                error!("Could not get thinpool status");
                // TODO: Take pool offline?
                return;
            }
        };

        match result {
            ThinPoolStatus::Good(wstatus, usage) => {
                match wstatus {
                    ThinPoolWorkingStatus::Good => {}
                    ThinPoolWorkingStatus::ReadOnly => {
                        // TODO: why is pool r/o and how do we get it
                        // rw again?
                    }
                    ThinPoolWorkingStatus::OutOfSpace => {
                        // TODO: Add more space if possible, or
                        // prevent further usage
                        // Should never happen -- we should be extending first!
                    }
                    ThinPoolWorkingStatus::NeedsCheck => {
                        // TODO: Take pool offline?
                        // TODO: run thin_check
                    }
                }

                if usage.used_meta > usage.total_meta - META_LOWATER {
                    // TODO: Extend meta device
                }

                if usage.used_data > usage.total_data - DATA_LOWATER {
                    // TODO: Extend data device
                }
            }
            ThinPoolStatus::Fail => {
                // TODO: Take pool offline?
                // TODO: Run thin_check
            }
        }

        for fs in &mut self.filesystems {
            match fs.check(&dm) {
                Ok(f_status) => {
                    if let FilesystemStatus::Failed = f_status {
                        // TODO: recover fs? (how?)
                    }
                }
                Err(_e) => error!("fs.check() failed"),
            }
        }
    }

    /// Teardown a pool.
    /// Take down the device mapper devices belonging to the pool.
    /// This method and destroy() must keep their DM teardown operations
    /// in sync.
    pub fn teardown(self) -> EngineResult<()> {
        // TODO: any necessary clean up of filesystems
        if !self.filesystems.is_empty() {
            return Err(EngineError::Engine(ErrorEnum::Busy,
                                           format!("May be unsynced files on device.")));
        }
        let dm = try!(DM::new());
        try!(self.thin_pool.teardown(&dm));
        try!(self.mdv.teardown(&dm));
        Ok(())
    }
}

impl Pool for StratPool {
    fn create_filesystems<'a, 'b>(&'a mut self,
                                  specs: &[&'b str])
                                  -> EngineResult<Vec<(&'b str, FilesystemUuid)>> {
        let names: HashSet<_, RandomState> = HashSet::from_iter(specs);
        for name in names.iter() {
            if self.filesystems.contains_name(name) {
                return Err(EngineError::Engine(ErrorEnum::AlreadyExists, name.to_string()));
            }
        }

        // TODO: Roll back on filesystem initialization failure.
        let dm = try!(DM::new());
        let mut result = Vec::new();
        for name in names.iter() {
            let uuid = Uuid::new_v4();
            let new_filesystem = try!(StratFilesystem::initialize(&self.pool_uuid,
                                                                  uuid,
                                                                  name,
                                                                  &dm,
                                                                  &mut self.thin_pool));
            try!(self.mdv.save_fs(&new_filesystem));
            self.filesystems.insert(new_filesystem);
            result.push((**name, uuid));
        }

        Ok(result)
    }

    fn add_blockdevs(&mut self, paths: &[&Path], force: bool) -> EngineResult<Vec<PathBuf>> {
        let bdev_paths = try!(self.block_devs.add(&self.pool_uuid, paths, force));
        try!(self.write_metadata());
        Ok(bdev_paths)
    }

    fn destroy(self) -> EngineResult<()> {
        // Ensure that DM teardown operations in this method are in sync
        // with operations in teardown().
        let dm = try!(DM::new());
        try!(self.thin_pool.teardown(&dm));
        try!(self.mdv.teardown(&dm));
        try!(self.block_devs.destroy_all());

        Ok(())
    }

    fn destroy_filesystems<'a, 'b>(&'a mut self,
                                   fs_uuids: &[&'b FilesystemUuid])
                                   -> EngineResult<Vec<&'b FilesystemUuid>> {
        for fsid in fs_uuids {
            try!(self.mdv.rm_fs(fsid));
        }
        destroy_filesystems!{self; fs_uuids}
    }

    fn rename_filesystem(&mut self,
                         uuid: &FilesystemUuid,
                         new_name: &str)
                         -> EngineResult<RenameAction> {
        rename_filesystem!{self; uuid; new_name}
    }

    fn rename(&mut self, name: &str) {
        self.name = name.to_owned();
    }

    fn get_filesystem(&mut self, uuid: &FilesystemUuid) -> Option<&mut Filesystem> {
        get_filesystem!(self; uuid)
    }
}

impl HasUuid for StratPool {
    fn uuid(&self) -> &FilesystemUuid {
        &self.pool_uuid
    }
}

impl HasName for StratPool {
    fn name(&self) -> &str {
        &self.name
    }
}

impl Recordable<PoolSave> for StratPool {
    fn record(&self) -> EngineResult<PoolSave> {

        let mapper = |seg: &Segment| -> EngineResult<(String, Sectors, Sectors)> {
            let bd = try!(self.block_devs
                     .get_by_device(seg.device)
                     .ok_or(EngineError::Engine(ErrorEnum::NotFound,
                                                format!("no block device found for device {:?}",
                                                        seg.device))));
            Ok((bd.uuid().simple().to_string(), seg.start, seg.length))
        };

        let mut meta_dev = vec![];
        for item in self.mdv.segments().iter().map(&mapper) {
            match item {
                Ok(seg) => meta_dev.push(seg),
                Err(err) => return Err(err),
            }
        }

        let mut thin_meta_dev = vec![];
        for item in self.thin_pool
                .meta_dev()
                .segments()
                .iter()
                .map(&mapper) {
            match item {
                Ok(seg) => thin_meta_dev.push(seg),
                Err(err) => return Err(err),
            }
        }

        let mut thin_data_dev = vec![];
        for item in self.thin_pool
                .data_dev()
                .segments()
                .iter()
                .map(&mapper) {
            match item {
                Ok(seg) => thin_data_dev.push(seg),
                Err(err) => return Err(err),
            }
        }

        Ok(PoolSave {
               name: self.name.clone(),
               block_devs: try!(self.block_devs.record()),
               flex_devs: FlexDevsSave {
                   meta_dev: meta_dev,
                   thin_meta_dev: thin_meta_dev,
                   thin_data_dev: thin_data_dev,
               },
               thinpool_dev: ThinPoolDevSave { data_block_size: *self.thin_pool.data_block_size() },
           })
    }
}
<commit_msg>update pool::uuid() to return a PoolUuid<commit_after>// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.

use std::collections::HashSet;
use std::collections::hash_map::RandomState;
use std::iter::FromIterator;
use std::path::Path;
use std::path::PathBuf;
use std::vec::Vec;

use devicemapper::consts::SECTOR_SIZE;
use devicemapper::DM;
use devicemapper::{DataBlocks, Sectors, Segment};
use devicemapper::LinearDev;
use devicemapper::{ThinPoolDev, ThinPoolStatus, ThinPoolWorkingStatus};
use time::now;
use uuid::Uuid;
use serde_json;

use super::super::consts::IEC::Mi;
use super::super::engine::{Filesystem, HasName, HasUuid, Pool};
use super::super::errors::{EngineError, EngineResult, ErrorEnum};
use super::super::structures::Table;
use super::super::types::{FilesystemUuid, PoolUuid, RenameAction, Redundancy};

use super::blockdevmgr::BlockDevMgr;
use super::device::wipe_sectors;
use super::dmdevice::{FlexRole, ThinPoolRole, format_flex_name, format_thinpool_name};
use super::filesystem::{StratFilesystem, FilesystemStatus};
use super::mdv::MetadataVol;
use super::metadata::MIN_MDA_SECTORS;
use super::serde_structs::{FlexDevsSave, PoolSave, Recordable, ThinPoolDevSave};

const DATA_BLOCK_SIZE: Sectors = Sectors(2048);
const META_LOWATER: u64 = 512;
const DATA_LOWATER: DataBlocks = DataBlocks(512);

const INITIAL_META_SIZE: Sectors = Sectors(16 * Mi / SECTOR_SIZE as u64);
const INITIAL_DATA_SIZE: Sectors = Sectors(512 * Mi / SECTOR_SIZE as u64);
const INITIAL_MDV_SIZE: Sectors = Sectors(16 * Mi / SECTOR_SIZE as u64);

#[derive(Debug)]
pub struct StratPool {
    name: String,
    pool_uuid: PoolUuid,
    pub block_devs: BlockDevMgr,
    pub filesystems: Table<StratFilesystem>,
    redundancy: Redundancy,
    thin_pool: ThinPoolDev,
    mdv: MetadataVol,
}

impl StratPool {
    /// Initialize a Stratis Pool.
    /// 1. Initialize the block devices specified by paths.
    /// 2. Set up thinpool device to back filesystems.
    pub fn initialize(name: &str,
                      dm: &DM,
                      paths: &[&Path],
                      redundancy: Redundancy,
                      force: bool)
                      -> EngineResult<StratPool> {
        let pool_uuid = Uuid::new_v4();

        let mut block_mgr =
            try!(BlockDevMgr::initialize(&pool_uuid, paths, MIN_MDA_SECTORS, force));

        if block_mgr.avail_space() < StratPool::min_initial_size() {
            let avail_size = block_mgr.avail_space().bytes();
            try!(block_mgr.destroy_all());
            return Err(EngineError::Engine(ErrorEnum::Invalid,
                                           format!("Space on pool must be at least {} bytes, \
                                                   available space is only {} bytes",
                                                   StratPool::min_initial_size().bytes(),
                                                   avail_size)));

        }

        let meta_regions = block_mgr
            .alloc_space(INITIAL_META_SIZE)
            .expect("blockmgr must not fail, already checked for space");
        let device_name = format_flex_name(&pool_uuid, FlexRole::ThinMeta);
        let meta_dev = try!(LinearDev::new(&device_name, dm, meta_regions));

        // When constructing a thin-pool, Stratis reserves the first N
        // sectors on a block device by creating a linear device with a
        // starting offset. DM writes the super block in the first block.
        // DM requires this first block to be zeros when the meta data for
        // the thin-pool is initially created. If we don't zero the
        // superblock DM issue error messages because it triggers code paths
        // that are trying to re-adopt the device with the attributes that
        // have been passed.
        try!(wipe_sectors(&try!(meta_dev.devnode()), Sectors(0), INITIAL_META_SIZE));

        let data_regions = block_mgr
            .alloc_space(INITIAL_DATA_SIZE)
            .expect("blockmgr must not fail, already checked for space");
        let device_name = format_flex_name(&pool_uuid, FlexRole::ThinData);
        let data_dev = try!(LinearDev::new(&device_name, dm, data_regions));
        let length = try!(data_dev.size());

        let device_name = format_thinpool_name(&pool_uuid, ThinPoolRole::Pool);
        // TODO Fix hard coded data blocksize and low water mark.
        let thinpool_dev = try!(ThinPoolDev::new(&device_name,
                                                 dm,
                                                 length,
                                                 DATA_BLOCK_SIZE,
                                                 DataBlocks(256000),
                                                 meta_dev,
                                                 data_dev));

        let mdv_regions = block_mgr
            .alloc_space(INITIAL_MDV_SIZE)
            .expect("blockmgr must not fail, already checked for space");
        let device_name = format_flex_name(&pool_uuid, FlexRole::MetadataVolume);
        let mdv_dev = try!(LinearDev::new(&device_name, dm, mdv_regions));
        let mdv = try!(MetadataVol::initialize(&pool_uuid, mdv_dev));

        let mut pool = StratPool {
            name: name.to_owned(),
            pool_uuid: pool_uuid,
            block_devs: block_mgr,
            filesystems: Table::new(),
            redundancy: redundancy,
            thin_pool: thinpool_dev,
            mdv: mdv,
        };

        try!(pool.write_metadata());

        Ok(pool)
    }

    /// Minimum initial size for a pool.
    pub fn min_initial_size() -> Sectors {
        INITIAL_META_SIZE + INITIAL_DATA_SIZE + INITIAL_MDV_SIZE
    }

    // TODO: Check current time against global last updated, and use
    // alternate time value if earlier, as described in SWDD
    fn write_metadata(&mut self) -> EngineResult<()> {
        let data = try!(serde_json::to_string(&try!(self.record())));
        self.block_devs
            .save_state(&now().to_timespec(), data.as_bytes())
    }

    pub fn check(&mut self) -> () {
        let dm = DM::new().expect("Could not get DM handle");

        if let Err(e) = self.mdv.check() {
            error!("MDV error: {}", e);
            return;
        }

        let result = match self.thin_pool.status(&dm) {
            Ok(r) => r,
            Err(_) => {
                error!("Could not get thinpool status");
                // TODO: Take pool offline?
                return;
            }
        };

        match result {
            ThinPoolStatus::Good(wstatus, usage) => {
                match wstatus {
                    ThinPoolWorkingStatus::Good => {}
                    ThinPoolWorkingStatus::ReadOnly => {
                        // TODO: why is pool r/o and how do we get it
                        // rw again?
                    }
                    ThinPoolWorkingStatus::OutOfSpace => {
                        // TODO: Add more space if possible, or
                        // prevent further usage
                        // Should never happen -- we should be extending first!
                    }
                    ThinPoolWorkingStatus::NeedsCheck => {
                        // TODO: Take pool offline?
                        // TODO: run thin_check
                    }
                }

                if usage.used_meta > usage.total_meta - META_LOWATER {
                    // TODO: Extend meta device
                }

                if usage.used_data > usage.total_data - DATA_LOWATER {
                    // TODO: Extend data device
                }
            }
            ThinPoolStatus::Fail => {
                // TODO: Take pool offline?
                // TODO: Run thin_check
            }
        }

        for fs in &mut self.filesystems {
            match fs.check(&dm) {
                Ok(f_status) => {
                    if let FilesystemStatus::Failed = f_status {
                        // TODO: recover fs? (how?)
                    }
                }
                Err(_e) => error!("fs.check() failed"),
            }
        }
    }

    /// Teardown a pool.
    /// Take down the device mapper devices belonging to the pool.
    /// This method and destroy() must keep their DM teardown operations
    /// in sync.
    pub fn teardown(self) -> EngineResult<()> {
        // TODO: any necessary clean up of filesystems
        if !self.filesystems.is_empty() {
            return Err(EngineError::Engine(ErrorEnum::Busy,
                                           format!("May be unsynced files on device.")));
        }
        let dm = try!(DM::new());
        try!(self.thin_pool.teardown(&dm));
        try!(self.mdv.teardown(&dm));
        Ok(())
    }
}

impl Pool for StratPool {
    fn create_filesystems<'a, 'b>(&'a mut self,
                                  specs: &[&'b str])
                                  -> EngineResult<Vec<(&'b str, FilesystemUuid)>> {
        let names: HashSet<_, RandomState> = HashSet::from_iter(specs);
        for name in names.iter() {
            if self.filesystems.contains_name(name) {
                return Err(EngineError::Engine(ErrorEnum::AlreadyExists, name.to_string()));
            }
        }

        // TODO: Roll back on filesystem initialization failure.
        let dm = try!(DM::new());
        let mut result = Vec::new();
        for name in names.iter() {
            let uuid = Uuid::new_v4();
            let new_filesystem = try!(StratFilesystem::initialize(&self.pool_uuid,
                                                                  uuid,
                                                                  name,
                                                                  &dm,
                                                                  &mut self.thin_pool));
            try!(self.mdv.save_fs(&new_filesystem));
            self.filesystems.insert(new_filesystem);
            result.push((**name, uuid));
        }

        Ok(result)
    }

    fn add_blockdevs(&mut self, paths: &[&Path], force: bool) -> EngineResult<Vec<PathBuf>> {
        let bdev_paths = try!(self.block_devs.add(&self.pool_uuid, paths, force));
        try!(self.write_metadata());
        Ok(bdev_paths)
    }

    fn destroy(self) -> EngineResult<()> {
        // Ensure that DM teardown operations in this method are in sync
        // with operations in teardown().
        let dm = try!(DM::new());
        try!(self.thin_pool.teardown(&dm));
        try!(self.mdv.teardown(&dm));
        try!(self.block_devs.destroy_all());

        Ok(())
    }

    fn destroy_filesystems<'a, 'b>(&'a mut self,
                                   fs_uuids: &[&'b FilesystemUuid])
                                   -> EngineResult<Vec<&'b FilesystemUuid>> {
        for fsid in fs_uuids {
            try!(self.mdv.rm_fs(fsid));
        }
        destroy_filesystems!{self; fs_uuids}
    }

    fn rename_filesystem(&mut self,
                         uuid: &FilesystemUuid,
                         new_name: &str)
                         -> EngineResult<RenameAction> {
        rename_filesystem!{self; uuid; new_name}
    }

    fn rename(&mut self, name: &str) {
        self.name = name.to_owned();
    }

    fn get_filesystem(&mut self, uuid: &FilesystemUuid) -> Option<&mut Filesystem> {
        get_filesystem!(self; uuid)
    }
}

impl HasUuid for StratPool {
    fn uuid(&self) -> &PoolUuid {
        &self.pool_uuid
    }
}

impl HasName for StratPool {
    fn name(&self) -> &str {
        &self.name
    }
}

impl Recordable<PoolSave> for StratPool {
    fn record(&self) -> EngineResult<PoolSave> {

        let mapper = |seg: &Segment| -> EngineResult<(String, Sectors, Sectors)> {
            let bd = try!(self.block_devs
                     .get_by_device(seg.device)
                     .ok_or(EngineError::Engine(ErrorEnum::NotFound,
                                                format!("no block device found for device {:?}",
                                                        seg.device))));
            Ok((bd.uuid().simple().to_string(), seg.start, seg.length))
        };

        let mut meta_dev = vec![];
        for item in self.mdv.segments().iter().map(&mapper) {
            match item {
                Ok(seg) => meta_dev.push(seg),
                Err(err) => return Err(err),
            }
        }

        let mut thin_meta_dev = vec![];
        for item in self.thin_pool
                .meta_dev()
                .segments()
                .iter()
                .map(&mapper) {
            match item {
                Ok(seg) => thin_meta_dev.push(seg),
                Err(err) => return Err(err),
            }
        }

        let mut thin_data_dev = vec![];
        for item in self.thin_pool
                .data_dev()
                .segments()
                .iter()
                .map(&mapper) {
            match item {
                Ok(seg) => thin_data_dev.push(seg),
                Err(err) => return Err(err),
            }
        }

        Ok(PoolSave {
               name: self.name.clone(),
               block_devs: try!(self.block_devs.record()),
               flex_devs: FlexDevsSave {
                   meta_dev: meta_dev,
                   thin_meta_dev: thin_meta_dev,
                   thin_data_dev: thin_data_dev,
               },
               thinpool_dev: ThinPoolDevSave { data_block_size: *self.thin_pool.data_block_size() },
           })
    }
}
<|endoftext|>


<commit_before>// Copyright 2014 The Gfx-rs Developers.
//
// 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.
#![feature(plugin_registrar, quote, box_syntax)]
#![deny(missing_copy_implementations)]
#![allow(unstable)]

//! Macro extensions crate.
//! Implements `shaders!` macro as well as `#[shader_param]` and
//! `#[vertex_format]` attributes.

extern crate rustc;
extern crate syntax;

use syntax::{ast, attr, ext, codemap};
use syntax::ext::build::AstBuilder;
use syntax::parse::token;
use syntax::fold::Folder;
use syntax::ptr::P;

pub mod shader_param;
pub mod vertex_format;

/// Entry point for the plugin phase
#[plugin_registrar]
pub fn registrar(reg: &mut rustc::plugin::Registry) {
    use syntax::parse::token::intern;
    use syntax::ext::base;
    // Register the `#[shader_param]` attribute.
    reg.register_syntax_extension(intern("shader_param"),
        base::Decorator(box shader_param::ShaderParam));
    // Register the `#[vertex_format]` attribute.
    reg.register_syntax_extension(intern("vertex_format"),
        base::Decorator(box vertex_format::VertexFormat));
}

/// Scan through the field's attributes and extract the field vertex name. If
/// multiple names are found, use the first name and emit a warning.
fn find_name(cx: &mut ext::base::ExtCtxt, span: codemap::Span,
             attributes: &[ast::Attribute]) -> Option<token::InternedString> {
    attributes.iter().fold(None, |name, attribute| {
        match attribute.node.value.node {
            ast::MetaNameValue(ref attr_name, ref attr_value) => {
                match (attr_name.get(), &attr_value.node) {
                    ("name", &ast::LitStr(ref new_name, _)) => {
                        attr::mark_used(attribute);
                        name.map_or(Some(new_name.clone()), |name| {
                            cx.span_warn(span, &format!(
                                "Extra field name detected: {:?} - \
                                ignoring in favour of: {:?}", new_name, name
                            )[]);
                            None
                        })
                    }
                    _ => None,
                }
            }
            _ => name,
        }
    })
}

/// Marker string to base the unique identifier generated by `extern_crate_hack()` on
static EXTERN_CRATE_HACK: &'static str = "__gfx_extern_crate_hack";

/// Inserts a module with a unique identifier that reexports
/// The `gfx` crate, and returns that identifier
fn extern_crate_hack<F>(context: &mut ext::base::ExtCtxt,
                        span: codemap::Span,
                        mut push: F) -> ast::Ident where F: FnMut(P<ast::Item>) {
    let extern_crate_hack = token::gensym_ident(EXTERN_CRATE_HACK);
    // mod $EXTERN_CRATE_HACK {
    //     extern crate gfx_ = "gfx";
    //     pub use gfx_ as gfx;
    // }
    let item = context.item_mod(
        span,
        span,
        extern_crate_hack,
        vec![],
        vec![
            P(ast::Item {
                span: span,
                vis: ast::Inherited,
                attrs: vec![],
                node: ast::ItemExternCrate(
                    Some((
                        token::InternedString::new("gfx"),
                        ast::CookedStr
                    )),
                ),
                id: ast::DUMMY_NODE_ID,
                ident: token::str_to_ident("gfx_")
            }),
            context.item_use_simple_(
                span,
                ast::Public,
                context.ident_of("gfx"),
                context.path(span, vec![
                    context.ident_of("self"),
                    context.ident_of("gfx_")
                ])
            )
        ]
    );
    push(item);
    extern_crate_hack
}

/// This Folder gets used to fixup all paths generated by the
/// #[derive trait impl to point to the unique module
/// containing the `gfx` reexport.
struct ExternCrateHackFolder {
    path_root: ast::Ident
}

impl Folder for ExternCrateHackFolder {
    fn fold_path(&mut self, p: ast::Path) -> ast::Path {
        let p = syntax::fold::noop_fold_path(p, self);
        let needs_fix = (&p.segments[]).get(0)
                         .map(|s| s.identifier.as_str() == EXTERN_CRATE_HACK)
                         .unwrap_or(false);
        let needs_fix_self = (&p.segments[]).get(0)
                              .map(|s| s.identifier.as_str() == "self")
                              .unwrap_or(false) &&
                             (&p.segments[]).get(1)
                              .map(|s| s.identifier.as_str() == EXTERN_CRATE_HACK)
                              .unwrap_or(false);

        if needs_fix {
            let mut p = p.clone();
            p.segments[0].identifier = self.path_root;
            p.global = false;
            p
        } else if needs_fix_self {
            let mut p = p.clone();
            p.segments[1].identifier = self.path_root;
            p.global = false;
            p
        } else {
            p
        }

    }
}

/// Simply applies the `ExternCrateHackFolder`
fn fixup_extern_crate_paths(item: P<ast::Item>, path_root: ast::Ident) -> P<ast::Item> {
    ExternCrateHackFolder {
        path_root: path_root
    }.fold_item(item).into_iter().next().unwrap()
}

// The `gfx` reexport module here does not need a unique name,
// as it gets inserted in a new block and thus doesn't conflict with
// any names outside its lexical scope.
#[macro_export]
macro_rules! shaders {
    (targets : $v:expr) => {
        {
            use gfx;
            gfx::ShaderSource {
                targets: $v,
                ..shaders!()
            }
        }
    };
    (targets : $v:expr, $($t:tt)*) => {
        {
            use gfx;
            gfx::ShaderSource {
                targets: $v,
                ..shaders!($($t)*)
            }
        }
    };
    ($i:ident : $v:expr) => {
        {
            use gfx;
            gfx::ShaderSource {
                $i: Some($v),
                ..shaders!()
            }
        }
    };
    ($i:ident : $v:expr, $($t:tt)*) => {
        {
            use gfx;
            gfx::ShaderSource {
                $i: Some($v),
                ..shaders!($($t)*)
            }
        }
    };
    () => {
        {
            use gfx;
            gfx::ShaderSource {
                glsl_120: None,
                glsl_130: None,
                glsl_140: None,
                glsl_150: None,
                targets: &[],
            }
        }
    }
}
<commit_msg>Silenced warnings in gfx_macros, related to unstable rust items<commit_after>// Copyright 2014 The Gfx-rs Developers.
//
// 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.
#![feature(core, plugin_registrar, quote, box_syntax, rustc_private)]
#![deny(missing_copy_implementations)]

//! Macro extensions crate.
//! Implements `shaders!` macro as well as `#[shader_param]` and
//! `#[vertex_format]` attributes.

extern crate rustc;
extern crate syntax;

use syntax::{ast, attr, ext, codemap};
use syntax::ext::build::AstBuilder;
use syntax::parse::token;
use syntax::fold::Folder;
use syntax::ptr::P;

pub mod shader_param;
pub mod vertex_format;

/// Entry point for the plugin phase
#[plugin_registrar]
pub fn registrar(reg: &mut rustc::plugin::Registry) {
    use syntax::parse::token::intern;
    use syntax::ext::base;
    // Register the `#[shader_param]` attribute.
    reg.register_syntax_extension(intern("shader_param"),
        base::Decorator(box shader_param::ShaderParam));
    // Register the `#[vertex_format]` attribute.
    reg.register_syntax_extension(intern("vertex_format"),
        base::Decorator(box vertex_format::VertexFormat));
}

/// Scan through the field's attributes and extract the field vertex name. If
/// multiple names are found, use the first name and emit a warning.
fn find_name(cx: &mut ext::base::ExtCtxt, span: codemap::Span,
             attributes: &[ast::Attribute]) -> Option<token::InternedString> {
    attributes.iter().fold(None, |name, attribute| {
        match attribute.node.value.node {
            ast::MetaNameValue(ref attr_name, ref attr_value) => {
                match (attr_name.get(), &attr_value.node) {
                    ("name", &ast::LitStr(ref new_name, _)) => {
                        attr::mark_used(attribute);
                        name.map_or(Some(new_name.clone()), |name| {
                            cx.span_warn(span, &format!(
                                "Extra field name detected: {:?} - \
                                ignoring in favour of: {:?}", new_name, name
                            )[]);
                            None
                        })
                    }
                    _ => None,
                }
            }
            _ => name,
        }
    })
}

/// Marker string to base the unique identifier generated by `extern_crate_hack()` on
static EXTERN_CRATE_HACK: &'static str = "__gfx_extern_crate_hack";

/// Inserts a module with a unique identifier that reexports
/// The `gfx` crate, and returns that identifier
fn extern_crate_hack<F>(context: &mut ext::base::ExtCtxt,
                        span: codemap::Span,
                        mut push: F) -> ast::Ident where F: FnMut(P<ast::Item>) {
    let extern_crate_hack = token::gensym_ident(EXTERN_CRATE_HACK);
    // mod $EXTERN_CRATE_HACK {
    //     extern crate gfx_ = "gfx";
    //     pub use gfx_ as gfx;
    // }
    let item = context.item_mod(
        span,
        span,
        extern_crate_hack,
        vec![],
        vec![
            P(ast::Item {
                span: span,
                vis: ast::Inherited,
                attrs: vec![],
                node: ast::ItemExternCrate(
                    Some((
                        token::InternedString::new("gfx"),
                        ast::CookedStr
                    )),
                ),
                id: ast::DUMMY_NODE_ID,
                ident: token::str_to_ident("gfx_")
            }),
            context.item_use_simple_(
                span,
                ast::Public,
                context.ident_of("gfx"),
                context.path(span, vec![
                    context.ident_of("self"),
                    context.ident_of("gfx_")
                ])
            )
        ]
    );
    push(item);
    extern_crate_hack
}

/// This Folder gets used to fixup all paths generated by the
/// #[derive trait impl to point to the unique module
/// containing the `gfx` reexport.
struct ExternCrateHackFolder {
    path_root: ast::Ident
}

impl Folder for ExternCrateHackFolder {
    fn fold_path(&mut self, p: ast::Path) -> ast::Path {
        let p = syntax::fold::noop_fold_path(p, self);
        let needs_fix = (&p.segments[]).get(0)
                         .map(|s| s.identifier.as_str() == EXTERN_CRATE_HACK)
                         .unwrap_or(false);
        let needs_fix_self = (&p.segments[]).get(0)
                              .map(|s| s.identifier.as_str() == "self")
                              .unwrap_or(false) &&
                             (&p.segments[]).get(1)
                              .map(|s| s.identifier.as_str() == EXTERN_CRATE_HACK)
                              .unwrap_or(false);

        if needs_fix {
            let mut p = p.clone();
            p.segments[0].identifier = self.path_root;
            p.global = false;
            p
        } else if needs_fix_self {
            let mut p = p.clone();
            p.segments[1].identifier = self.path_root;
            p.global = false;
            p
        } else {
            p
        }

    }
}

/// Simply applies the `ExternCrateHackFolder`
fn fixup_extern_crate_paths(item: P<ast::Item>, path_root: ast::Ident) -> P<ast::Item> {
    ExternCrateHackFolder {
        path_root: path_root
    }.fold_item(item).into_iter().next().unwrap()
}

// The `gfx` reexport module here does not need a unique name,
// as it gets inserted in a new block and thus doesn't conflict with
// any names outside its lexical scope.
#[macro_export]
macro_rules! shaders {
    (targets : $v:expr) => {
        {
            use gfx;
            gfx::ShaderSource {
                targets: $v,
                ..shaders!()
            }
        }
    };
    (targets : $v:expr, $($t:tt)*) => {
        {
            use gfx;
            gfx::ShaderSource {
                targets: $v,
                ..shaders!($($t)*)
            }
        }
    };
    ($i:ident : $v:expr) => {
        {
            use gfx;
            gfx::ShaderSource {
                $i: Some($v),
                ..shaders!()
            }
        }
    };
    ($i:ident : $v:expr, $($t:tt)*) => {
        {
            use gfx;
            gfx::ShaderSource {
                $i: Some($v),
                ..shaders!($($t)*)
            }
        }
    };
    () => {
        {
            use gfx;
            gfx::ShaderSource {
                glsl_120: None,
                glsl_130: None,
                glsl_140: None,
                glsl_150: None,
                targets: &[],
            }
        }
    }
}
<|endoftext|>


<commit_before><commit_msg>entry<commit_after><|endoftext|>