<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 std::uint;

pub struct Graph<N,E> {
    nodes: Vec<Node<N>> ,
    edges: Vec<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,
}

#[deriving(Eq)]
pub struct NodeIndex(uint);
pub static InvalidNodeIndex: NodeIndex = NodeIndex(uint::MAX);

#[deriving(Eq)]
pub struct EdgeIndex(uint);
pub static InvalidEdgeIndex: EdgeIndex = EdgeIndex(uint::MAX);

// Use a private field here to guarantee no more instances are created:
pub struct Direction { repr: uint }
pub static Outgoing: Direction = Direction { repr: 0 };
pub static Incoming: Direction = Direction { repr: 1 };

impl NodeIndex {
    fn get(&self) -> uint { let NodeIndex(v) = *self; v }
}

impl EdgeIndex {
    fn get(&self) -> uint { let EdgeIndex(v) = *self; v }
}

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

    pub fn with_capacity(num_nodes: uint,
                         num_edges: uint) -> Graph<N,E> {
        Graph {
            nodes: Vec::with_capacity(num_nodes),
            edges: Vec::with_capacity(num_edges),
        }
    }

    ///////////////////////////////////////////////////////////////////////////
    // Simple accessors

    #[inline]
    pub fn all_nodes<'a>(&'a self) -> &'a [Node<N>] {
        let nodes: &'a [Node<N>] = self.nodes.as_slice();
        nodes
    }

    #[inline]
    pub fn all_edges<'a>(&'a self) -> &'a [Edge<E>] {
        let edges: &'a [Edge<E>] = self.edges.as_slice();
        edges
    }

    ///////////////////////////////////////////////////////////////////////////
    // 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: [InvalidEdgeIndex, InvalidEdgeIndex],
            data: data
        });
        idx
    }

    pub fn mut_node_data<'a>(&'a mut self, idx: NodeIndex) -> &'a mut N {
        &mut self.nodes.get_mut(idx.get()).data
    }

    pub fn node_data<'a>(&'a self, idx: NodeIndex) -> &'a N {
        &self.nodes.get(idx.get()).data
    }

    pub fn node<'a>(&'a self, idx: NodeIndex) -> &'a Node<N> {
        self.nodes.get(idx.get())
    }

    ///////////////////////////////////////////////////////////////////////////
    // 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 {
        let idx = self.next_edge_index();

        // read current first of the list of edges from each node
        let source_first = self.nodes.get(source.get())
                                     .first_edge[Outgoing.repr];
        let target_first = self.nodes.get(target.get())
                                     .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.get_mut(source.get()).first_edge[Outgoing.repr] = idx;
        self.nodes.get_mut(target.get()).first_edge[Incoming.repr] = idx;

        return idx;
    }

    pub fn mut_edge_data<'a>(&'a mut self, idx: EdgeIndex) -> &'a mut E {
        &mut self.edges.get_mut(idx.get()).data
    }

    pub fn edge_data<'a>(&'a self, idx: EdgeIndex) -> &'a E {
        &self.edges.get(idx.get()).data
    }

    pub fn edge<'a>(&'a self, idx: EdgeIndex) -> &'a Edge<E> {
        self.edges.get(idx.get())
    }

    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.get(node.get()).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.get(edge.get()).next_edge[dir.repr]
    }

    ///////////////////////////////////////////////////////////////////////////
    // Iterating over nodes, edges

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

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

    pub fn each_outgoing_edge(&self,
                              source: NodeIndex,
                              f: |EdgeIndex, &Edge<E>| -> bool)
                              -> bool {
        //! Iterates over all outgoing edges from the node `from`

        self.each_adjacent_edge(source, Outgoing, f)
    }

    pub fn each_incoming_edge(&self,
                              target: NodeIndex,
                              f: |EdgeIndex, &Edge<E>| -> bool)
                              -> bool {
        //! Iterates over all incoming edges to the node `target`

        self.each_adjacent_edge(target, Incoming, f)
    }

    pub fn each_adjacent_edge(&self,
                              node: NodeIndex,
                              dir: Direction,
                              f: |EdgeIndex, &Edge<E>| -> bool)
                              -> bool {
        //! Iterates over all edges adjacent to the node `node`
        //! in the direction `dir` (either `Outgoing` or `Incoming)

        let mut edge_idx = self.first_adjacent(node, dir);
        while edge_idx != InvalidEdgeIndex {
            let edge = self.edges.get(edge_idx.get());
            if !f(edge_idx, edge) {
                return false;
            }
            edge_idx = edge.next_edge[dir.repr];
        }
        return true;
    }

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

    pub fn iterate_until_fixed_point(&self,
                                     op: |iter_index: uint,
                                          edge_index: EdgeIndex,
                                          edge: &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 each_edge_index(max_edge_index: EdgeIndex, f: |EdgeIndex| -> bool) {
    let mut i = 0;
    let n = max_edge_index.get();
    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
    }
}

#[cfg(test)]
mod test {
    use middle::graph::*;

    type TestNode = Node<&'static str>;
    type TestEdge = Edge<&'static str>;
    type TestGraph = Graph<&'static str, &'static str>;

    fn create_graph() -> TestGraph {
        let mut graph = Graph::new();

        // Create a simple graph
        //
        //    A -+> B --> C
        //       |  |     ^
        //       |  v     |
        //       F  D --> E

        let a = graph.add_node("A");
        let b = graph.add_node("B");
        let c = graph.add_node("C");
        let d = graph.add_node("D");
        let e = graph.add_node("E");
        let f = graph.add_node("F");

        graph.add_edge(a, b, "AB");
        graph.add_edge(b, c, "BC");
        graph.add_edge(b, d, "BD");
        graph.add_edge(d, e, "DE");
        graph.add_edge(e, c, "EC");
        graph.add_edge(f, b, "FB");

        return graph;
    }

    #[test]
    fn each_node() {
        let graph = create_graph();
        let expected = ["A", "B", "C", "D", "E", "F"];
        graph.each_node(|idx, node| {
            assert_eq!(&expected[idx.get()], graph.node_data(idx));
            assert_eq!(expected[idx.get()], node.data);
            true
        });
    }

    #[test]
    fn each_edge() {
        let graph = create_graph();
        let expected = ["AB", "BC", "BD", "DE", "EC", "FB"];
        graph.each_edge(|idx, edge| {
            assert_eq!(&expected[idx.get()], graph.edge_data(idx));
            assert_eq!(expected[idx.get()], edge.data);
            true
        });
    }

    fn test_adjacent_edges<N:Eq,E:Eq>(graph: &Graph<N,E>,
                                      start_index: NodeIndex,
                                      start_data: N,
                                      expected_incoming: &[(E,N)],
                                      expected_outgoing: &[(E,N)]) {
        assert!(graph.node_data(start_index) == &start_data);

        let mut counter = 0;
        graph.each_incoming_edge(start_index, |edge_index, edge| {
            assert!(graph.edge_data(edge_index) == &edge.data);
            assert!(counter < expected_incoming.len());
            debug!("counter={:?} expected={:?} edge_index={:?} edge={:?}",
                   counter, expected_incoming[counter], edge_index, edge);
            match expected_incoming[counter] {
                (ref e, ref n) => {
                    assert!(e == &edge.data);
                    assert!(n == graph.node_data(edge.source));
                    assert!(start_index == edge.target);
                }
            }
            counter += 1;
            true
        });
        assert_eq!(counter, expected_incoming.len());

        let mut counter = 0;
        graph.each_outgoing_edge(start_index, |edge_index, edge| {
            assert!(graph.edge_data(edge_index) == &edge.data);
            assert!(counter < expected_outgoing.len());
            debug!("counter={:?} expected={:?} edge_index={:?} edge={:?}",
                   counter, expected_outgoing[counter], edge_index, edge);
            match expected_outgoing[counter] {
                (ref e, ref n) => {
                    assert!(e == &edge.data);
                    assert!(start_index == edge.source);
                    assert!(n == graph.node_data(edge.target));
                }
            }
            counter += 1;
            true
        });
        assert_eq!(counter, expected_outgoing.len());
    }

    #[test]
    fn each_adjacent_from_a() {
        let graph = create_graph();
        test_adjacent_edges(&graph, NodeIndex(0), "A",
                            [],
                            [("AB", "B")]);
    }

    #[test]
    fn each_adjacent_from_b() {
        let graph = create_graph();
        test_adjacent_edges(&graph, NodeIndex(1), "B",
                            [("FB", "F"), ("AB", "A"),],
                            [("BD", "D"), ("BC", "C"),]);
    }

    #[test]
    fn each_adjacent_from_c() {
        let graph = create_graph();
        test_adjacent_edges(&graph, NodeIndex(2), "C",
                            [("EC", "E"), ("BC", "B")],
                            []);
    }

    #[test]
    fn each_adjacent_from_d() {
        let graph = create_graph();
        test_adjacent_edges(&graph, NodeIndex(3), "D",
                            [("BD", "B")],
                            [("DE", "E")]);
    }
}
<commit_msg>middle: graph: ignore dead code<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`).

*/

#![allow(dead_code)] // still WIP

use std::uint;

pub struct Graph<N,E> {
    nodes: Vec<Node<N>> ,
    edges: Vec<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,
}

#[deriving(Eq)]
pub struct NodeIndex(uint);
pub static InvalidNodeIndex: NodeIndex = NodeIndex(uint::MAX);

#[deriving(Eq)]
pub struct EdgeIndex(uint);
pub static InvalidEdgeIndex: EdgeIndex = EdgeIndex(uint::MAX);

// Use a private field here to guarantee no more instances are created:
pub struct Direction { repr: uint }
pub static Outgoing: Direction = Direction { repr: 0 };
pub static Incoming: Direction = Direction { repr: 1 };

impl NodeIndex {
    fn get(&self) -> uint { let NodeIndex(v) = *self; v }
}

impl EdgeIndex {
    fn get(&self) -> uint { let EdgeIndex(v) = *self; v }
}

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

    pub fn with_capacity(num_nodes: uint,
                         num_edges: uint) -> Graph<N,E> {
        Graph {
            nodes: Vec::with_capacity(num_nodes),
            edges: Vec::with_capacity(num_edges),
        }
    }

    ///////////////////////////////////////////////////////////////////////////
    // Simple accessors

    #[inline]
    pub fn all_nodes<'a>(&'a self) -> &'a [Node<N>] {
        let nodes: &'a [Node<N>] = self.nodes.as_slice();
        nodes
    }

    #[inline]
    pub fn all_edges<'a>(&'a self) -> &'a [Edge<E>] {
        let edges: &'a [Edge<E>] = self.edges.as_slice();
        edges
    }

    ///////////////////////////////////////////////////////////////////////////
    // 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: [InvalidEdgeIndex, InvalidEdgeIndex],
            data: data
        });
        idx
    }

    pub fn mut_node_data<'a>(&'a mut self, idx: NodeIndex) -> &'a mut N {
        &mut self.nodes.get_mut(idx.get()).data
    }

    pub fn node_data<'a>(&'a self, idx: NodeIndex) -> &'a N {
        &self.nodes.get(idx.get()).data
    }

    pub fn node<'a>(&'a self, idx: NodeIndex) -> &'a Node<N> {
        self.nodes.get(idx.get())
    }

    ///////////////////////////////////////////////////////////////////////////
    // 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 {
        let idx = self.next_edge_index();

        // read current first of the list of edges from each node
        let source_first = self.nodes.get(source.get())
                                     .first_edge[Outgoing.repr];
        let target_first = self.nodes.get(target.get())
                                     .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.get_mut(source.get()).first_edge[Outgoing.repr] = idx;
        self.nodes.get_mut(target.get()).first_edge[Incoming.repr] = idx;

        return idx;
    }

    pub fn mut_edge_data<'a>(&'a mut self, idx: EdgeIndex) -> &'a mut E {
        &mut self.edges.get_mut(idx.get()).data
    }

    pub fn edge_data<'a>(&'a self, idx: EdgeIndex) -> &'a E {
        &self.edges.get(idx.get()).data
    }

    pub fn edge<'a>(&'a self, idx: EdgeIndex) -> &'a Edge<E> {
        self.edges.get(idx.get())
    }

    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.get(node.get()).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.get(edge.get()).next_edge[dir.repr]
    }

    ///////////////////////////////////////////////////////////////////////////
    // Iterating over nodes, edges

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

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

    pub fn each_outgoing_edge(&self,
                              source: NodeIndex,
                              f: |EdgeIndex, &Edge<E>| -> bool)
                              -> bool {
        //! Iterates over all outgoing edges from the node `from`

        self.each_adjacent_edge(source, Outgoing, f)
    }

    pub fn each_incoming_edge(&self,
                              target: NodeIndex,
                              f: |EdgeIndex, &Edge<E>| -> bool)
                              -> bool {
        //! Iterates over all incoming edges to the node `target`

        self.each_adjacent_edge(target, Incoming, f)
    }

    pub fn each_adjacent_edge(&self,
                              node: NodeIndex,
                              dir: Direction,
                              f: |EdgeIndex, &Edge<E>| -> bool)
                              -> bool {
        //! Iterates over all edges adjacent to the node `node`
        //! in the direction `dir` (either `Outgoing` or `Incoming)

        let mut edge_idx = self.first_adjacent(node, dir);
        while edge_idx != InvalidEdgeIndex {
            let edge = self.edges.get(edge_idx.get());
            if !f(edge_idx, edge) {
                return false;
            }
            edge_idx = edge.next_edge[dir.repr];
        }
        return true;
    }

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

    pub fn iterate_until_fixed_point(&self,
                                     op: |iter_index: uint,
                                          edge_index: EdgeIndex,
                                          edge: &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 each_edge_index(max_edge_index: EdgeIndex, f: |EdgeIndex| -> bool) {
    let mut i = 0;
    let n = max_edge_index.get();
    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
    }
}

#[cfg(test)]
mod test {
    use middle::graph::*;

    type TestNode = Node<&'static str>;
    type TestEdge = Edge<&'static str>;
    type TestGraph = Graph<&'static str, &'static str>;

    fn create_graph() -> TestGraph {
        let mut graph = Graph::new();

        // Create a simple graph
        //
        //    A -+> B --> C
        //       |  |     ^
        //       |  v     |
        //       F  D --> E

        let a = graph.add_node("A");
        let b = graph.add_node("B");
        let c = graph.add_node("C");
        let d = graph.add_node("D");
        let e = graph.add_node("E");
        let f = graph.add_node("F");

        graph.add_edge(a, b, "AB");
        graph.add_edge(b, c, "BC");
        graph.add_edge(b, d, "BD");
        graph.add_edge(d, e, "DE");
        graph.add_edge(e, c, "EC");
        graph.add_edge(f, b, "FB");

        return graph;
    }

    #[test]
    fn each_node() {
        let graph = create_graph();
        let expected = ["A", "B", "C", "D", "E", "F"];
        graph.each_node(|idx, node| {
            assert_eq!(&expected[idx.get()], graph.node_data(idx));
            assert_eq!(expected[idx.get()], node.data);
            true
        });
    }

    #[test]
    fn each_edge() {
        let graph = create_graph();
        let expected = ["AB", "BC", "BD", "DE", "EC", "FB"];
        graph.each_edge(|idx, edge| {
            assert_eq!(&expected[idx.get()], graph.edge_data(idx));
            assert_eq!(expected[idx.get()], edge.data);
            true
        });
    }

    fn test_adjacent_edges<N:Eq,E:Eq>(graph: &Graph<N,E>,
                                      start_index: NodeIndex,
                                      start_data: N,
                                      expected_incoming: &[(E,N)],
                                      expected_outgoing: &[(E,N)]) {
        assert!(graph.node_data(start_index) == &start_data);

        let mut counter = 0;
        graph.each_incoming_edge(start_index, |edge_index, edge| {
            assert!(graph.edge_data(edge_index) == &edge.data);
            assert!(counter < expected_incoming.len());
            debug!("counter={:?} expected={:?} edge_index={:?} edge={:?}",
                   counter, expected_incoming[counter], edge_index, edge);
            match expected_incoming[counter] {
                (ref e, ref n) => {
                    assert!(e == &edge.data);
                    assert!(n == graph.node_data(edge.source));
                    assert!(start_index == edge.target);
                }
            }
            counter += 1;
            true
        });
        assert_eq!(counter, expected_incoming.len());

        let mut counter = 0;
        graph.each_outgoing_edge(start_index, |edge_index, edge| {
            assert!(graph.edge_data(edge_index) == &edge.data);
            assert!(counter < expected_outgoing.len());
            debug!("counter={:?} expected={:?} edge_index={:?} edge={:?}",
                   counter, expected_outgoing[counter], edge_index, edge);
            match expected_outgoing[counter] {
                (ref e, ref n) => {
                    assert!(e == &edge.data);
                    assert!(start_index == edge.source);
                    assert!(n == graph.node_data(edge.target));
                }
            }
            counter += 1;
            true
        });
        assert_eq!(counter, expected_outgoing.len());
    }

    #[test]
    fn each_adjacent_from_a() {
        let graph = create_graph();
        test_adjacent_edges(&graph, NodeIndex(0), "A",
                            [],
                            [("AB", "B")]);
    }

    #[test]
    fn each_adjacent_from_b() {
        let graph = create_graph();
        test_adjacent_edges(&graph, NodeIndex(1), "B",
                            [("FB", "F"), ("AB", "A"),],
                            [("BD", "D"), ("BC", "C"),]);
    }

    #[test]
    fn each_adjacent_from_c() {
        let graph = create_graph();
        test_adjacent_edges(&graph, NodeIndex(2), "C",
                            [("EC", "E"), ("BC", "B")],
                            []);
    }

    #[test]
    fn each_adjacent_from_d() {
        let graph = create_graph();
        test_adjacent_edges(&graph, NodeIndex(3), "D",
                            [("BD", "B")],
                            [("DE", "E")]);
    }
}
<|endoftext|>


<commit_before>use crate::ptr;
use crate::sys_common::alloc::{MIN_ALIGN, realloc_fallback};
use crate::alloc::{GlobalAlloc, Layout, System};
use crate::mem;

#[stable(feature = "alloc_system_type", since = "1.28.0")]
unsafe impl GlobalAlloc for System {
    #[inline]
    unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
        // jemalloc provides alignment less than MIN_ALIGN for small allocations.
        // So only rely on MIN_ALIGN if size >= align.
        // Also see <https://github.com/rust-lang/rust/issues/45955> and
        // <https://github.com/rust-lang/rust/issues/62251#issuecomment-507580914>.
        if layout.align() <= MIN_ALIGN && layout.align() <= layout.size() {
            libc::malloc(layout.size()) as *mut u8
        } else {
            #[cfg(target_os = "macos")]
            {
                if layout.align() > (1 << 31) {
                    return ptr::null_mut()
                }
            }
            aligned_malloc(&layout)
        }
    }

    #[inline]
    unsafe fn alloc_zeroed(&self, layout: Layout) -> *mut u8 {
        // See the comment above in `alloc` for why this check looks the way it does.
        if layout.align() <= MIN_ALIGN && layout.align() <= layout.size() {
            libc::calloc(layout.size(), 1) as *mut u8
        } else {
            let ptr = self.alloc(layout.clone());
            if !ptr.is_null() {
                ptr::write_bytes(ptr, 0, layout.size());
            }
            ptr
        }
    }

    #[inline]
    unsafe fn dealloc(&self, ptr: *mut u8, _layout: Layout) {
        libc::free(ptr as *mut libc::c_void)
    }

    #[inline]
    unsafe fn realloc(&self, ptr: *mut u8, layout: Layout, new_size: usize) -> *mut u8 {
        if layout.align() <= MIN_ALIGN && layout.align() <= new_size {
            libc::realloc(ptr as *mut libc::c_void, new_size) as *mut u8
        } else {
            realloc_fallback(self, ptr, layout, new_size)
        }
    }
}

#[cfg(any(target_os = "android",
          target_os = "hermit",
          target_os = "redox",
          target_os = "solaris"))]
#[inline]
unsafe fn aligned_malloc(layout: &Layout) -> *mut u8 {
    // On android we currently target API level 9 which unfortunately
    // doesn't have the `posix_memalign` API used below. Instead we use
    // `memalign`, but this unfortunately has the property on some systems
    // where the memory returned cannot be deallocated by `free`!
    //
    // Upon closer inspection, however, this appears to work just fine with
    // Android, so for this platform we should be fine to call `memalign`
    // (which is present in API level 9). Some helpful references could
    // possibly be chromium using memalign [1], attempts at documenting that
    // memalign + free is ok [2] [3], or the current source of chromium
    // which still uses memalign on android [4].
    //
    // [1]: https://codereview.chromium.org/10796020/
    // [2]: https://code.google.com/p/android/issues/detail?id=35391
    // [3]: https://bugs.chromium.org/p/chromium/issues/detail?id=138579
    // [4]: https://chromium.googlesource.com/chromium/src/base/+/master/
    //                                       /memory/aligned_memory.cc
    libc::memalign(layout.align(), layout.size()) as *mut u8
}

#[cfg(not(any(target_os = "android",
              target_os = "hermit",
              target_os = "redox",
              target_os = "solaris")))]
#[inline]
unsafe fn aligned_malloc(layout: &Layout) -> *mut u8 {
    let mut out = ptr::null_mut();
    // posix_memalign requires that the alignment be a multiple of `sizeof(void*)`.
    // Since these are all powers of 2, we can just use max.
    let align = layout.align().max(mem::size_of::<usize>());
    let ret = libc::posix_memalign(&mut out, align, layout.size());
    if ret != 0 {
        ptr::null_mut()
    } else {
        out as *mut u8
    }
}
<commit_msg>fix unused-import error on android<commit_after>use crate::ptr;
use crate::sys_common::alloc::{MIN_ALIGN, realloc_fallback};
use crate::alloc::{GlobalAlloc, Layout, System};

#[stable(feature = "alloc_system_type", since = "1.28.0")]
unsafe impl GlobalAlloc for System {
    #[inline]
    unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
        // jemalloc provides alignment less than MIN_ALIGN for small allocations.
        // So only rely on MIN_ALIGN if size >= align.
        // Also see <https://github.com/rust-lang/rust/issues/45955> and
        // <https://github.com/rust-lang/rust/issues/62251#issuecomment-507580914>.
        if layout.align() <= MIN_ALIGN && layout.align() <= layout.size() {
            libc::malloc(layout.size()) as *mut u8
        } else {
            #[cfg(target_os = "macos")]
            {
                if layout.align() > (1 << 31) {
                    return ptr::null_mut()
                }
            }
            aligned_malloc(&layout)
        }
    }

    #[inline]
    unsafe fn alloc_zeroed(&self, layout: Layout) -> *mut u8 {
        // See the comment above in `alloc` for why this check looks the way it does.
        if layout.align() <= MIN_ALIGN && layout.align() <= layout.size() {
            libc::calloc(layout.size(), 1) as *mut u8
        } else {
            let ptr = self.alloc(layout.clone());
            if !ptr.is_null() {
                ptr::write_bytes(ptr, 0, layout.size());
            }
            ptr
        }
    }

    #[inline]
    unsafe fn dealloc(&self, ptr: *mut u8, _layout: Layout) {
        libc::free(ptr as *mut libc::c_void)
    }

    #[inline]
    unsafe fn realloc(&self, ptr: *mut u8, layout: Layout, new_size: usize) -> *mut u8 {
        if layout.align() <= MIN_ALIGN && layout.align() <= new_size {
            libc::realloc(ptr as *mut libc::c_void, new_size) as *mut u8
        } else {
            realloc_fallback(self, ptr, layout, new_size)
        }
    }
}

#[cfg(any(target_os = "android",
          target_os = "hermit",
          target_os = "redox",
          target_os = "solaris"))]
#[inline]
unsafe fn aligned_malloc(layout: &Layout) -> *mut u8 {
    // On android we currently target API level 9 which unfortunately
    // doesn't have the `posix_memalign` API used below. Instead we use
    // `memalign`, but this unfortunately has the property on some systems
    // where the memory returned cannot be deallocated by `free`!
    //
    // Upon closer inspection, however, this appears to work just fine with
    // Android, so for this platform we should be fine to call `memalign`
    // (which is present in API level 9). Some helpful references could
    // possibly be chromium using memalign [1], attempts at documenting that
    // memalign + free is ok [2] [3], or the current source of chromium
    // which still uses memalign on android [4].
    //
    // [1]: https://codereview.chromium.org/10796020/
    // [2]: https://code.google.com/p/android/issues/detail?id=35391
    // [3]: https://bugs.chromium.org/p/chromium/issues/detail?id=138579
    // [4]: https://chromium.googlesource.com/chromium/src/base/+/master/
    //                                       /memory/aligned_memory.cc
    libc::memalign(layout.align(), layout.size()) as *mut u8
}

#[cfg(not(any(target_os = "android",
              target_os = "hermit",
              target_os = "redox",
              target_os = "solaris")))]
#[inline]
unsafe fn aligned_malloc(layout: &Layout) -> *mut u8 {
    let mut out = ptr::null_mut();
    // posix_memalign requires that the alignment be a multiple of `sizeof(void*)`.
    // Since these are all powers of 2, we can just use max.
    let align = layout.align().max(crate::mem::size_of::<usize>());
    let ret = libc::posix_memalign(&mut out, align, layout.size());
    if ret != 0 {
        ptr::null_mut()
    } else {
        out as *mut u8
    }
}
<|endoftext|>


<commit_before>// Copyright 2018 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.

use std::fmt;
use std::str::FromStr;

/// The edition of the compiler (RFC 2052)
#[derive(Clone, Copy, Hash, PartialOrd, Ord, Eq, PartialEq, Debug, RustcEncodable, RustcDecodable)]
#[non_exhaustive]
pub enum Edition {
    // editions must be kept in order, newest to oldest

    /// The 2015 edition
    Edition2015,
    /// The 2018 edition
    Edition2018,

    // when adding new editions, be sure to update:
    //
    // - Update the `ALL_EDITIONS` const
    // - Update the EDITION_NAME_LIST const
    // - add a `rust_####()` function to the session
    // - update the enum in Cargo's sources as well
}

// must be in order from oldest to newest
pub const ALL_EDITIONS: &[Edition] = &[Edition::Edition2015, Edition::Edition2018];

pub const EDITION_NAME_LIST: &'static str = "2015|2018";

pub const DEFAULT_EDITION: Edition = Edition::Edition2015;

impl fmt::Display for Edition {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let s = match *self {
            Edition::Edition2015 => "2015",
            Edition::Edition2018 => "2018",
        };
        write!(f, "{}", s)
    }
}

impl Edition {
    pub fn lint_name(&self) -> &'static str {
        match *self {
            Edition::Edition2015 => "rust_2015_compatibility",
            Edition::Edition2018 => "rust_2018_compatibility",
        }
    }

    pub fn feature_name(&self) -> &'static str {
        match *self {
            Edition::Edition2015 => "rust_2015_preview",
            Edition::Edition2018 => "rust_2018_preview",
        }
    }

    pub fn is_stable(&self) -> bool {
        match *self {
            Edition::Edition2015 => true,
            Edition::Edition2018 => false,
        }
    }
}

impl FromStr for Edition {
    type Err = ();
    fn from_str(s: &str) -> Result<Self, ()> {
        match s {
            "2015" => Ok(Edition::Edition2015),
            "2018" => Ok(Edition::Edition2018),
            _ => Err(())
        }
    }
}
<commit_msg>Fix comment on editions<commit_after>// Copyright 2018 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.

use std::fmt;
use std::str::FromStr;

/// The edition of the compiler (RFC 2052)
#[derive(Clone, Copy, Hash, PartialOrd, Ord, Eq, PartialEq, Debug, RustcEncodable, RustcDecodable)]
#[non_exhaustive]
pub enum Edition {
    // editions must be kept in order, oldest to newest

    /// The 2015 edition
    Edition2015,
    /// The 2018 edition
    Edition2018,

    // when adding new editions, be sure to update:
    //
    // - Update the `ALL_EDITIONS` const
    // - Update the EDITION_NAME_LIST const
    // - add a `rust_####()` function to the session
    // - update the enum in Cargo's sources as well
}

// must be in order from oldest to newest
pub const ALL_EDITIONS: &[Edition] = &[Edition::Edition2015, Edition::Edition2018];

pub const EDITION_NAME_LIST: &'static str = "2015|2018";

pub const DEFAULT_EDITION: Edition = Edition::Edition2015;

impl fmt::Display for Edition {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let s = match *self {
            Edition::Edition2015 => "2015",
            Edition::Edition2018 => "2018",
        };
        write!(f, "{}", s)
    }
}

impl Edition {
    pub fn lint_name(&self) -> &'static str {
        match *self {
            Edition::Edition2015 => "rust_2015_compatibility",
            Edition::Edition2018 => "rust_2018_compatibility",
        }
    }

    pub fn feature_name(&self) -> &'static str {
        match *self {
            Edition::Edition2015 => "rust_2015_preview",
            Edition::Edition2018 => "rust_2018_preview",
        }
    }

    pub fn is_stable(&self) -> bool {
        match *self {
            Edition::Edition2015 => true,
            Edition::Edition2018 => false,
        }
    }
}

impl FromStr for Edition {
    type Err = ();
    fn from_str(s: &str) -> Result<Self, ()> {
        match s {
            "2015" => Ok(Edition::Edition2015),
            "2018" => Ok(Edition::Edition2018),
            _ => Err(())
        }
    }
}
<|endoftext|>


<commit_before>//! Validates the MIR to ensure that invariants are upheld.

use super::{MirPass, MirSource};
use rustc_middle::mir::visit::Visitor;
use rustc_middle::{
    mir::{
        BasicBlock, Body, Location, Operand, Rvalue, Statement, StatementKind, Terminator,
        TerminatorKind,
    },
    ty::{self, fold::BottomUpFolder, ParamEnv, Ty, TyCtxt, TypeFoldable},
};

#[derive(Copy, Clone, Debug)]
enum EdgeKind {
    Unwind,
    Normal,
}

pub struct Validator {
    /// Describes at which point in the pipeline this validation is happening.
    pub when: String,
}

impl<'tcx> MirPass<'tcx> for Validator {
    fn run_pass(&self, tcx: TyCtxt<'tcx>, source: MirSource<'tcx>, body: &mut Body<'tcx>) {
        let param_env = tcx.param_env(source.def_id());
        TypeChecker { when: &self.when, source, body, tcx, param_env }.visit_body(body);
    }
}

struct TypeChecker<'a, 'tcx> {
    when: &'a str,
    source: MirSource<'tcx>,
    body: &'a Body<'tcx>,
    tcx: TyCtxt<'tcx>,
    param_env: ParamEnv<'tcx>,
}

impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
    fn fail(&self, location: Location, msg: impl AsRef<str>) {
        let span = self.body.source_info(location).span;
        // We use `delay_span_bug` as we might see broken MIR when other errors have already
        // occurred.
        self.tcx.sess.diagnostic().delay_span_bug(
            span,
            &format!(
                "broken MIR in {:?} ({}) at {:?}:\n{}",
                self.source.instance,
                self.when,
                location,
                msg.as_ref()
            ),
        );
    }

    fn check_edge(&self, location: Location, bb: BasicBlock, edge_kind: EdgeKind) {
        if let Some(bb) = self.body.basic_blocks().get(bb) {
            let src = self.body.basic_blocks().get(location.block).unwrap();
            match (src.is_cleanup, bb.is_cleanup, edge_kind) {
                // Non-cleanup blocks can jump to non-cleanup blocks along non-unwind edges
                (false, false, EdgeKind::Normal)
                // Non-cleanup blocks can jump to cleanup blocks along unwind edges
                | (false, true, EdgeKind::Unwind)
                // Cleanup blocks can jump to cleanup blocks along non-unwind edges
                | (true, true, EdgeKind::Normal) => {}
                // All other jumps are invalid
                _ => {
                    self.fail(
                        location,
                        format!(
                            "{:?} edge to {:?} violates unwind invariants (cleanup {:?} -> {:?})",
                            edge_kind,
                            bb,
                            src.is_cleanup,
                            bb.is_cleanup,
                        )
                    )
                }
            }
        } else {
            self.fail(location, format!("encountered jump to invalid basic block {:?}", bb))
        }
    }
}

/// Check if src can be assigned into dest.
/// This is not precise, it will accept some incorrect assignments.
fn mir_assign_valid_types<'tcx>(tcx: TyCtxt<'tcx>, src: Ty<'tcx>, dest: Ty<'tcx>) -> bool {
    if src == dest {
        // Equal types, all is good.
        return true;
    }

    // Type-changing assignments can happen for (at least) two reasons:
    // 1. `&mut T` -> `&T` gets optimized from a reborrow to a mere assignment.
    // 2. Subtyping is used. While all normal lifetimes are erased, higher-ranked types
    //    with their late-bound lifetimes are still around and can lead to type differences.
    // Normalize both of them away.
    // FIXME: Share this code with `interpret/eval_context.rs`.
    let normalize = |ty: Ty<'tcx>| {
        ty.fold_with(&mut BottomUpFolder {
            tcx,
            // Normalize all references to immutable.
            ty_op: |ty| match ty.kind {
                ty::Ref(_, pointee, _) => tcx.mk_imm_ref(tcx.lifetimes.re_erased, pointee),
                _ => ty,
            },
            // We just erase all late-bound lifetimes, but this is not fully correct (FIXME):
            // lifetimes in invariant positions could matter (e.g. through associated types).
            // But that just means we miss some potential incompatible types, it will not
            // lead to wrong errors.
            lt_op: |_| tcx.lifetimes.re_erased,
            // Leave consts unchanged.
            ct_op: |ct| ct,
        })
    };
    normalize(src) == normalize(dest)
}

impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
    fn visit_operand(&mut self, operand: &Operand<'tcx>, location: Location) {
        // `Operand::Copy` is only supposed to be used with `Copy` types.
        if let Operand::Copy(place) = operand {
            let ty = place.ty(&self.body.local_decls, self.tcx).ty;
            let span = self.body.source_info(location).span;

            if !ty.is_copy_modulo_regions(self.tcx, self.param_env, span) {
                self.fail(location, format!("`Operand::Copy` with non-`Copy` type {}", ty));
            }
        }

        self.super_operand(operand, location);
    }

    fn visit_statement(&mut self, statement: &Statement<'tcx>, location: Location) {
        if let StatementKind::Assign(box (dest, rvalue)) = &statement.kind {
            // LHS and RHS of the assignment must have the same type.
            let left_ty = dest.ty(&self.body.local_decls, self.tcx).ty;
            let right_ty = rvalue.ty(&self.body.local_decls, self.tcx);
            if !mir_assign_valid_types(self.tcx, right_ty, left_ty) {
                self.fail(
                    location,
                    format!(
                        "encountered `Assign` statement with incompatible types:\n\
                        left-hand side has type: {}\n\
                        right-hand side has type: {}",
                        left_ty, right_ty,
                    ),
                );
            }
            // The sides of an assignment must not alias. Currently this just checks whether the places
            // are identical.
            match rvalue {
                Rvalue::Use(Operand::Copy(src) | Operand::Move(src)) => {
                    if dest == src {
                        self.fail(
                            location,
                            "encountered `Assign` statement with overlapping memory",
                        );
                    }
                }
                _ => {}
            }
        }
    }

    fn visit_terminator(&mut self, terminator: &Terminator<'tcx>, location: Location) {
        match &terminator.kind {
            TerminatorKind::Goto { target } => {
                self.check_edge(location, *target, EdgeKind::Normal);
            }
            TerminatorKind::SwitchInt { targets, values, .. } => {
                if targets.len() != values.len() + 1 {
                    self.fail(
                        location,
                        format!(
                            "encountered `SwitchInt` terminator with {} values, but {} targets (should be values+1)",
                            values.len(),
                            targets.len(),
                        ),
                    );
                }
                for target in targets {
                    self.check_edge(location, *target, EdgeKind::Normal);
                }
            }
            TerminatorKind::Drop { target, unwind, .. } => {
                self.check_edge(location, *target, EdgeKind::Normal);
                if let Some(unwind) = unwind {
                    self.check_edge(location, *unwind, EdgeKind::Unwind);
                }
            }
            TerminatorKind::DropAndReplace { target, unwind, .. } => {
                self.check_edge(location, *target, EdgeKind::Normal);
                if let Some(unwind) = unwind {
                    self.check_edge(location, *unwind, EdgeKind::Unwind);
                }
            }
            TerminatorKind::Call { func, destination, cleanup, .. } => {
                let func_ty = func.ty(&self.body.local_decls, self.tcx);
                match func_ty.kind {
                    ty::FnPtr(..) | ty::FnDef(..) => {}
                    _ => self.fail(
                        location,
                        format!("encountered non-callable type {} in `Call` terminator", func_ty),
                    ),
                }
                if let Some((_, target)) = destination {
                    self.check_edge(location, *target, EdgeKind::Normal);
                }
                if let Some(cleanup) = cleanup {
                    self.check_edge(location, *cleanup, EdgeKind::Unwind);
                }
            }
            TerminatorKind::Assert { cond, target, cleanup, .. } => {
                let cond_ty = cond.ty(&self.body.local_decls, self.tcx);
                if cond_ty != self.tcx.types.bool {
                    self.fail(
                        location,
                        format!(
                            "encountered non-boolean condition of type {} in `Assert` terminator",
                            cond_ty
                        ),
                    );
                }
                self.check_edge(location, *target, EdgeKind::Normal);
                if let Some(cleanup) = cleanup {
                    self.check_edge(location, *cleanup, EdgeKind::Unwind);
                }
            }
            TerminatorKind::Yield { resume, drop, .. } => {
                self.check_edge(location, *resume, EdgeKind::Normal);
                if let Some(drop) = drop {
                    self.check_edge(location, *drop, EdgeKind::Normal);
                }
            }
            TerminatorKind::FalseEdge { real_target, imaginary_target } => {
                self.check_edge(location, *real_target, EdgeKind::Normal);
                self.check_edge(location, *imaginary_target, EdgeKind::Normal);
            }
            TerminatorKind::FalseUnwind { real_target, unwind } => {
                self.check_edge(location, *real_target, EdgeKind::Normal);
                if let Some(unwind) = unwind {
                    self.check_edge(location, *unwind, EdgeKind::Unwind);
                }
            }
            TerminatorKind::InlineAsm { destination, .. } => {
                if let Some(destination) = destination {
                    self.check_edge(location, *destination, EdgeKind::Normal);
                }
            }
            // Nothing to validate for these.
            TerminatorKind::Resume
            | TerminatorKind::Abort
            | TerminatorKind::Return
            | TerminatorKind::Unreachable
            | TerminatorKind::GeneratorDrop => {}
        }
    }
}
<commit_msg>prepare visit_statement for checking more kinds of statements<commit_after>//! Validates the MIR to ensure that invariants are upheld.

use super::{MirPass, MirSource};
use rustc_middle::mir::visit::Visitor;
use rustc_middle::{
    mir::{
        BasicBlock, Body, Location, Operand, Rvalue, Statement, StatementKind, Terminator,
        TerminatorKind,
    },
    ty::{self, fold::BottomUpFolder, ParamEnv, Ty, TyCtxt, TypeFoldable},
};

#[derive(Copy, Clone, Debug)]
enum EdgeKind {
    Unwind,
    Normal,
}

pub struct Validator {
    /// Describes at which point in the pipeline this validation is happening.
    pub when: String,
}

impl<'tcx> MirPass<'tcx> for Validator {
    fn run_pass(&self, tcx: TyCtxt<'tcx>, source: MirSource<'tcx>, body: &mut Body<'tcx>) {
        let param_env = tcx.param_env(source.def_id());
        TypeChecker { when: &self.when, source, body, tcx, param_env }.visit_body(body);
    }
}

struct TypeChecker<'a, 'tcx> {
    when: &'a str,
    source: MirSource<'tcx>,
    body: &'a Body<'tcx>,
    tcx: TyCtxt<'tcx>,
    param_env: ParamEnv<'tcx>,
}

impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
    fn fail(&self, location: Location, msg: impl AsRef<str>) {
        let span = self.body.source_info(location).span;
        // We use `delay_span_bug` as we might see broken MIR when other errors have already
        // occurred.
        self.tcx.sess.diagnostic().delay_span_bug(
            span,
            &format!(
                "broken MIR in {:?} ({}) at {:?}:\n{}",
                self.source.instance,
                self.when,
                location,
                msg.as_ref()
            ),
        );
    }

    fn check_edge(&self, location: Location, bb: BasicBlock, edge_kind: EdgeKind) {
        if let Some(bb) = self.body.basic_blocks().get(bb) {
            let src = self.body.basic_blocks().get(location.block).unwrap();
            match (src.is_cleanup, bb.is_cleanup, edge_kind) {
                // Non-cleanup blocks can jump to non-cleanup blocks along non-unwind edges
                (false, false, EdgeKind::Normal)
                // Non-cleanup blocks can jump to cleanup blocks along unwind edges
                | (false, true, EdgeKind::Unwind)
                // Cleanup blocks can jump to cleanup blocks along non-unwind edges
                | (true, true, EdgeKind::Normal) => {}
                // All other jumps are invalid
                _ => {
                    self.fail(
                        location,
                        format!(
                            "{:?} edge to {:?} violates unwind invariants (cleanup {:?} -> {:?})",
                            edge_kind,
                            bb,
                            src.is_cleanup,
                            bb.is_cleanup,
                        )
                    )
                }
            }
        } else {
            self.fail(location, format!("encountered jump to invalid basic block {:?}", bb))
        }
    }
}

/// Check if src can be assigned into dest.
/// This is not precise, it will accept some incorrect assignments.
fn mir_assign_valid_types<'tcx>(tcx: TyCtxt<'tcx>, src: Ty<'tcx>, dest: Ty<'tcx>) -> bool {
    if src == dest {
        // Equal types, all is good.
        return true;
    }

    // Type-changing assignments can happen for (at least) two reasons:
    // 1. `&mut T` -> `&T` gets optimized from a reborrow to a mere assignment.
    // 2. Subtyping is used. While all normal lifetimes are erased, higher-ranked types
    //    with their late-bound lifetimes are still around and can lead to type differences.
    // Normalize both of them away.
    // FIXME: Share this code with `interpret/eval_context.rs`.
    let normalize = |ty: Ty<'tcx>| {
        ty.fold_with(&mut BottomUpFolder {
            tcx,
            // Normalize all references to immutable.
            ty_op: |ty| match ty.kind {
                ty::Ref(_, pointee, _) => tcx.mk_imm_ref(tcx.lifetimes.re_erased, pointee),
                _ => ty,
            },
            // We just erase all late-bound lifetimes, but this is not fully correct (FIXME):
            // lifetimes in invariant positions could matter (e.g. through associated types).
            // But that just means we miss some potential incompatible types, it will not
            // lead to wrong errors.
            lt_op: |_| tcx.lifetimes.re_erased,
            // Leave consts unchanged.
            ct_op: |ct| ct,
        })
    };
    normalize(src) == normalize(dest)
}

impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
    fn visit_operand(&mut self, operand: &Operand<'tcx>, location: Location) {
        // `Operand::Copy` is only supposed to be used with `Copy` types.
        if let Operand::Copy(place) = operand {
            let ty = place.ty(&self.body.local_decls, self.tcx).ty;
            let span = self.body.source_info(location).span;

            if !ty.is_copy_modulo_regions(self.tcx, self.param_env, span) {
                self.fail(location, format!("`Operand::Copy` with non-`Copy` type {}", ty));
            }
        }

        self.super_operand(operand, location);
    }

    fn visit_statement(&mut self, statement: &Statement<'tcx>, location: Location) {
        match &statement.kind {
            StatementKind::Assign(box (dest, rvalue)) => {
                // LHS and RHS of the assignment must have the same type.
                let left_ty = dest.ty(&self.body.local_decls, self.tcx).ty;
                let right_ty = rvalue.ty(&self.body.local_decls, self.tcx);
                if !mir_assign_valid_types(self.tcx, right_ty, left_ty) {
                    self.fail(
                        location,
                        format!(
                            "encountered `Assign` statement with incompatible types:\n\
                            left-hand side has type: {}\n\
                            right-hand side has type: {}",
                            left_ty, right_ty,
                        ),
                    );
                }
                // The sides of an assignment must not alias. Currently this just checks whether the places
                // are identical.
                match rvalue {
                    Rvalue::Use(Operand::Copy(src) | Operand::Move(src)) => {
                        if dest == src {
                            self.fail(
                                location,
                                "encountered `Assign` statement with overlapping memory",
                            );
                        }
                    }
                    _ => {}
                }
            }
            _ => {}
        }
    }

    fn visit_terminator(&mut self, terminator: &Terminator<'tcx>, location: Location) {
        match &terminator.kind {
            TerminatorKind::Goto { target } => {
                self.check_edge(location, *target, EdgeKind::Normal);
            }
            TerminatorKind::SwitchInt { targets, values, .. } => {
                if targets.len() != values.len() + 1 {
                    self.fail(
                        location,
                        format!(
                            "encountered `SwitchInt` terminator with {} values, but {} targets (should be values+1)",
                            values.len(),
                            targets.len(),
                        ),
                    );
                }
                for target in targets {
                    self.check_edge(location, *target, EdgeKind::Normal);
                }
            }
            TerminatorKind::Drop { target, unwind, .. } => {
                self.check_edge(location, *target, EdgeKind::Normal);
                if let Some(unwind) = unwind {
                    self.check_edge(location, *unwind, EdgeKind::Unwind);
                }
            }
            TerminatorKind::DropAndReplace { target, unwind, .. } => {
                self.check_edge(location, *target, EdgeKind::Normal);
                if let Some(unwind) = unwind {
                    self.check_edge(location, *unwind, EdgeKind::Unwind);
                }
            }
            TerminatorKind::Call { func, destination, cleanup, .. } => {
                let func_ty = func.ty(&self.body.local_decls, self.tcx);
                match func_ty.kind {
                    ty::FnPtr(..) | ty::FnDef(..) => {}
                    _ => self.fail(
                        location,
                        format!("encountered non-callable type {} in `Call` terminator", func_ty),
                    ),
                }
                if let Some((_, target)) = destination {
                    self.check_edge(location, *target, EdgeKind::Normal);
                }
                if let Some(cleanup) = cleanup {
                    self.check_edge(location, *cleanup, EdgeKind::Unwind);
                }
            }
            TerminatorKind::Assert { cond, target, cleanup, .. } => {
                let cond_ty = cond.ty(&self.body.local_decls, self.tcx);
                if cond_ty != self.tcx.types.bool {
                    self.fail(
                        location,
                        format!(
                            "encountered non-boolean condition of type {} in `Assert` terminator",
                            cond_ty
                        ),
                    );
                }
                self.check_edge(location, *target, EdgeKind::Normal);
                if let Some(cleanup) = cleanup {
                    self.check_edge(location, *cleanup, EdgeKind::Unwind);
                }
            }
            TerminatorKind::Yield { resume, drop, .. } => {
                self.check_edge(location, *resume, EdgeKind::Normal);
                if let Some(drop) = drop {
                    self.check_edge(location, *drop, EdgeKind::Normal);
                }
            }
            TerminatorKind::FalseEdge { real_target, imaginary_target } => {
                self.check_edge(location, *real_target, EdgeKind::Normal);
                self.check_edge(location, *imaginary_target, EdgeKind::Normal);
            }
            TerminatorKind::FalseUnwind { real_target, unwind } => {
                self.check_edge(location, *real_target, EdgeKind::Normal);
                if let Some(unwind) = unwind {
                    self.check_edge(location, *unwind, EdgeKind::Unwind);
                }
            }
            TerminatorKind::InlineAsm { destination, .. } => {
                if let Some(destination) = destination {
                    self.check_edge(location, *destination, EdgeKind::Normal);
                }
            }
            // Nothing to validate for these.
            TerminatorKind::Resume
            | TerminatorKind::Abort
            | TerminatorKind::Return
            | TerminatorKind::Unreachable
            | TerminatorKind::GeneratorDrop => {}
        }
    }
}
<|endoftext|>


<commit_before>use std::num::Wrapping;
use number_types::d8_type::d8;

#[allow(warnings)]
#[derive(Copy, Clone, Debug)]
pub struct d16(pub Wrapping<u16>);

impl d16 {
    pub fn lsb(self) -> d8 {
        // remember, on little-endian systems, the lsb has index 0!
        let array: [d8; 2] = unsafe {
            ::std::mem::transmute::<d16, [d8; 2]>(self)
        };
        array[0]
    }

    pub const HIGHEST_BIT_MASK: d16 = d16(Wrapping(0b1000000000000000));
    pub const LOWEST_BIT_MASK: d16 = d16(Wrapping(0b0000000000000001));
    pub const ZERO: d16 = d16(Wrapping(0));
}

impl ::std::cmp::PartialEq for d16 {
    fn eq(&self, &d16(other): &Self) -> bool {
        let d16(me) = *self;
        me == other
    }
}

impl ::std::cmp::Eq for d16 {}

impl ::std::cmp::PartialEq<u16> for d16 {
    fn eq(&self, &other: &u16) -> bool {
        let d16(Wrapping(me)) = *self;
        me == other
    }
}

impl ::std::cmp::PartialOrd for d16 {
    fn partial_cmp(&self, &d16(other): &Self) -> Option<::std::cmp::Ordering> {
        let d16(me) = *self;
        if me < other {
            Some(::std::cmp::Ordering::Less)
        } else if me > other {
            Some(::std::cmp::Ordering::Greater)
        } else {
            Some(::std::cmp::Ordering::Equal)
        }
    }

    fn lt(&self, &d16(other): &Self) -> bool {
        let d16(me) = *self;
        me < other
    }

    fn gt(&self, &d16(other): &Self) -> bool {
        let d16(me) = *self;
        me > other
    }

    fn le(&self, &d16(other): &Self) -> bool {
        let d16(me) = *self;
        me <= other
    }

    fn ge(&self, &d16(other): &Self) -> bool {
        let d16(me) = *self;
        me >= other
    }
}

impl ::std::cmp::Ord for d16 {
    fn cmp(&self, &d16(other): &Self) -> ::std::cmp::Ordering {
        let d16(me) = *self;
        if me < other {
            ::std::cmp::Ordering::Less
        } else if me > other {
            ::std::cmp::Ordering::Greater
        } else {
            ::std::cmp::Ordering::Equal
        }
    }
}

impl ::std::convert::AsRef<[d8; 2]> for d16 {
    fn as_ref(&self) -> &[d8; 2] {
        use std::mem::transmute;

        unsafe {
            transmute(&self)
        }
    }
}

impl ::std::convert::Into<[d8; 2]> for d16 {
    fn into(self) -> [d8; 2] {
        unsafe {
            ::std::mem::transmute(self)
        }
    }
}

impl ::std::convert::Into<d16> for [d8; 2] {
    fn into(self) -> d16 {
        unsafe {
            ::std::mem::transmute(self)
        }
    }
}

impl ::std::ops::Add for d16 {
    type Output = Self;
    fn add(self, d16(other): Self) -> <Self as ::std::ops::Add<Self>>::Output {
        let d16(me) = self;
        d16(me + other)
    }
}

impl ::std::ops::AddAssign for d16 {
    fn add_assign(&mut self, d16(other): Self) {
        self.0 = self.0 + other;
    }
}

impl ::std::ops::Add<u16> for d16 {
    type Output = Self;
    fn add(self, other: u16) -> <Self as ::std::ops::Add<u16>>::Output {
        let d16(me) = self;
        d16(me + Wrapping(other))
    }
}

impl ::std::ops::AddAssign<u16> for d16 {
    fn add_assign(&mut self, other: u16) {
        self.0 = self.0 + Wrapping(other);
    }
}

impl ::std::ops::Sub for d16 {
    type Output = Self;
    fn sub(self, d16(other): Self) -> <Self as ::std::ops::Sub<Self>>::Output {
        let d16(me) = self;
        d16(me - other)
    }
}

impl ::std::ops::SubAssign for d16 {
    fn sub_assign(&mut self, d16(other): Self) {
        self.0 = self.0 - other;
    }
}

impl ::std::ops::SubAssign<u16> for d16 {
    fn sub_assign(&mut self, other: u16) {
        self.0 = self.0 - Wrapping(other);
    }
}

impl ::std::ops::BitAnd for d16 {
    type Output = Self;
    fn bitand(self, d16(other): Self) -> <Self as ::std::ops::BitAnd>::Output {
        let d16(me) = self;
        d16(me & other)
    }
}

impl ::std::ops::BitAndAssign for d16 {
    fn bitand_assign(&mut self, d16(other): Self) {
        self.0 &= other;
    }
}
<commit_msg>Switched from implementing Into to From for d16 <=> [d8; 2] conversions<commit_after>use std::num::Wrapping;
use number_types::d8_type::d8;

#[allow(warnings)]
#[derive(Copy, Clone, Debug)]
pub struct d16(pub Wrapping<u16>);

impl d16 {
    pub fn lsb(self) -> d8 {
        // remember, on little-endian systems, the lsb has index 0!
        let array: [d8; 2] = unsafe {
            ::std::mem::transmute::<d16, [d8; 2]>(self)
        };
        array[0]
    }

    pub const HIGHEST_BIT_MASK: d16 = d16(Wrapping(0b1000000000000000));
    pub const LOWEST_BIT_MASK: d16 = d16(Wrapping(0b0000000000000001));
    pub const ZERO: d16 = d16(Wrapping(0));
}

impl ::std::cmp::PartialEq for d16 {
    fn eq(&self, &d16(other): &Self) -> bool {
        let d16(me) = *self;
        me == other
    }
}

impl ::std::cmp::Eq for d16 {}

impl ::std::cmp::PartialEq<u16> for d16 {
    fn eq(&self, &other: &u16) -> bool {
        let d16(Wrapping(me)) = *self;
        me == other
    }
}

impl ::std::cmp::PartialOrd for d16 {
    fn partial_cmp(&self, &d16(other): &Self) -> Option<::std::cmp::Ordering> {
        let d16(me) = *self;
        if me < other {
            Some(::std::cmp::Ordering::Less)
        } else if me > other {
            Some(::std::cmp::Ordering::Greater)
        } else {
            Some(::std::cmp::Ordering::Equal)
        }
    }

    fn lt(&self, &d16(other): &Self) -> bool {
        let d16(me) = *self;
        me < other
    }

    fn gt(&self, &d16(other): &Self) -> bool {
        let d16(me) = *self;
        me > other
    }

    fn le(&self, &d16(other): &Self) -> bool {
        let d16(me) = *self;
        me <= other
    }

    fn ge(&self, &d16(other): &Self) -> bool {
        let d16(me) = *self;
        me >= other
    }
}

impl ::std::cmp::Ord for d16 {
    fn cmp(&self, &d16(other): &Self) -> ::std::cmp::Ordering {
        let d16(me) = *self;
        if me < other {
            ::std::cmp::Ordering::Less
        } else if me > other {
            ::std::cmp::Ordering::Greater
        } else {
            ::std::cmp::Ordering::Equal
        }
    }
}

impl ::std::convert::AsRef<[d8; 2]> for d16 {
    fn as_ref(&self) -> &[d8; 2] {
        use std::mem::transmute;

        unsafe {
            transmute(&self)
        }
    }
}

impl ::std::convert::From<[d8; 2]> for d16 {
    fn from(this: [d8; 2]) -> Self {
        unsafe {
            ::std::mem::transmute(this)
        }
    }
}

impl ::std::convert::From<d16> for [d8; 2] {
    fn from(this: d16) -> Self {
        unsafe {
            ::std::mem::transmute(this)
        }
    }
}

impl ::std::ops::Add for d16 {
    type Output = Self;
    fn add(self, d16(other): Self) -> <Self as ::std::ops::Add<Self>>::Output {
        let d16(me) = self;
        d16(me + other)
    }
}

impl ::std::ops::AddAssign for d16 {
    fn add_assign(&mut self, d16(other): Self) {
        self.0 = self.0 + other;
    }
}

impl ::std::ops::Add<u16> for d16 {
    type Output = Self;
    fn add(self, other: u16) -> <Self as ::std::ops::Add<u16>>::Output {
        let d16(me) = self;
        d16(me + Wrapping(other))
    }
}

impl ::std::ops::AddAssign<u16> for d16 {
    fn add_assign(&mut self, other: u16) {
        self.0 = self.0 + Wrapping(other);
    }
}

impl ::std::ops::Sub for d16 {
    type Output = Self;
    fn sub(self, d16(other): Self) -> <Self as ::std::ops::Sub<Self>>::Output {
        let d16(me) = self;
        d16(me - other)
    }
}

impl ::std::ops::SubAssign for d16 {
    fn sub_assign(&mut self, d16(other): Self) {
        self.0 = self.0 - other;
    }
}

impl ::std::ops::SubAssign<u16> for d16 {
    fn sub_assign(&mut self, other: u16) {
        self.0 = self.0 - Wrapping(other);
    }
}

impl ::std::ops::BitAnd for d16 {
    type Output = Self;
    fn bitand(self, d16(other): Self) -> <Self as ::std::ops::BitAnd>::Output {
        let d16(me) = self;
        d16(me & other)
    }
}

impl ::std::ops::BitAndAssign for d16 {
    fn bitand_assign(&mut self, d16(other): Self) {
        self.0 &= other;
    }
}
<|endoftext|>


<commit_before>use seed::prelude::*;
use crate::Msg;

pub mod perfects_utils {
	use num_bigint::{BigUint,ToBigUint};
	use num_traits::{ToPrimitive};
    use seed::prelude::*;
    use crate::Msg;

	#[derive(Clone)]
	pub struct Perfect {
		pub n: u64,
		pub p: u64,
		pub digits: u64,
		pub discovery: String,
	}

	#[derive(Clone)]
	pub struct PerfectDownload {
		pub n: u64,
		pub p: u64,
	}

	pub fn perfects() -> Vec<Perfect> {
        vec![
			Perfect {n: 51, p: 82589934, digits: 49724095, discovery: String::from("2018 Laroche, Woltman, Kurowski, Blosser, et al.")},
			Perfect {n: 50, p: 77232917, digits: 46498850, discovery: String::from("2017 Jonathan Pace, George Woltman, Scott Kurowski, Aaron Blosser, et al..") },
			Perfect {n: 49, p: 74207281, digits: 44677235, discovery: String::from("2016 Cooper, Woltman, Kurowski, Blosser et al.") },
			Perfect {n: 48, p: 57885161, digits: 34850340, discovery: String::from("2013 Cooper, Woltman, Kurowski, et al.") },
			Perfect {n: 47, p: 43112609, digits: 25956377, discovery: String::from("2008 Smith, Woltman, Kurowski, et al.") },
			Perfect {n: 46, p: 42643801, digits: 42643801, discovery: String::from("2009 Strindmo, Woltman, Kurowski, et al.") },
			Perfect {n: 45, p: 37156667, digits: 22370543, discovery: String::from("2008 Elvenich, Woltman, Kurowski, et al.") },
			Perfect {n: 44, p: 32582657, digits: 19616714, discovery: String::from("2006 Cooper, Boone, Woltman, Kurowski, et al.") },
			Perfect {n: 43, p: 30402457, digits: 18304103, discovery: String::from("2005 Cooper, Boone, Woltman, Kurowski, et al.") },
			Perfect {n: 42, p: 25964951, digits: 15632458, discovery: String::from("2005 Nowak, Woltman, Kurowski, et. al.") },
			Perfect {n: 41, p: 24036583, digits: 14471465, discovery: String::from("2004 Findley, Woltman, Kurowski, et. al.") },
			Perfect {n: 40, p: 20996011, digits: 12640858, discovery: String::from("2003 Shafer, Woltman, Kurowski, et. al.") },
			Perfect {n: 39, p: 13466917, digits: 8107892, discovery: String::from("2001 Cameron, Woltman, Kurowski, et. al.") },
			Perfect {n: 38, p: 6972593, digits: 4197919, discovery: String::from("1999 Hajratwala, Woltman, Kurowski, et. al.") },
			Perfect {n: 37, p: 3021377, digits: 1819050, discovery: String::from("1998 Clarkson, Woltman, Kurowski, et. al.") },
			Perfect {n: 36, p: 2976221, digits: 1791864, discovery: String::from("1997 Spence, Woltman, et. al.") },
			Perfect {n: 35, p: 1398269, digits: 841842, discovery: String::from("1996 Armengaud, Woltman, et. al.") },
			Perfect {n: 34, p: 1257787, digits: 757263, discovery: String::from("1996 Slowinski&Gage") },
			Perfect {n: 33, p: 859433, digits: 517430, discovery: String::from("1994 Slowinski&Gage") },
			Perfect {n: 32, p: 756839, digits: 455663, discovery: String::from("1992 Slowinski&Gage") },
			Perfect {n: 31, p: 216091, digits: 130100, discovery: String::from("1985 Slowinski") },
			Perfect {n: 30, p: 132049, digits: 79502, discovery: String::from("1983 Slowinski") },
			Perfect {n: 29, p: 110503, digits: 66530, discovery: String::from("1988 Colquitt&Welsh") },
			Perfect {n: 28, p: 86243, digits: 51924, discovery: String::from("1982 Slowinski") },
			Perfect {n: 27, p: 44497, digits: 26790, discovery: String::from("1979 Nelson&Slowinski") },
			Perfect {n: 26, p: 23209, digits: 13973, discovery: String::from("1979 Noll") },
			Perfect {n: 25, p: 21701, digits: 13066, discovery: String::from("1978 Noll&Nickel") },
			Perfect {n: 24, p: 19937, digits: 12003, discovery: String::from("1971 Tuckerman") },
			Perfect {n: 23, p: 11213, digits: 6751, discovery: String::from("1963 Gillies") },
			Perfect {n: 22, p: 9941, digits: 5985, discovery: String::from("1963 Gillies") },
			Perfect {n: 21, p: 9689, digits: 5834, discovery: String::from("1963 Gillies") },
			Perfect {n: 20, p: 4423, digits: 2663, discovery: String::from("1961 Hurwitz") },
			Perfect {n: 19, p: 4253, digits: 2561, discovery: String::from("1961 Hurwitz") },
			Perfect {n: 18, p: 3217, digits: 1937, discovery: String::from("1957 Riesel") },
			Perfect {n: 17, p: 2281, digits: 1373, discovery: String::from("1952 Robinson") },
			Perfect {n: 16, p: 2203, digits: 1327, discovery: String::from("1952 Robinson") },
			Perfect {n: 15, p: 1279, digits: 770, discovery: String::from("1952 Robinson") },
			Perfect {n: 14, p: 607, digits: 366, discovery: String::from("1952 Robinson") },
			Perfect {n: 13, p: 521, digits: 314, discovery: String::from("1952 Robinson") },
			Perfect {n: 12, p: 127, digits: 77, discovery: String::from("1876 Lucas") },
			Perfect {n: 11, p: 107, digits: 65, discovery: String::from("1914 Powers") },
			Perfect {n: 10, p: 89, digits: 54, discovery: String::from("1911 Powers") },
			Perfect {n: 9, p: 61, digits: 37, discovery: String::from("1883 Pervushin") },
			Perfect {n: 8, p: 31, digits: 19, discovery: String::from("1772 Euler") },
			Perfect {n: 7, p: 19, digits: 12, discovery: String::from("1588 Cataldi") },
			Perfect {n: 6, p: 17, digits: 10, discovery: String::from("1588 Cataldi") },
			Perfect {n: 5, p: 13, digits: 8, discovery: String::from("1456 ?") },
			Perfect {n: 4, p: 7, digits: 4, discovery: String::from("?") },
			Perfect {n: 3, p: 5, digits: 3, discovery: String::from("?") },
			Perfect {n: 2, p: 3, digits: 2, discovery: String::from("?") },
			Perfect {n: 1, p: 2, digits: 1, discovery: String::from("?") },
		]
	}

	pub fn save_as_file(filename:String, filecontent:String) -> seed::dom_types::Node<Msg> {
        let href:String = vec!["data:text/plain,",&filecontent].into_iter().collect();
        a![attrs!{At::Download => &filename, At::Href => &href}, "TXT"]
    }

	pub fn generate_file(n:u64, p:u64) -> seed::dom_types::Node<Msg> {
		let download_filename:String = format!("P{}.txt",&n.to_string());
		let two:BigUint = 2.to_biguint().unwrap();
		let power:BigUint = two.clone() << (p.to_usize().unwrap()-1-1);
        let perfect_value:BigUint = power.clone() * ((power.clone()*two.clone()) -1.to_biguint().unwrap());
        save_as_file(download_filename, perfect_value.to_string())
    }
}

pub fn render(model: &crate::Model) -> seed::dom_types::Node<Msg> {
    let mut html = vec![];
    let perfects = perfects_utils::perfects().to_owned();

    for perfect in perfects.iter() {
		let perfectp:u64 = perfect.p;
		let perfect_download = perfects_utils::PerfectDownload {n: perfect.n, p: perfect.p};
		let equation:String = format!("2{} × (2{}-1)",&(perfectp-1).to_string(),&(perfectp).to_string());

        html.push(
            tr![
                td![perfect.n.to_string()],//rank
				td![El::from_html(&equation)],//perfect number as a formula

                td![perfect.digits.to_string()],//digits in length
                td![perfect.discovery],//discovery
				if model.download.n == perfect.n {
					td![perfects_utils::generate_file(model.download.n,model.download.p)]
				} else {
					td![button!["Generate",mouse_ev("mouseup", move |event| Msg::GenerateDownload(event, perfect_download))]]
				},
            ]
        );
    }

    div![
        h1!["The Perfect Numbers"],
        br![],
        br![],
        br![],
        table![
            attrs!{At::Class => "perfecttable text"},
            tbody![
                tr![
                    td![
                        b!["No."]
                    ],
                    td![
                        b!["Prime"]
                    ],
                    td![
                        b!["Digits"]
                    ],
                    td![
                        b!["Discovered"]
                    ],
                    td![
                        b!["Download"]
                    ]
                ],
                html
            ]
        ]
    ]
}

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

    #[test]
    fn perfect_test<'a>() {
        let mut perfects:Vec<perfects_utils::Perfect> = perfects_utils::perfects();
		perfects.reverse();
		assert_eq!(perfects[50].digits, 49724095);
        assert_eq!(perfects[49].digits, 46498850);
        assert_eq!(perfects[39].digits, 12640858);
    }
}<commit_msg>Fixing & -> &<commit_after>use seed::prelude::*;
use crate::Msg;

pub mod perfects_utils {
	use num_bigint::{BigUint,ToBigUint};
	use num_traits::{ToPrimitive};
    use seed::prelude::*;
    use crate::Msg;

	#[derive(Clone)]
	pub struct Perfect {
		pub n: u64,
		pub p: u64,
		pub digits: u64,
		pub discovery: String,
	}

	#[derive(Clone)]
	pub struct PerfectDownload {
		pub n: u64,
		pub p: u64,
	}

	pub fn perfects() -> Vec<Perfect> {
        vec![
			Perfect {n: 51, p: 82589934, digits: 49724095, discovery: String::from("2018 Laroche, Woltman, Kurowski, Blosser, et al.")},
			Perfect {n: 50, p: 77232917, digits: 46498850, discovery: String::from("2017 Jonathan Pace, George Woltman, Scott Kurowski, Aaron Blosser, et al..") },
			Perfect {n: 49, p: 74207281, digits: 44677235, discovery: String::from("2016 Cooper, Woltman, Kurowski, Blosser et al.") },
			Perfect {n: 48, p: 57885161, digits: 34850340, discovery: String::from("2013 Cooper, Woltman, Kurowski, et al.") },
			Perfect {n: 47, p: 43112609, digits: 25956377, discovery: String::from("2008 Smith, Woltman, Kurowski, et al.") },
			Perfect {n: 46, p: 42643801, digits: 42643801, discovery: String::from("2009 Strindmo, Woltman, Kurowski, et al.") },
			Perfect {n: 45, p: 37156667, digits: 22370543, discovery: String::from("2008 Elvenich, Woltman, Kurowski, et al.") },
			Perfect {n: 44, p: 32582657, digits: 19616714, discovery: String::from("2006 Cooper, Boone, Woltman, Kurowski, et al.") },
			Perfect {n: 43, p: 30402457, digits: 18304103, discovery: String::from("2005 Cooper, Boone, Woltman, Kurowski, et al.") },
			Perfect {n: 42, p: 25964951, digits: 15632458, discovery: String::from("2005 Nowak, Woltman, Kurowski, et. al.") },
			Perfect {n: 41, p: 24036583, digits: 14471465, discovery: String::from("2004 Findley, Woltman, Kurowski, et. al.") },
			Perfect {n: 40, p: 20996011, digits: 12640858, discovery: String::from("2003 Shafer, Woltman, Kurowski, et. al.") },
			Perfect {n: 39, p: 13466917, digits: 8107892, discovery: String::from("2001 Cameron, Woltman, Kurowski, et. al.") },
			Perfect {n: 38, p: 6972593, digits: 4197919, discovery: String::from("1999 Hajratwala, Woltman, Kurowski, et. al.") },
			Perfect {n: 37, p: 3021377, digits: 1819050, discovery: String::from("1998 Clarkson, Woltman, Kurowski, et. al.") },
			Perfect {n: 36, p: 2976221, digits: 1791864, discovery: String::from("1997 Spence, Woltman, et. al.") },
			Perfect {n: 35, p: 1398269, digits: 841842, discovery: String::from("1996 Armengaud, Woltman, et. al.") },
			Perfect {n: 34, p: 1257787, digits: 757263, discovery: String::from("1996 Slowinski & Gage") },
			Perfect {n: 33, p: 859433, digits: 517430, discovery: String::from("1994 Slowinski & Gage") },
			Perfect {n: 32, p: 756839, digits: 455663, discovery: String::from("1992 Slowinski & Gage") },
			Perfect {n: 31, p: 216091, digits: 130100, discovery: String::from("1985 Slowinski") },
			Perfect {n: 30, p: 132049, digits: 79502, discovery: String::from("1983 Slowinski") },
			Perfect {n: 29, p: 110503, digits: 66530, discovery: String::from("1988 Colquitt & Welsh") },
			Perfect {n: 28, p: 86243, digits: 51924, discovery: String::from("1982 Slowinski") },
			Perfect {n: 27, p: 44497, digits: 26790, discovery: String::from("1979 Nelson & Slowinski") },
			Perfect {n: 26, p: 23209, digits: 13973, discovery: String::from("1979 Noll") },
			Perfect {n: 25, p: 21701, digits: 13066, discovery: String::from("1978 Noll & Nickel") },
			Perfect {n: 24, p: 19937, digits: 12003, discovery: String::from("1971 Tuckerman") },
			Perfect {n: 23, p: 11213, digits: 6751, discovery: String::from("1963 Gillies") },
			Perfect {n: 22, p: 9941, digits: 5985, discovery: String::from("1963 Gillies") },
			Perfect {n: 21, p: 9689, digits: 5834, discovery: String::from("1963 Gillies") },
			Perfect {n: 20, p: 4423, digits: 2663, discovery: String::from("1961 Hurwitz") },
			Perfect {n: 19, p: 4253, digits: 2561, discovery: String::from("1961 Hurwitz") },
			Perfect {n: 18, p: 3217, digits: 1937, discovery: String::from("1957 Riesel") },
			Perfect {n: 17, p: 2281, digits: 1373, discovery: String::from("1952 Robinson") },
			Perfect {n: 16, p: 2203, digits: 1327, discovery: String::from("1952 Robinson") },
			Perfect {n: 15, p: 1279, digits: 770, discovery: String::from("1952 Robinson") },
			Perfect {n: 14, p: 607, digits: 366, discovery: String::from("1952 Robinson") },
			Perfect {n: 13, p: 521, digits: 314, discovery: String::from("1952 Robinson") },
			Perfect {n: 12, p: 127, digits: 77, discovery: String::from("1876 Lucas") },
			Perfect {n: 11, p: 107, digits: 65, discovery: String::from("1914 Powers") },
			Perfect {n: 10, p: 89, digits: 54, discovery: String::from("1911 Powers") },
			Perfect {n: 9, p: 61, digits: 37, discovery: String::from("1883 Pervushin") },
			Perfect {n: 8, p: 31, digits: 19, discovery: String::from("1772 Euler") },
			Perfect {n: 7, p: 19, digits: 12, discovery: String::from("1588 Cataldi") },
			Perfect {n: 6, p: 17, digits: 10, discovery: String::from("1588 Cataldi") },
			Perfect {n: 5, p: 13, digits: 8, discovery: String::from("1456 ?") },
			Perfect {n: 4, p: 7, digits: 4, discovery: String::from("?") },
			Perfect {n: 3, p: 5, digits: 3, discovery: String::from("?") },
			Perfect {n: 2, p: 3, digits: 2, discovery: String::from("?") },
			Perfect {n: 1, p: 2, digits: 1, discovery: String::from("?") },
		]
	}

	pub fn save_as_file(filename:String, filecontent:String) -> seed::dom_types::Node<Msg> {
        let href:String = vec!["data:text/plain,",&filecontent].into_iter().collect();
        a![attrs!{At::Download => &filename, At::Href => &href}, "TXT"]
    }

	pub fn generate_file(n:u64, p:u64) -> seed::dom_types::Node<Msg> {
		let download_filename:String = format!("P{}.txt",&n.to_string());
		let two:BigUint = 2.to_biguint().unwrap();
		let power:BigUint = two.clone() << (p.to_usize().unwrap()-1-1);
        let perfect_value:BigUint = power.clone() * ((power.clone()*two.clone()) -1.to_biguint().unwrap());
        save_as_file(download_filename, perfect_value.to_string())
    }
}

pub fn render(model: &crate::Model) -> seed::dom_types::Node<Msg> {
    let mut html = vec![];
    let perfects = perfects_utils::perfects().to_owned();

    for perfect in perfects.iter() {
		let perfectp:u64 = perfect.p;
		let perfect_download = perfects_utils::PerfectDownload {n: perfect.n, p: perfect.p};
		let equation:String = format!("2{} × (2{}-1)",&(perfectp-1).to_string(),&(perfectp).to_string());

        html.push(
            tr![
                td![perfect.n.to_string()],//rank
				td![El::from_html(&equation)],//perfect number as a formula

                td![perfect.digits.to_string()],//digits in length
                td![perfect.discovery],//discovery
				if model.download.n == perfect.n {
					td![perfects_utils::generate_file(model.download.n,model.download.p)]
				} else {
					td![button!["Generate",mouse_ev("mouseup", move |event| Msg::GenerateDownload(event, perfect_download))]]
				},
            ]
        );
    }

    div![
        h1!["The Perfect Numbers"],
        br![],
        br![],
        br![],
        table![
            attrs!{At::Class => "perfecttable text"},
            tbody![
                tr![
                    td![
                        b!["No."]
                    ],
                    td![
                        b!["Prime"]
                    ],
                    td![
                        b!["Digits"]
                    ],
                    td![
                        b!["Discovered"]
                    ],
                    td![
                        b!["Download"]
                    ]
                ],
                html
            ]
        ]
    ]
}

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

    #[test]
    fn perfect_test<'a>() {
        let mut perfects:Vec<perfects_utils::Perfect> = perfects_utils::perfects();
		perfects.reverse();
		assert_eq!(perfects[50].digits, 49724095);
        assert_eq!(perfects[49].digits, 46498850);
        assert_eq!(perfects[39].digits, 12640858);
    }
}<|endoftext|>