<commit_before>use crate::deserialize::*;
use crate::errors::*;

use std::path::Path;

/// sort <link> and <joint> to avoid the [issue](https://github.com/RReverser/serde-xml-rs/issues/5)
fn sort_link_joint(string: &str) -> Result<String> {
    let e: xml::Element = string.parse().map_err(UrdfError::new)?;
    let mut links = Vec::new();
    let mut joints = Vec::new();
    let mut materials = Vec::new();
    for c in &e.children {
        if let xml::Xml::ElementNode(ref xml_elm) = *c {
            if xml_elm.name == "link" {
                links.push(xml::Xml::ElementNode(xml_elm.clone()));
            } else if xml_elm.name == "joint" {
                joints.push(xml::Xml::ElementNode(xml_elm.clone()));
            } else if xml_elm.name == "material" {
                materials.push(xml::Xml::ElementNode(xml_elm.clone()));
            }
        };
    }
    let mut new_elm = e.clone();
    links.extend(joints);
    links.extend(materials);
    new_elm.children = links;
    Ok(format!("{}", new_elm))
}

/// Read urdf file and create Robot instance
///
/// # Examples
///
/// ```
/// let urdf_robo = urdf_rs::read_file("sample.urdf").unwrap();
/// let links = urdf_robo.links;
/// println!("{:?}", links[0].visual[0].origin.xyz);
/// ```
pub fn read_file<P: AsRef<Path>>(path: P) -> Result<Robot> {
    read_from_string(&std::fs::read_to_string(path)?)
}

/// Read from string instead of file.
///
///
/// # Examples
///
/// ```
/// let s = r##"
///     <robot name="robo">
///         <link name="shoulder1">
///             <inertial>
///                 <origin xyz="0 0 0.5" rpy="0 0 0"/>
///                 <mass value="1"/>
///                 <inertia ixx="100"  ixy="0"  ixz="0" iyy="100" iyz="0" izz="100" />
///             </inertial>
///             <visual>
///                 <origin xyz="0.1 0.2 0.3" rpy="-0.1 -0.2  -0.3" />
///                 <geometry>
///                     <box size="1.0 2.0 3.0" />
///                 </geometry>
///                 <material name="Cyan">
///                     <color rgba="0 1.0 1.0 1.0"/>
///                 </material>
///             </visual>
///             <collision>
///                 <origin xyz="0 0 0" rpy="0 0 0"/>
///                 <geometry>
///                     <cylinder radius="1" length="0.5"/>
///                 </geometry>
///             </collision>
///         </link>
///         <link name="elbow1" />
///         <link name="wrist1" />
///         <joint name="shoulder_pitch" type="revolute">
///             <origin xyz="0.0 0.0 0.1" />
///             <parent link="shoulder1" />
///             <child link="elbow1" />
///             <axis xyz="0 1 -1" />
///             <limit lower="-1" upper="1.0" effort="0" velocity="1.0"/>
///         </joint>
///         <joint name="shoulder_pitch" type="revolute">
///             <origin xyz="0.0 0.0 0.0" />
///             <parent link="elbow1" />
///             <child link="wrist1" />
///             <axis xyz="0 1 0" />
///             <limit lower="-2" upper="1.0" effort="0" velocity="1.0"/>
///         </joint>
///     </robot>
///    "##;
/// let urdf_robo = urdf_rs::read_from_string(s).unwrap();
/// println!("{:?}", urdf_robo.links[0].visual[0].origin.xyz);
/// ```

pub fn read_from_string(string: &str) -> Result<Robot> {
    let sorted_string = sort_link_joint(string)?;
    serde_xml_rs::from_str(&sorted_string).map_err(UrdfError::new)
}

#[test]
fn it_works() {
    let s = r##"
        <robot name="robo">
            <material name="blue">
              <color rgba="0.0 0.0 0.8 1.0"/>
            </material>

            <link name="shoulder1">
                <inertial>
                    <origin xyz="0 0 0.5" rpy="0 0 0"/>
                    <mass value="1"/>
                    <inertia ixx="100"  ixy="0"  ixz="0" iyy="100" iyz="0" izz="100" />
                </inertial>
                <visual>
                    <origin xyz="0.1 0.2 0.3" rpy="-0.1 -0.2  -0.3" />
                    <geometry>
                        <box size="1.0 2.0 3.0" />
                    </geometry>
                    <material name="Cyan">
                        <color rgba="0 1.0 1.0 1.0"/>
                    </material>
                </visual>
                <collision>
                    <origin xyz="0 0 0" rpy="0 0 0"/>
                    <geometry>
                        <cylinder radius="1" length="0.5"/>
                    </geometry>
                </collision>
            </link>
            <joint name="shoulder_pitch" type="revolute">
                <origin xyz="0.0 0.0 0.1" />
                <parent link="shoulder1" />
                <child link="elbow1" />
                <axis xyz="0 1 -1" />
                <limit lower="-1" upper="1.0" effort="0" velocity="1.0"/>
            </joint>
            <link name="elbow1" />
            <link name="wrist1" />
            <joint name="shoulder_pitch" type="revolute">
                <origin xyz="0.0 0.0 0.0" />
                <parent link="elbow1" />
                <child link="wrist1" />
                <axis xyz="0 1 0" />
                <limit lower="-2" upper="1.0" effort="0" velocity="1.0"/>
            </joint>
        </robot>
    "##;
    let robo = read_from_string(s).unwrap();

    assert_eq!(robo.name, "robo");
    assert_eq!(robo.links.len(), 3);
    assert_eq!(robo.joints.len(), 2);
    assert_eq!(robo.links[0].visual.len(), 1);
    let xyz = robo.links[0].visual[0].origin.xyz;
    assert_eq!(xyz[0], 0.1);
    assert_eq!(xyz[1], 0.2);
    assert_eq!(xyz[2], 0.3);
    let rpy = robo.links[0].visual[0].origin.rpy;
    assert_eq!(rpy[0], -0.1);
    assert_eq!(rpy[1], -0.2);
    assert_eq!(rpy[2], -0.3);

    match robo.links[0].visual[0].geometry {
        Geometry::Box { size } => {
            assert_eq!(size[0], 1.0f64);
            assert_eq!(size[1], 2.0f64);
            assert_eq!(size[2], 3.0f64);
        }
        _ => panic!("geometry error"),
    }
    assert_eq!(robo.materials.len(), 1);

    assert_eq!(robo.joints[0].name, "shoulder_pitch");
    let xyz = robo.joints[0].axis.xyz;
    assert_eq!(xyz[0], 0.0f64);
    assert_eq!(xyz[1], 1.0f64);
    assert_eq!(xyz[2], -1.0f64);
    let xyz = robo.joints[0].axis.xyz;
    //"0 1 -1"
    assert_eq!(xyz[0], 0.0);
    assert_eq!(xyz[1], 1.0);
    assert_eq!(xyz[2], -1.0);
}
<commit_msg>Remove needless clone<commit_after>use crate::deserialize::*;
use crate::errors::*;

use std::path::Path;

/// sort <link> and <joint> to avoid the [issue](https://github.com/RReverser/serde-xml-rs/issues/5)
fn sort_link_joint(string: &str) -> Result<String> {
    let e: xml::Element = string.parse().map_err(UrdfError::new)?;
    let mut links = Vec::new();
    let mut joints = Vec::new();
    let mut materials = Vec::new();
    for c in &e.children {
        if let xml::Xml::ElementNode(ref xml_elm) = *c {
            if xml_elm.name == "link" {
                links.push(xml::Xml::ElementNode(xml_elm.clone()));
            } else if xml_elm.name == "joint" {
                joints.push(xml::Xml::ElementNode(xml_elm.clone()));
            } else if xml_elm.name == "material" {
                materials.push(xml::Xml::ElementNode(xml_elm.clone()));
            }
        };
    }
    let mut new_elm = e;
    links.extend(joints);
    links.extend(materials);
    new_elm.children = links;
    Ok(format!("{}", new_elm))
}

/// Read urdf file and create Robot instance
///
/// # Examples
///
/// ```
/// let urdf_robo = urdf_rs::read_file("sample.urdf").unwrap();
/// let links = urdf_robo.links;
/// println!("{:?}", links[0].visual[0].origin.xyz);
/// ```
pub fn read_file<P: AsRef<Path>>(path: P) -> Result<Robot> {
    read_from_string(&std::fs::read_to_string(path)?)
}

/// Read from string instead of file.
///
///
/// # Examples
///
/// ```
/// let s = r##"
///     <robot name="robo">
///         <link name="shoulder1">
///             <inertial>
///                 <origin xyz="0 0 0.5" rpy="0 0 0"/>
///                 <mass value="1"/>
///                 <inertia ixx="100"  ixy="0"  ixz="0" iyy="100" iyz="0" izz="100" />
///             </inertial>
///             <visual>
///                 <origin xyz="0.1 0.2 0.3" rpy="-0.1 -0.2  -0.3" />
///                 <geometry>
///                     <box size="1.0 2.0 3.0" />
///                 </geometry>
///                 <material name="Cyan">
///                     <color rgba="0 1.0 1.0 1.0"/>
///                 </material>
///             </visual>
///             <collision>
///                 <origin xyz="0 0 0" rpy="0 0 0"/>
///                 <geometry>
///                     <cylinder radius="1" length="0.5"/>
///                 </geometry>
///             </collision>
///         </link>
///         <link name="elbow1" />
///         <link name="wrist1" />
///         <joint name="shoulder_pitch" type="revolute">
///             <origin xyz="0.0 0.0 0.1" />
///             <parent link="shoulder1" />
///             <child link="elbow1" />
///             <axis xyz="0 1 -1" />
///             <limit lower="-1" upper="1.0" effort="0" velocity="1.0"/>
///         </joint>
///         <joint name="shoulder_pitch" type="revolute">
///             <origin xyz="0.0 0.0 0.0" />
///             <parent link="elbow1" />
///             <child link="wrist1" />
///             <axis xyz="0 1 0" />
///             <limit lower="-2" upper="1.0" effort="0" velocity="1.0"/>
///         </joint>
///     </robot>
///    "##;
/// let urdf_robo = urdf_rs::read_from_string(s).unwrap();
/// println!("{:?}", urdf_robo.links[0].visual[0].origin.xyz);
/// ```

pub fn read_from_string(string: &str) -> Result<Robot> {
    let sorted_string = sort_link_joint(string)?;
    serde_xml_rs::from_str(&sorted_string).map_err(UrdfError::new)
}

#[test]
fn it_works() {
    let s = r##"
        <robot name="robo">
            <material name="blue">
              <color rgba="0.0 0.0 0.8 1.0"/>
            </material>

            <link name="shoulder1">
                <inertial>
                    <origin xyz="0 0 0.5" rpy="0 0 0"/>
                    <mass value="1"/>
                    <inertia ixx="100"  ixy="0"  ixz="0" iyy="100" iyz="0" izz="100" />
                </inertial>
                <visual>
                    <origin xyz="0.1 0.2 0.3" rpy="-0.1 -0.2  -0.3" />
                    <geometry>
                        <box size="1.0 2.0 3.0" />
                    </geometry>
                    <material name="Cyan">
                        <color rgba="0 1.0 1.0 1.0"/>
                    </material>
                </visual>
                <collision>
                    <origin xyz="0 0 0" rpy="0 0 0"/>
                    <geometry>
                        <cylinder radius="1" length="0.5"/>
                    </geometry>
                </collision>
            </link>
            <joint name="shoulder_pitch" type="revolute">
                <origin xyz="0.0 0.0 0.1" />
                <parent link="shoulder1" />
                <child link="elbow1" />
                <axis xyz="0 1 -1" />
                <limit lower="-1" upper="1.0" effort="0" velocity="1.0"/>
            </joint>
            <link name="elbow1" />
            <link name="wrist1" />
            <joint name="shoulder_pitch" type="revolute">
                <origin xyz="0.0 0.0 0.0" />
                <parent link="elbow1" />
                <child link="wrist1" />
                <axis xyz="0 1 0" />
                <limit lower="-2" upper="1.0" effort="0" velocity="1.0"/>
            </joint>
        </robot>
    "##;
    let robo = read_from_string(s).unwrap();

    assert_eq!(robo.name, "robo");
    assert_eq!(robo.links.len(), 3);
    assert_eq!(robo.joints.len(), 2);
    assert_eq!(robo.links[0].visual.len(), 1);
    let xyz = robo.links[0].visual[0].origin.xyz;
    assert_eq!(xyz[0], 0.1);
    assert_eq!(xyz[1], 0.2);
    assert_eq!(xyz[2], 0.3);
    let rpy = robo.links[0].visual[0].origin.rpy;
    assert_eq!(rpy[0], -0.1);
    assert_eq!(rpy[1], -0.2);
    assert_eq!(rpy[2], -0.3);

    match robo.links[0].visual[0].geometry {
        Geometry::Box { size } => {
            assert_eq!(size[0], 1.0f64);
            assert_eq!(size[1], 2.0f64);
            assert_eq!(size[2], 3.0f64);
        }
        _ => panic!("geometry error"),
    }
    assert_eq!(robo.materials.len(), 1);

    assert_eq!(robo.joints[0].name, "shoulder_pitch");
    let xyz = robo.joints[0].axis.xyz;
    assert_eq!(xyz[0], 0.0f64);
    assert_eq!(xyz[1], 1.0f64);
    assert_eq!(xyz[2], -1.0f64);
    let xyz = robo.joints[0].axis.xyz;
    //"0 1 -1"
    assert_eq!(xyz[0], 0.0);
    assert_eq!(xyz[1], 1.0);
    assert_eq!(xyz[2], -1.0);
}
<|endoftext|>


<commit_before>use std::hash::Hash;
use std::collections::{HashMap, HashSet, VecDeque};

use crate::colour::Colour;
use crate::grid::Grid;

// Represent the state of the game as a graph.  One node for each cell.  There is an edge between
// two cells if and only if they are the same colour and have a distance of 1 according to the
// Manhattan metric.
//
// The game has only one real operation (i.e. not counting level generation): Switching the colour
// of the connected component containing the top left cell to whichever colour the clicked cell
// has.  This results in said component growing by every component it neighbours which has its new
// colour.  In essence, the aim of the gaim is to join connected components until only one is
// left.  Fewer clicks is better.
//
// So, we represent the game state as a collection of connected components, each of which has a
// colour, a list of coordinates of the constituent cells, and a list of it s neighbours.  As we
// do all our operations on connected components, we actually work not with the graph of
// neighbouring cells but with a graph of connected components.  The graph of connected components
// is made up of one node representing each connected component and an edge between any two
// connected components that have cells which share an edge, i.e. two cells which would have been
// connected by an edge in the original graph if they had had the same colour (which they did
// not).

#[derive(Clone, Eq, PartialEq, Hash)]
pub struct Position {
    pub row: usize,
    pub column: usize,
}

#[derive(Clone)]
pub struct ConnectedComponent {
    counter: usize,
    pub colour: Colour,
    pub cells: HashSet<Position>,
}

impl PartialEq for ConnectedComponent {
    fn eq(&self, other: &Self) -> bool {
        self.counter == other.counter
    }
}

impl Eq for ConnectedComponent {}

impl Hash for ConnectedComponent {
    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
        self.counter.hash(state);
    }
}

pub struct Graph {
    pub size: usize,
    pub neighbours: HashMap<ConnectedComponent, HashSet<ConnectedComponent>>,
}

fn find_connected_components(grid: &Grid) -> Vec<(ConnectedComponent, HashSet<usize>)> {
    let rows = grid.number_of_rows;
    let columns = grid.number_of_columns;

    let mut remaining_cells: HashSet<usize> = (0..grid.cells.len()).into_iter().collect();

    let mut components = vec![];
    let mut counter = 0;

    // Take any element to land in any component.
    while let Some(&start_cell_index) = remaining_cells.iter().next() {
        let mut visited = HashSet::new();
        let mut neighbours = HashSet::new();
        let mut queue = VecDeque::new();

        queue.push_back(start_cell_index);

        // Gather all cells in the connected component of start_cell_index.
        while let Some(i) = queue.pop_front() {
            visited.insert(i);
            remaining_cells.remove(&i);

            let mut neighbouring_cells = vec![];
            if i % columns > 0 {
                neighbouring_cells.push(i - 1);
            }
            if i % columns < columns - 1 {
                neighbouring_cells.push(i + 1);
            }
            if i >= columns {
                neighbouring_cells.push(i - columns)
            }
            if i < (rows - 1 ) * columns {
                neighbouring_cells.push(i + columns)
            }

            for neighbour in neighbouring_cells {
                if visited.contains(&neighbour) {
                    continue
                }

                if grid.cells[i] == grid.cells[neighbour] {
                    queue.push_back(neighbour);
                } else {
                    neighbours.insert(neighbour);
                }
            }
        }

        let cells = visited
            .iter()
            .map(|&i| Position {
                column: i % columns,
                row: i / columns,
            })
            .collect();

        let component = ConnectedComponent {
            counter,
            colour: grid.cells[*visited.iter().next().unwrap()],
            cells,
        };
        counter += 1;

        components.push((component, neighbours));
    }

    return components
}

impl Graph {
    pub fn create(grid: &Grid) -> Self {
        let components_and_neighbours = find_connected_components(&grid);

        let map_cell_to_component: HashMap<Position, ConnectedComponent> = components_and_neighbours
        .iter()
        .flat_map(|(component, _)| {
            component.cells
            .iter()
            .map(|cell| (cell.clone(), component.clone()))
            .collect::<Vec<(Position, ConnectedComponent)>>()
        })
        .collect();

        let mut neighbours:  HashMap<ConnectedComponent, HashSet<ConnectedComponent>> = HashMap::new();

        for (component, neighbour_cells) in components_and_neighbours {
            let mut neighbour_components: HashSet<ConnectedComponent> = HashSet::new();

            for cell in neighbour_cells {
                let position = Position{column: cell % grid.number_of_columns, row: cell / grid.number_of_columns};
                neighbour_components.insert(map_cell_to_component[&position].clone());
            }

            neighbours.insert(component, neighbour_components);
        }

        Self {
             size: grid.number_of_columns,
             neighbours
        }
    }

    fn to_grid(&self, rows: usize, columns: usize) -> Grid {
        let mut cells = vec![Colour::Red; rows * columns];

        for component in self.neighbours.keys() {
            for position in &component.cells {
                cells[position.column + position.row * columns] = component.colour;
            }
        }

        Grid { number_of_rows: rows, number_of_columns: columns, cells, }
    }

    pub fn find_component(&self, position: Position) -> &ConnectedComponent {
        for component in self.neighbours.keys() {
            if component.cells.contains(&position) {
                return component
            }
        }

        unreachable!()
    }
}

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

    #[test]
    fn should_return_same_grid_as_input() {
        let size = 4;
        let grid = Grid::generate(size);

        let graph = Graph::create(&grid);
        let reconstituted_grid = graph.to_grid(size, size);

        assert_eq!(reconstituted_grid, grid);
    }

    #[test]
    fn should_have_one_component() {
        let grid = Grid{
            number_of_columns: 2,
             number_of_rows: 2,
             cells: vec![Colour::Red; 4]
        };

        let graph = Graph::create(&grid);

        assert_eq!(graph.neighbours.len(), 1);
    }

    #[test]
    fn should_have_four_component() {
        let grid = Grid{
            number_of_columns: 2,
             number_of_rows: 2,
             cells: vec![Colour::Red, Colour::Yellow, Colour::Yellow, Colour::Red]
        };

        let graph = Graph::create(&grid);

        assert_eq!(graph.neighbours.len(), 4);
    }

    #[test]
    fn should_have_two_component() {
        let grid = Grid{
            number_of_columns: 2,
             number_of_rows: 2,
             cells: vec![Colour::Red, Colour::Red, Colour::Yellow, Colour::Yellow]
        };

        let graph = Graph::create(&grid);

        assert_eq!(graph.neighbours.len(), 2);
    }
}
<commit_msg>Remove unused field size<commit_after>use std::hash::Hash;
use std::collections::{HashMap, HashSet, VecDeque};

use crate::colour::Colour;
use crate::grid::Grid;

// Represent the state of the game as a graph.  One node for each cell.  There is an edge between
// two cells if and only if they are the same colour and have a distance of 1 according to the
// Manhattan metric.
//
// The game has only one real operation (i.e. not counting level generation): Switching the colour
// of the connected component containing the top left cell to whichever colour the clicked cell
// has.  This results in said component growing by every component it neighbours which has its new
// colour.  In essence, the aim of the gaim is to join connected components until only one is
// left.  Fewer clicks is better.
//
// So, we represent the game state as a collection of connected components, each of which has a
// colour, a list of coordinates of the constituent cells, and a list of it s neighbours.  As we
// do all our operations on connected components, we actually work not with the graph of
// neighbouring cells but with a graph of connected components.  The graph of connected components
// is made up of one node representing each connected component and an edge between any two
// connected components that have cells which share an edge, i.e. two cells which would have been
// connected by an edge in the original graph if they had had the same colour (which they did
// not).

#[derive(Clone, Eq, PartialEq, Hash)]
pub struct Position {
    pub row: usize,
    pub column: usize,
}

#[derive(Clone)]
pub struct ConnectedComponent {
    counter: usize,
    pub colour: Colour,
    pub cells: HashSet<Position>,
}

impl PartialEq for ConnectedComponent {
    fn eq(&self, other: &Self) -> bool {
        self.counter == other.counter
    }
}

impl Eq for ConnectedComponent {}

impl Hash for ConnectedComponent {
    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
        self.counter.hash(state);
    }
}

pub struct Graph {
    pub neighbours: HashMap<ConnectedComponent, HashSet<ConnectedComponent>>,
}

fn find_connected_components(grid: &Grid) -> Vec<(ConnectedComponent, HashSet<usize>)> {
    let rows = grid.number_of_rows;
    let columns = grid.number_of_columns;

    let mut remaining_cells: HashSet<usize> = (0..grid.cells.len()).into_iter().collect();

    let mut components = vec![];
    let mut counter = 0;

    // Take any element to land in any component.
    while let Some(&start_cell_index) = remaining_cells.iter().next() {
        let mut visited = HashSet::new();
        let mut neighbours = HashSet::new();
        let mut queue = VecDeque::new();

        queue.push_back(start_cell_index);

        // Gather all cells in the connected component of start_cell_index.
        while let Some(i) = queue.pop_front() {
            visited.insert(i);
            remaining_cells.remove(&i);

            let mut neighbouring_cells = vec![];
            if i % columns > 0 {
                neighbouring_cells.push(i - 1);
            }
            if i % columns < columns - 1 {
                neighbouring_cells.push(i + 1);
            }
            if i >= columns {
                neighbouring_cells.push(i - columns)
            }
            if i < (rows - 1 ) * columns {
                neighbouring_cells.push(i + columns)
            }

            for neighbour in neighbouring_cells {
                if visited.contains(&neighbour) {
                    continue
                }

                if grid.cells[i] == grid.cells[neighbour] {
                    queue.push_back(neighbour);
                } else {
                    neighbours.insert(neighbour);
                }
            }
        }

        let cells = visited
            .iter()
            .map(|&i| Position {
                column: i % columns,
                row: i / columns,
            })
            .collect();

        let component = ConnectedComponent {
            counter,
            colour: grid.cells[*visited.iter().next().unwrap()],
            cells,
        };
        counter += 1;

        components.push((component, neighbours));
    }

    return components
}

impl Graph {
    pub fn create(grid: &Grid) -> Self {
        let components_and_neighbours = find_connected_components(&grid);

        let map_cell_to_component: HashMap<Position, ConnectedComponent> = components_and_neighbours
        .iter()
        .flat_map(|(component, _)| {
            component.cells
            .iter()
            .map(|cell| (cell.clone(), component.clone()))
            .collect::<Vec<(Position, ConnectedComponent)>>()
        })
        .collect();

        let mut neighbours:  HashMap<ConnectedComponent, HashSet<ConnectedComponent>> = HashMap::new();

        for (component, neighbour_cells) in components_and_neighbours {
            let mut neighbour_components: HashSet<ConnectedComponent> = HashSet::new();

            for cell in neighbour_cells {
                let position = Position{column: cell % grid.number_of_columns, row: cell / grid.number_of_columns};
                neighbour_components.insert(map_cell_to_component[&position].clone());
            }

            neighbours.insert(component, neighbour_components);
        }

        Self {
             neighbours
        }
    }

    fn to_grid(&self, rows: usize, columns: usize) -> Grid {
        let mut cells = vec![Colour::Red; rows * columns];

        for component in self.neighbours.keys() {
            for position in &component.cells {
                cells[position.column + position.row * columns] = component.colour;
            }
        }

        Grid { number_of_rows: rows, number_of_columns: columns, cells, }
    }

    pub fn find_component(&self, position: Position) -> &ConnectedComponent {
        for component in self.neighbours.keys() {
            if component.cells.contains(&position) {
                return component
            }
        }

        unreachable!()
    }
}

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

    #[test]
    fn should_return_same_grid_as_input() {
        let size = 4;
        let grid = Grid::generate(size);

        let graph = Graph::create(&grid);
        let reconstituted_grid = graph.to_grid(size, size);

        assert_eq!(reconstituted_grid, grid);
    }

    #[test]
    fn should_have_one_component() {
        let grid = Grid{
            number_of_columns: 2,
             number_of_rows: 2,
             cells: vec![Colour::Red; 4]
        };

        let graph = Graph::create(&grid);

        assert_eq!(graph.neighbours.len(), 1);
    }

    #[test]
    fn should_have_four_component() {
        let grid = Grid{
            number_of_columns: 2,
             number_of_rows: 2,
             cells: vec![Colour::Red, Colour::Yellow, Colour::Yellow, Colour::Red]
        };

        let graph = Graph::create(&grid);

        assert_eq!(graph.neighbours.len(), 4);
    }

    #[test]
    fn should_have_two_component() {
        let grid = Grid{
            number_of_columns: 2,
             number_of_rows: 2,
             cells: vec![Colour::Red, Colour::Red, Colour::Yellow, Colour::Yellow]
        };

        let graph = Graph::create(&grid);

        assert_eq!(graph.neighbours.len(), 2);
    }
}
<|endoftext|>


<commit_before>use std::collections::{HashMap, HashSet, VecDeque};
use std::hash::Hash;

use crate::colour::Colour;
use crate::grid::Grid;

// Represent the state of the game as a graph.  One node for each cell.  There is an edge between
// two cells if and only if they are the same colour and have a distance of 1 according to the
// Manhattan metric.
//
// The game has only one real operation (i.e. not counting level generation): Switching the colour
// of the connected component containing the top left cell to whichever colour the clicked cell
// has.  This results in said component growing by every component it neighbours which has its new
// colour.  In essence, the aim of the gaim is to join connected components until only one is
// left.  Fewer clicks is better.
//
// So, we represent the game state as a collection of connected components, each of which has a
// colour, a list of coordinates of the constituent cells, and a list of it s neighbours.  As we
// do all our operations on connected components, we actually work not with the graph of
// neighbouring cells but with a graph of connected components.  The graph of connected components
// is made up of one node representing each connected component and an edge between any two
// connected components that have cells which share an edge, i.e. two cells which would have been
// connected by an edge in the original graph if they had had the same colour (which they did
// not).

#[derive(Debug, Clone, Eq, PartialEq, Hash)]
pub struct Position {
    pub row: usize,
    pub column: usize,
}

#[derive(Debug, Clone)]
pub struct ConnectedComponent {
    id: usize,
    pub colour: Colour,
    pub cells: HashSet<Position>,
}

impl PartialEq for ConnectedComponent {
    fn eq(&self, other: &Self) -> bool {
        self.id == other.id
    }
}

impl Eq for ConnectedComponent {}

impl Hash for ConnectedComponent {
    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
        self.id.hash(state);
    }
}

#[derive(Debug)]
pub struct Graph {
    pub components: HashMap<usize, ConnectedComponent>,
    pub neighbours: HashMap<usize, HashSet<usize>>,
}

fn find_connected_components(grid: &Grid) -> Vec<(ConnectedComponent, HashSet<usize>)> {
    let rows = grid.number_of_rows;
    let columns = grid.number_of_columns;

    let mut remaining_cells: HashSet<usize> = (0..grid.cells.len()).into_iter().collect();

    let mut components = vec![];
    let mut counter = 0;

    // Take any element to land in any component.
    while let Some(&start_cell_index) = remaining_cells.iter().next() {
        let mut visited = HashSet::new();
        let mut neighbours = HashSet::new();
        let mut queue = VecDeque::new();

        queue.push_back(start_cell_index);

        // Gather all cells in the connected component of start_cell_index.
        while let Some(i) = queue.pop_front() {
            visited.insert(i);
            remaining_cells.remove(&i);

            let mut neighbouring_cells = vec![];
            if i % columns > 0 {
                neighbouring_cells.push(i - 1);
            }
            if i % columns < columns - 1 {
                neighbouring_cells.push(i + 1);
            }
            if i >= columns {
                neighbouring_cells.push(i - columns)
            }
            if i < (rows - 1) * columns {
                neighbouring_cells.push(i + columns)
            }

            for neighbour in neighbouring_cells {
                if visited.contains(&neighbour) {
                    continue;
                }

                if grid.cells[i] == grid.cells[neighbour] {
                    queue.push_back(neighbour);
                } else {
                    neighbours.insert(neighbour);
                }
            }
        }

        let cells = visited
            .iter()
            .map(|&i| Position {
                column: i % columns,
                row: i / columns,
            })
            .collect();

        let component = ConnectedComponent {
            id: counter,
            colour: grid.cells[*visited.iter().next().unwrap()],
            cells,
        };
        counter += 1;

        components.push((component, neighbours));
    }

    return components;
}

impl Graph {
    pub fn create(grid: &Grid) -> Self {
        let components_and_neighbours = find_connected_components(&grid);

        let mut components = HashMap::with_capacity(components_and_neighbours.len());
        let mut neighbours: HashMap<usize, HashSet<usize>> = HashMap::new();

        for (c, n) in components_and_neighbours.into_iter() {
            let id = c.id;
            components.insert(id, c);
            neighbours.insert(id, n);
        }

        Self {
            components,
            neighbours
        }
    }

    fn to_grid(&self, rows: usize, columns: usize) -> Grid {
        let mut cells = vec![Colour::Red; rows * columns];

        for component in self.neighbours.keys() {
            for position in &self.components[component].cells {
                cells[position.column + position.row * columns] = self.components[component].colour;
            }
        }

        Grid {
            number_of_rows: rows,
            number_of_columns: columns,
            cells,
        }
    }

    pub fn find_component(&self, position: &Position) -> &ConnectedComponent {
        for component in self.neighbours.keys() {
            if self.components[component].cells.contains(&position) {
                return &self.components[component];
            }
        }

        unreachable!()
    }
}

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

    #[test]
    fn should_return_same_grid_as_input() {
        let size = 4;
        let grid = Grid::generate(size);

        let graph = Graph::create(&grid);
        let reconstituted_grid = graph.to_grid(size, size);

        assert_eq!(reconstituted_grid, grid);
    }

    #[test]
    fn should_have_one_component() {
        let grid = Grid {
            number_of_columns: 2,
            number_of_rows: 2,
            cells: vec![Colour::Red; 4],
        };

        let graph = Graph::create(&grid);

        assert_eq!(graph.neighbours.len(), 1);
    }

    #[test]
    fn should_have_four_component() {
        let grid = Grid {
            number_of_columns: 2,
            number_of_rows: 2,
            cells: vec![Colour::Red, Colour::Yellow, Colour::Yellow, Colour::Red],
        };

        let graph = Graph::create(&grid);

        assert_eq!(graph.neighbours.len(), 4);
    }

    #[test]
    fn should_have_two_component() {
        let grid = Grid {
            number_of_columns: 2,
            number_of_rows: 2,
            cells: vec![Colour::Red, Colour::Red, Colour::Yellow, Colour::Yellow],
        };

        let graph = Graph::create(&grid);

        assert_eq!(graph.neighbours.len(), 2);
    }

    #[test]
    fn should_have_same_keys_for_components_and_neighbours_maps() {
        let size = 4;
        let grid = Grid::generate(size);

        let graph = Graph::create(&grid);

        let components_keys: HashSet<_> = graph.components.keys().collect();
        let neighbours_keys: HashSet<_> = graph.neighbours.keys().collect();
        assert_eq!(components_keys, neighbours_keys);
    }

    #[test]
    fn should_contain_exactly_the_component_ids_as_keys() {
        let size = 4;
        let grid = Grid::generate(size);

        let graph = Graph::create(&grid);

        let component_keys: HashSet<_> = graph.components.keys().collect();
        let component_ids: HashSet<_> = graph.components.values().map(|x| &x.id).collect();
        assert_eq!(component_keys, component_ids);

        for (id, component) in graph.components {
            assert_eq!(id, component.id);
        }
    }
}
<commit_msg>Fix initialization of neighbours map in Graph<commit_after>use std::collections::{HashMap, HashSet, VecDeque};
use std::hash::Hash;

use crate::colour::Colour;
use crate::grid::Grid;

// Represent the state of the game as a graph.  One node for each cell.  There is an edge between
// two cells if and only if they are the same colour and have a distance of 1 according to the
// Manhattan metric.
//
// The game has only one real operation (i.e. not counting level generation): Switching the colour
// of the connected component containing the top left cell to whichever colour the clicked cell
// has.  This results in said component growing by every component it neighbours which has its new
// colour.  In essence, the aim of the gaim is to join connected components until only one is
// left.  Fewer clicks is better.
//
// So, we represent the game state as a collection of connected components, each of which has a
// colour, a list of coordinates of the constituent cells, and a list of it s neighbours.  As we
// do all our operations on connected components, we actually work not with the graph of
// neighbouring cells but with a graph of connected components.  The graph of connected components
// is made up of one node representing each connected component and an edge between any two
// connected components that have cells which share an edge, i.e. two cells which would have been
// connected by an edge in the original graph if they had had the same colour (which they did
// not).

#[derive(Debug, Clone, Eq, PartialEq, Hash)]
pub struct Position {
    pub row: usize,
    pub column: usize,
}

#[derive(Debug, Clone)]
pub struct ConnectedComponent {
    id: usize,
    pub colour: Colour,
    pub cells: HashSet<Position>,
}

impl PartialEq for ConnectedComponent {
    fn eq(&self, other: &Self) -> bool {
        self.id == other.id
    }
}

impl Eq for ConnectedComponent {}

impl Hash for ConnectedComponent {
    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
        self.id.hash(state);
    }
}

#[derive(Debug)]
pub struct Graph {
    pub components: HashMap<usize, ConnectedComponent>,
    pub neighbours: HashMap<usize, HashSet<usize>>,
}

fn find_connected_components(grid: &Grid) -> Vec<(ConnectedComponent, HashSet<usize>)> {
    let rows = grid.number_of_rows;
    let columns = grid.number_of_columns;

    let mut remaining_cells: HashSet<usize> = (0..grid.cells.len()).into_iter().collect();

    let mut components = vec![];
    let mut counter = 0;

    // Take any element to land in any component.
    while let Some(&start_cell_index) = remaining_cells.iter().next() {
        let mut visited = HashSet::new();
        let mut neighbours = HashSet::new();
        let mut queue = VecDeque::new();

        queue.push_back(start_cell_index);

        // Gather all cells in the connected component of start_cell_index.
        while let Some(i) = queue.pop_front() {
            visited.insert(i);
            remaining_cells.remove(&i);

            let mut neighbouring_cells = vec![];
            if i % columns > 0 {
                neighbouring_cells.push(i - 1);
            }
            if i % columns < columns - 1 {
                neighbouring_cells.push(i + 1);
            }
            if i >= columns {
                neighbouring_cells.push(i - columns)
            }
            if i < (rows - 1) * columns {
                neighbouring_cells.push(i + columns)
            }

            for neighbour in neighbouring_cells {
                if visited.contains(&neighbour) {
                    continue;
                }

                if grid.cells[i] == grid.cells[neighbour] {
                    queue.push_back(neighbour);
                } else {
                    neighbours.insert(neighbour);
                }
            }
        }

        let cells = visited
            .iter()
            .map(|&i| Position {
                column: i % columns,
                row: i / columns,
            })
            .collect();

        let component = ConnectedComponent {
            id: counter,
            colour: grid.cells[*visited.iter().next().unwrap()],
            cells,
        };
        counter += 1;

        components.push((component, neighbours));
    }

    return components;
}

impl Graph {
    pub fn create(grid: &Grid) -> Self {
        let components_and_neighbours = find_connected_components(&grid);

        let map_cell_to_component: HashMap<Position, ConnectedComponent> =
            components_and_neighbours
                .iter()
                .flat_map(|(component, _)| {
                    component
                        .cells
                        .iter()
                        .map(|cell| (cell.clone(), component.clone()))
                        .collect::<Vec<(Position, ConnectedComponent)>>()
                })
                .collect();

        let mut neighbours: HashMap<usize, HashSet<usize>> = HashMap::new();

        for (component, neighbour_cells) in &components_and_neighbours {
            let mut neighbour_components = HashSet::new();

            for cell in neighbour_cells {
                let position = Position {
                    column: cell % grid.number_of_columns,
                    row: cell / grid.number_of_columns,
                };
                neighbour_components.insert(map_cell_to_component[&position].id);
            }
            neighbours.insert(component.id, neighbour_components);
        }

        let mut components = HashMap::with_capacity(components_and_neighbours.len());

        for (c, n) in components_and_neighbours.into_iter() {
            components.insert(c.id, c);
        }

        Self {
            components,
            neighbours
        }
    }

    fn to_grid(&self, rows: usize, columns: usize) -> Grid {
        let mut cells = vec![Colour::Red; rows * columns];

        for component in self.neighbours.keys() {
            for position in &self.components[component].cells {
                cells[position.column + position.row * columns] = self.components[component].colour;
            }
        }

        Grid {
            number_of_rows: rows,
            number_of_columns: columns,
            cells,
        }
    }

    pub fn find_component(&self, position: &Position) -> &ConnectedComponent {
        for component in self.neighbours.keys() {
            if self.components[component].cells.contains(&position) {
                return &self.components[component];
            }
        }

        unreachable!()
    }
}

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

    #[test]
    fn should_return_same_grid_as_input() {
        let size = 4;
        let grid = Grid::generate(size);

        let graph = Graph::create(&grid);
        let reconstituted_grid = graph.to_grid(size, size);

        assert_eq!(reconstituted_grid, grid);
    }

    #[test]
    fn should_have_one_component() {
        let grid = Grid {
            number_of_columns: 2,
            number_of_rows: 2,
            cells: vec![Colour::Red; 4],
        };

        let graph = Graph::create(&grid);

        assert_eq!(graph.neighbours.len(), 1);
    }

    #[test]
    fn should_have_four_component() {
        let grid = Grid {
            number_of_columns: 2,
            number_of_rows: 2,
            cells: vec![Colour::Red, Colour::Yellow, Colour::Yellow, Colour::Red],
        };

        let graph = Graph::create(&grid);

        assert_eq!(graph.neighbours.len(), 4);
    }

    #[test]
    fn should_have_two_component() {
        let grid = Grid {
            number_of_columns: 2,
            number_of_rows: 2,
            cells: vec![Colour::Red, Colour::Red, Colour::Yellow, Colour::Yellow],
        };

        let graph = Graph::create(&grid);

        assert_eq!(graph.neighbours.len(), 2);
    }

    #[test]
    fn should_have_same_keys_for_components_and_neighbours_maps() {
        let size = 4;
        let grid = Grid::generate(size);

        let graph = Graph::create(&grid);

        let components_keys: HashSet<_> = graph.components.keys().collect();
        let neighbours_keys: HashSet<_> = graph.neighbours.keys().collect();
        assert_eq!(components_keys, neighbours_keys);
    }

    #[test]
    fn should_contain_exactly_the_component_ids_as_keys() {
        let size = 4;
        let grid = Grid::generate(size);

        let graph = Graph::create(&grid);

        let component_keys: HashSet<_> = graph.components.keys().collect();
        let component_ids: HashSet<_> = graph.components.values().map(|x| &x.id).collect();
        assert_eq!(component_keys, component_ids);

        for (id, component) in graph.components {
            assert_eq!(id, component.id);
        }
    }
}
<|endoftext|>


<commit_before>use std::iter::repeat;
use std::collections::VecDeque;

fn max(a: u32, b: u32) -> u32 { if a > b { a } else { b } }

#[derive(Clone)]
struct Edge {
    vertex: u32,
    weight: f32,
}

impl Edge {
    pub fn new(vertex_: u32, weight_: f32) -> Edge {
        Edge{vertex: vertex_, weight: weight_,}
    }
}

struct Graph {
    nodes: Vec<Vec<Edge>>,
}

impl Graph {
    pub fn new() -> Graph { Graph{nodes: Vec::new(),} }

    pub fn add_edge(&mut self, src: u32, dst: u32, weight: f32) {
        let len = self.nodes.len();
        if (max(src, dst)) > len as u32 {
            let new_len = (max(src, dst) + 1) as usize;
            self.nodes.extend(repeat(Vec::new()).take(new_len - len))
        }
        self.nodes[src as usize].push(Edge::new(dst, weight));
    }
    pub fn bfs(&self, src: u32) {
        let mut queue: VecDeque<u32> = VecDeque::new();
        let len = self.nodes.len();
        let mut visited = vec!(false ; len);
        queue.push_front(src);
        while let Some(current) = queue.pop_back() {
            if !visited[current as usize] {
                println!("current: {}" , current);
                visited[current as usize] = true;
            } else { continue ; }

            for n in &self.nodes[current as usize] {
                let neighbor: u32 = n.vertex;
                queue.push_front(neighbor);
            }
        }
    }
    pub fn dfs(&self, src: u32) {
        let mut stack: Vec<u32> = Vec::new();
        let len = self.nodes.len() as usize;
        let mut visited = vec!(false ; len);
        stack.push(src);
        while let Some(current) = stack.pop() {
            if !visited[current as usize] {
                println!("current: {}" , current);
                visited[current as usize] = true;
            } else { continue ; }

            for n in &self.nodes[current as usize] {
                let neighbor: u32 = n.vertex;
                stack.push(neighbor);
            }
        }
    }
}

fn main() {
    let mut g1 = Graph::new();
    g1.add_edge(0, 1, 1.0);
    g1.add_edge(0, 2, 4.0);
    g1.add_edge(1, 0, 1.0);
    g1.add_edge(1, 2, 2.0);
    g1.add_edge(1, 3, 6.0);
    g1.add_edge(2, 0, 4.0);
    g1.add_edge(2, 1, 2.0);
    g1.add_edge(2, 3, 3.0);
    g1.add_edge(3, 1, 6.0);
    g1.add_edge(3, 2, 3.0);
    g1.bfs(3);
    println!("\n");
    g1.dfs(3);
}<commit_msg>added dijkstra<commit_after>use std::iter::repeat;
use std::collections::VecDeque;
use std::collections::BinaryHeap;
use std::cmp::Ordering;

fn max(a: u32, b: u32) -> u32 { if a > b { a } else { b } }

#[derive(Clone, PartialEq, Eq)]
struct Edge {
    vertex: u32,
    weight: f32,
}

impl Edge {
    pub fn new(vertex_: u32, weight_: f32) -> Edge {
        Edge{vertex: vertex_, weight: weight_,}
    }
}

impl Ord for Edge {
    fn cmp(&self, other: &Self) -> Ordering {
        (self.weight, &self.vertex).cmp(&(other.weight, &other.vertex))
    }
}

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

struct Graph {
    nodes: Vec<Vec<Edge>>,
}

impl Graph {
    pub fn new() -> Graph { Graph{nodes: Vec::new(),} }

    pub fn add_edge(&mut self, src: u32, dst: u32, weight: f32) {
        let len = self.nodes.len();

        if (max(src, dst)) > len as u32 {
            let new_len = (max(src, dst) + 1) as usize;
            self.nodes.extend(repeat(Vec::new()).take(new_len - len))
        }
        self.nodes[src as usize].push(Edge::new(dst, weight));
    }
    pub fn bfs(&self, src: u32) {
        let mut queue: VecDeque<u32> = VecDeque::new();
        let len = self.nodes.len();
        let mut visited = vec!(false ; len);

        queue.push_front(src);

        while let Some(current) = queue.pop_back() {
            if !visited[current as usize] {
                println!("current: {}" , current);
                visited[current as usize] = true;
            } else { continue ; }

            for n in &self.nodes[current as usize] {
                let neighbor: u32 = n.vertex;
                queue.push_front(neighbor);
            }
        }
    }
    pub fn dfs(&self, src: u32) {
        let mut stack: Vec<u32> = Vec::new();
        let len = self.nodes.len() as usize;
        let mut visited = vec!(false ; len);

        stack.push(src);

        while let Some(current) = stack.pop() {
            if !visited[current as usize] {
                println!("current: {}" , current);
                visited[current as usize] = true;
            } else { continue ; }

            for n in &self.nodes[current as usize] {
                let neighbor: u32 = n.vertex;
                stack.push(neighbor);
            }
        }
    }

    pub fn dijkstra(&self, src: u32, dst: u32) {
      let mut dist: Vec<f32> = Vec::new();
      let mut prev: Vec<u32> = Vec::new();
      let mut q = BinaryHeap::new();
      const max_weight: f32 = std::f32::MAX;

      // init dist, prev table
      for i in 0..self.nodes.len() {
        dist.push(max_weight);
        prev.push(0);
      }

      // We're at `start`, with a zero cost
      dist[src as usize] = 0.0;
      q.push(Edge::new(src, dist[src as usize]));

      //while (!q.is_empty()) {
      while let Some(u) = q.pop() {
        //let u: Edge = el.unwrap();

        // loop for all edges connected to
        for v in self.nodes[u.vertex as usize].iter() {

          let alt: f32 = dist[u.vertex as usize] + v.weight; // accumulate shortest dist from source

          if (alt < dist[v.vertex as usize]) {
            dist[v.vertex as usize] = alt; // keep the shortest dist from src to v
            prev[v.vertex as usize] = u.vertex;

            q.push(Edge::new(v.vertex, dist[v.vertex as usize])); // Add unvisited v into the Q to be processed
          }
        }
      }

      let mut shortestPath: Vec<u32> = Vec::new();
      let mut curr: u32 = dst;

      shortestPath.push(curr);

      while (curr != src) {
        curr = prev[curr as usize];
        shortestPath.push(curr);
      }

      shortestPath.reverse();

      for v in shortestPath.iter() {
        println!("{}", v);
      }
    }
}

fn main() {
    let mut g1 = Graph::new();
    g1.add_edge(0, 1, 1.0);
    g1.add_edge(0, 2, 4.0);
    g1.add_edge(1, 0, 1.0);
    g1.add_edge(1, 2, 2.0);
    g1.add_edge(1, 3, 6.0);
    g1.add_edge(2, 0, 4.0);
    g1.add_edge(2, 1, 2.0);
    g1.add_edge(2, 3, 3.0);
    g1.add_edge(3, 1, 6.0);
    g1.add_edge(3, 2, 3.0);

    g1.bfs(3);

    println!("\n");

    g1.dfs(3);

    g1.dijkstra(0, 2);
}<|endoftext|>


<commit_before>// Copyright 2017 PingCAP, Inc.
//
// 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,
// See the License for the specific language governing permissions and
// limitations under the License.

#![allow(dead_code, unused_imports)]

extern crate gcc;
extern crate cmake;
extern crate pkg_config;

use std::path::Path;
use std::process::Command;

const GRPC_VERSION: &'static str = "1.2.5";
const ZLIB_VERSION: &'static str = "1.2.8";
const BORINGSSL_GIT_HASH: &'static str = "78684e5b222645828ca302e56b40b9daff2b2d27";

#[cfg(not(feature = "static-link"))]
fn build_or_link_grpc(cc: &mut gcc::Config) {
    if let Ok(lib) = pkg_config::Config::new().atleast_version(GRPC_VERSION).statik(true).probe("grpc_unsecure") {
        for inc_path in &lib.include_paths {
            cc.include(inc_path);
        }
        return;
    }
}

fn wget(url: &str, out: &str) -> Result<(), String> {
    Command::new("wget").args(&["-q", "-c", "-O", out, url])
        .status()
        .map_err(|err| format!("wget execute failed: {}", err))
        .and_then(|status| {
            if status.success() {
                Ok(())
            } else {
                Err(format!("wget exit with {}", status))
            }
        })
}

fn tar_xf(file: &str) -> Result<(), String> {
    Command::new("tar").args(&["zxf", file])
        .status()
        .map_err(|err| format!("tar execute failed: {}", err))
        .and_then(|status| {
            if status.success() {
                Ok(())
            } else {
                Err(format!("tar exit with {}", status))
            }
        })
}

#[cfg(feature = "static-link")]
fn build_or_link_grpc(cc: &mut gcc::Config) {
    if !Path::new(&format!("grpc-{}", GRPC_VERSION)).exists() {
        wget(&format!("https://github.com/grpc/grpc/archive/v{}.tar.gz", GRPC_VERSION),
             "grpc.tar.gz")
            .and_then(|_| tar_xf("grpc.tar.gz"))
            .unwrap();
    }

    if !Path::new(&format!("zlib-{}", ZLIB_VERSION)).exists() {
        wget(&format!("https://github.com/madler/zlib/archive/v{}.tar.gz", ZLIB_VERSION),
             "zlib.tar.gz")
            .and_then(|_| tar_xf("zlib.tar.gz"))
            .unwrap();
    }

    if !Path::new(&format!("boringssl-{}", BORINGSSL_GIT_HASH)).exists() {
        wget(&format!("https://github.com/google/boringssl/archive/{}.tar.gz", BORINGSSL_GIT_HASH),
             "boringssl.tar.gz")
            .and_then(|_| tar_xf("boringssl.tar.gz"))
            .unwrap();
    }

    let dst = cmake::Config::new(format!("zlib-{}", ZLIB_VERSION))
        .build();

    println!("cargo:rustc-link-search=native={}/lib", dst.display());

    let dst = cmake::Config::new(format!("grpc-{}", GRPC_VERSION))
        .define("ZLIB_ROOT_DIR", format!("../zlib-{}", ZLIB_VERSION)) // relative to grpc dir
        .define("BORINGSSL_ROOT_DIR", format!("../boringssl-{}", BORINGSSL_GIT_HASH))
        .build_target("grpc_unsecure")
        .build();

    cc.include(format!("grpc-{}/include", GRPC_VERSION));

    println!("cargo:rustc-link-search=native={}/build", dst.display());
    println!("cargo:rustc-link-search=native={}/build/third_party/zlib", dst.display());

    println!("cargo:rustc-link-lib=static=z");
    println!("cargo:rustc-link-lib=static=gpr");
    println!("cargo:rustc-link-lib=static=grpc_unsecure");
}

fn main() {
    println!("cargo:rerun-if-changed=build.rs");

    let mut cc = gcc::Config::new();

    build_or_link_grpc(&mut cc);

    cc.file("grpc_wrap.c")
        .flag("-fPIC")
        .flag("-O2")
        .compile("libgrpc_wrap.a");
}
<commit_msg>*: run rustfmt<commit_after>// Copyright 2017 PingCAP, Inc.
//
// 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,
// See the License for the specific language governing permissions and
// limitations under the License.

#![allow(dead_code, unused_imports)]

extern crate gcc;
extern crate cmake;
extern crate pkg_config;

use std::path::Path;
use std::process::Command;

const GRPC_VERSION: &'static str = "1.2.5";
const ZLIB_VERSION: &'static str = "1.2.8";
const BORINGSSL_GIT_HASH: &'static str = "78684e5b222645828ca302e56b40b9daff2b2d27";

#[cfg(not(feature = "static-link"))]
fn build_or_link_grpc(cc: &mut gcc::Config) {
    if let Ok(lib) = pkg_config::Config::new()
        .atleast_version(GRPC_VERSION)
        .statik(true)
        .probe("grpc_unsecure") {
        for inc_path in lib.include_paths {
            cc.include(inc_path);
        }
    } else {
        panic!("can't find dynamic grpc library");
    }
}

#[cfg(feature = "static-link")]
fn build_or_link_grpc(cc: &mut gcc::Config) {
    fn wget(url: &str, out: &str) -> Result<(), String> {
        Command::new("wget")
            .args(&["-q", "-c", "-O", out, url])
            .status()
            .map_err(|err| format!("wget execute failed: {}", err))
            .and_then(|status| {
                if status.success() {
                    Ok(())
                } else {
                    Err(format!("wget exit with {}", status))
                }
            })
    }

    fn tar_xf(file: &str) -> Result<(), String> {
        Command::new("tar")
            .args(&["zxf", file])
            .status()
            .map_err(|err| format!("tar execute failed: {}", err))
            .and_then(|status| {
                if status.success() {
                    Ok(())
                } else {
                    Err(format!("tar exit with {}", status))
                }
            })
    }

    if !Path::new(&format!("grpc-{}", GRPC_VERSION)).exists() {
        wget(&format!("https://github.com/grpc/grpc/archive/v{}.tar.gz",
                      GRPC_VERSION),
             "grpc.tar.gz")
            .and_then(|_| tar_xf("grpc.tar.gz"))
            .unwrap();
    }

    if !Path::new(&format!("zlib-{}", ZLIB_VERSION)).exists() {
        wget(&format!("https://github.com/madler/zlib/archive/v{}.tar.gz",
                      ZLIB_VERSION),
             "zlib.tar.gz")
            .and_then(|_| tar_xf("zlib.tar.gz"))
            .unwrap();
    }

    if !Path::new(&format!("boringssl-{}", BORINGSSL_GIT_HASH)).exists() {
        wget(&format!("https://github.com/google/boringssl/archive/{}.tar.gz",
                      BORINGSSL_GIT_HASH),
             "boringssl.tar.gz")
            .and_then(|_| tar_xf("boringssl.tar.gz"))
            .unwrap();
    }

    let dst = cmake::Config::new(format!("zlib-{}", ZLIB_VERSION)).build();

    println!("cargo:rustc-link-search=native={}/lib", dst.display());

    let dst = cmake::Config::new(format!("grpc-{}", GRPC_VERSION))
        .define("ZLIB_ROOT_DIR", format!("../zlib-{}", ZLIB_VERSION)) // relative to grpc dir
        .define("BORINGSSL_ROOT_DIR", format!("../boringssl-{}", BORINGSSL_GIT_HASH))
        .build_target("grpc_unsecure")
        .build();

    cc.include(format!("grpc-{}/include", GRPC_VERSION));

    println!("cargo:rustc-link-search=native={}/build", dst.display());
    println!("cargo:rustc-link-search=native={}/build/third_party/zlib",
             dst.display());

    println!("cargo:rustc-link-lib=static=z");
    println!("cargo:rustc-link-lib=static=gpr");
    println!("cargo:rustc-link-lib=static=grpc_unsecure");
}

fn main() {
    println!("cargo:rerun-if-changed=build.rs");

    let mut cc = gcc::Config::new();

    build_or_link_grpc(&mut cc);

    cc.file("grpc_wrap.c")
        .flag("-fPIC")
        .flag("-O2")
        .compile("libgrpc_wrap.a");
}
<|endoftext|>


<commit_before>//! Draw image

use current::{ Modifier };
use internal;
use triangulation;
use BackEnd;
use Color;
use Context;
use ImageSize;
use Rect;
use SrcRect;

/// An image
#[deriving(Copy)]
pub struct Image {
    /// The color
    pub color: Option<internal::Color>,
    /// The rectangle to draw image inside
    pub rectangle: Option<internal::Rectangle>,
    /// The image source rectangle
    pub source_rectangle: Option<internal::SourceRectangle>,
}

impl Image {
    /// Creates a new image
    pub fn new() -> Image {
        Image {
            color: None,
            source_rectangle: None,
            rectangle: None,
        }
    }

    /// Draws the image.
    pub fn draw<B: BackEnd<I>, I: ImageSize>(
        &self,
        texture: &I,
        c: &Context,
        back_end: &mut B
    ) {
        use internal::Scalar;

        let color = self.color.unwrap_or([1.0, ..4]);
        if color[3] == 0.0 { return; }
        let source_rectangle = self.source_rectangle.unwrap_or({
            let (w, h) = texture.get_size();
            [0, 0, w as i32, h as i32]
        });
        let rectangle = self.rectangle.unwrap_or([
            0.0,
            0.0,
            source_rectangle[2] as Scalar,
            source_rectangle[3] as Scalar
        ]);
        back_end.enable_texture(texture);
        back_end.color(color);
        back_end.tri_list_uv(
            &triangulation::rect_tri_list_xy(c.transform, rectangle),
            &triangulation::rect_tri_list_uv(texture, source_rectangle)
        );
        back_end.disable_texture();
    }
}

impl Modifier<Image> for Color {
    fn modify(self, img: &mut Image) {
        let Color(val) = self;
        img.color = Some(val);
    }
}

impl Modifier<Image> for Rect {
    fn modify(self, img: &mut Image) {
        let Rect(val) = self;
        img.rectangle = Some(val);
    }
}

impl Modifier<Image> for SrcRect {
    fn modify(self, img: &mut Image) {
        let SrcRect(val) = self;
        img.source_rectangle = Some(val);
    }
}

#[cfg(test)]
mod test {
    use super::Image;
    use Color;
    use Rect;
    use SrcRect;
    use current::Set;

    #[test]
    fn test_image() {
        let _img = Image::new()
            .set(Color([1.0, ..4]))
            .set(Rect([0.0, 0.0, 100.0, 100.0]))
            .set(SrcRect([0, 0, 32, 32]));
    }
}

<commit_msg>Added colored constructor to Image<commit_after>//! Draw image

use current::{ Modifier };
use internal;
use triangulation;
use BackEnd;
use Color;
use Context;
use ImageSize;
use Rect;
use SrcRect;

/// An image
#[deriving(Copy)]
pub struct Image {
    /// The color
    pub color: Option<internal::Color>,
    /// The rectangle to draw image inside
    pub rectangle: Option<internal::Rectangle>,
    /// The image source rectangle
    pub source_rectangle: Option<internal::SourceRectangle>,
}

impl Image {
    /// Creates a new image
    pub fn new() -> Image {
        Image {
            color: None,
            source_rectangle: None,
            rectangle: None,
        }
    }

    /// Creates a new colored image
    pub fn colored(color: internal::Color) -> Image {
        Image {
            color: Some(color),
            source_rectangle: None,
            rectangle: None
        }
    }

    /// Draws the image.
    pub fn draw<B: BackEnd<I>, I: ImageSize>(
        &self,
        texture: &I,
        c: &Context,
        back_end: &mut B
    ) {
        use internal::Scalar;

        let color = self.color.unwrap_or([1.0, ..4]);
        if color[3] == 0.0 { return; }
        let source_rectangle = self.source_rectangle.unwrap_or({
            let (w, h) = texture.get_size();
            [0, 0, w as i32, h as i32]
        });
        let rectangle = self.rectangle.unwrap_or([
            0.0,
            0.0,
            source_rectangle[2] as Scalar,
            source_rectangle[3] as Scalar
        ]);
        back_end.enable_texture(texture);
        back_end.color(color);
        back_end.tri_list_uv(
            &triangulation::rect_tri_list_xy(c.transform, rectangle),
            &triangulation::rect_tri_list_uv(texture, source_rectangle)
        );
        back_end.disable_texture();
    }
}

impl Modifier<Image> for Color {
    fn modify(self, img: &mut Image) {
        let Color(val) = self;
        img.color = Some(val);
    }
}

impl Modifier<Image> for Rect {
    fn modify(self, img: &mut Image) {
        let Rect(val) = self;
        img.rectangle = Some(val);
    }
}

impl Modifier<Image> for SrcRect {
    fn modify(self, img: &mut Image) {
        let SrcRect(val) = self;
        img.source_rectangle = Some(val);
    }
}

#[cfg(test)]
mod test {
    use super::Image;
    use Color;
    use Rect;
    use SrcRect;
    use current::Set;

    #[test]
    fn test_image() {
        let _img = Image::new()
            .set(Color([1.0, ..4]))
            .set(Rect([0.0, 0.0, 100.0, 100.0]))
            .set(SrcRect([0, 0, 32, 32]));
    }
}

<|endoftext|>


<commit_before>extern crate regex;
#[macro_use]
extern crate lazy_static;
extern crate itertools;

use regex::Regex;
use itertools::Itertools;
use std::collections::HashMap;
use std::ffi::OsStr;
use std::fs;
use std::io::prelude::*;

lazy_static! {
    static ref DEC_CLIPPY_LINT_RE: Regex = Regex::new(r#"(?x)
        declare_clippy_lint!\s*[\{(]\s*
        pub\s+(?P<name>[A-Z_][A-Z_0-9]*)\s*,\s*
        (?P<cat>[a-z_]+)\s*,\s*
        "(?P<desc>(?:[^"\\]+|\\(?s).(?-s))*)"\s*[})]
    "#).unwrap();
    static ref DEC_DEPRECATED_LINT_RE: Regex = Regex::new(r#"(?x)
        declare_deprecated_lint!\s*[{(]\s*
        pub\s+(?P<name>[A-Z_][A-Z_0-9]*)\s*,\s*
        "(?P<desc>(?:[^"\\]+|\\(?s).(?-s))*)"\s*[})]
    "#).unwrap();
    static ref NL_ESCAPE_RE: Regex = Regex::new(r#"\\\n\s*"#).unwrap();
    pub static ref DOCS_LINK: String = "https://rust-lang-nursery.github.io/rust-clippy/master/index.html".to_string();
}

#[derive(Clone, PartialEq, Debug)]
pub struct Lint {
    pub name: String,
    pub group: String,
    pub desc: String,
    pub deprecation: Option<String>,
    pub module: String,
}

impl Lint {
    pub fn new(name: &str, group: &str, desc: &str, deprecation: Option<&str>, module: &str) -> Lint {
        Lint {
            name: name.to_lowercase(),
            group: group.to_string(),
            desc: NL_ESCAPE_RE.replace(&desc.replace("\\\"", "\""), "").to_string(),
            deprecation: deprecation.map(|d| d.to_string()),
            module: module.to_string(),
        }
    }

    /// Returns all non-deprecated lints
    pub fn active_lints(lints: &[Lint]) -> impl Iterator<Item=&Lint> {
        lints.iter().filter(|l| l.deprecation.is_none())
    }

    /// Returns the lints in a HashMap, grouped by the different lint groups
    pub fn by_lint_group(lints: &[Lint]) -> HashMap<String, Vec<Lint>> {
        lints.iter().map(|lint| (lint.group.to_string(), lint.clone())).into_group_map()
    }
}

pub fn gather_all() -> impl Iterator<Item=Lint> {
    lint_files().flat_map(gather_from_file)
}

fn gather_from_file(dir_entry: fs::DirEntry) -> impl Iterator<Item=Lint> {
    let mut file = fs::File::open(dir_entry.path()).unwrap();
    let mut content = String::new();
    file.read_to_string(&mut content).unwrap();
    parse_contents(&content, dir_entry.path().file_stem().unwrap().to_str().unwrap())
}

fn parse_contents(content: &str, filename: &str) -> impl Iterator<Item=Lint> {
    let lints = DEC_CLIPPY_LINT_RE
        .captures_iter(content)
        .map(|m| Lint::new(&m["name"], &m["cat"], &m["desc"], None, filename));
    let deprecated = DEC_DEPRECATED_LINT_RE
        .captures_iter(content)
        .map(|m| Lint::new( &m["name"], "Deprecated", &m["desc"], Some(&m["desc"]), filename));
    // Removing the `.collect::<Vec<Lint>>().into_iter()` causes some lifetime issues due to the map
    lints.chain(deprecated).collect::<Vec<Lint>>().into_iter()
}

/// Collects all .rs files in the `clippy_lints/src` directory
fn lint_files() -> impl Iterator<Item=fs::DirEntry> {
    fs::read_dir("../clippy_lints/src")
        .unwrap()
        .filter_map(|f| f.ok())
        .filter(|f| f.path().extension() == Some(OsStr::new("rs")))
}

#[test]
fn test_parse_contents() {
    let result: Vec<Lint> = parse_contents(
        r#"
declare_clippy_lint! {
    pub PTR_ARG,
    style,
    "really long \
     text"
}

declare_clippy_lint!{
    pub DOC_MARKDOWN,
    pedantic,
    "single line"
}

/// some doc comment
declare_deprecated_lint! {
    pub SHOULD_ASSERT_EQ,
    "`assert!()` will be more flexible with RFC 2011"
}
    "#,
    "module_name").collect();

    let expected = vec![
        Lint::new("ptr_arg", "style", "really long text", None, "module_name"),
        Lint::new("doc_markdown", "pedantic", "single line", None, "module_name"),
        Lint::new(
            "should_assert_eq",
            "Deprecated",
            "`assert!()` will be more flexible with RFC 2011",
            Some("`assert!()` will be more flexible with RFC 2011"),
            "module_name"
        ),
    ];
    assert_eq!(expected, result);
}

#[test]
fn test_active_lints() {
    let lints = vec![
        Lint::new("should_assert_eq", "Deprecated", "abc", Some("Reason"), "module_name"),
        Lint::new("should_assert_eq2", "Not Deprecated", "abc", None, "module_name")
    ];
    let expected = vec![
        Lint::new("should_assert_eq2", "Not Deprecated", "abc", None, "module_name")
    ];
    assert_eq!(expected, Lint::active_lints(&lints).cloned().collect::<Vec<Lint>>());
}

#[test]
fn test_by_lint_group() {
    let lints = vec![
        Lint::new("should_assert_eq", "group1", "abc", None, "module_name"),
        Lint::new("should_assert_eq2", "group2", "abc", None, "module_name"),
        Lint::new("incorrect_match", "group1", "abc", None, "module_name"),
    ];
    let mut expected: HashMap<String, Vec<Lint>> = HashMap::new();
    expected.insert("group1".to_string(), vec![
        Lint::new("should_assert_eq", "group1", "abc", None, "module_name"),
        Lint::new("incorrect_match", "group1", "abc", None, "module_name"),
    ]);
    expected.insert("group2".to_string(), vec![
        Lint::new("should_assert_eq2", "group2", "abc", None, "module_name")
    ]);
    assert_eq!(expected, Lint::by_lint_group(&lints));
}
<commit_msg>Pass by ref instead of value<commit_after>extern crate regex;
#[macro_use]
extern crate lazy_static;
extern crate itertools;

use regex::Regex;
use itertools::Itertools;
use std::collections::HashMap;
use std::ffi::OsStr;
use std::fs;
use std::io::prelude::*;

lazy_static! {
    static ref DEC_CLIPPY_LINT_RE: Regex = Regex::new(r#"(?x)
        declare_clippy_lint!\s*[\{(]\s*
        pub\s+(?P<name>[A-Z_][A-Z_0-9]*)\s*,\s*
        (?P<cat>[a-z_]+)\s*,\s*
        "(?P<desc>(?:[^"\\]+|\\(?s).(?-s))*)"\s*[})]
    "#).unwrap();
    static ref DEC_DEPRECATED_LINT_RE: Regex = Regex::new(r#"(?x)
        declare_deprecated_lint!\s*[{(]\s*
        pub\s+(?P<name>[A-Z_][A-Z_0-9]*)\s*,\s*
        "(?P<desc>(?:[^"\\]+|\\(?s).(?-s))*)"\s*[})]
    "#).unwrap();
    static ref NL_ESCAPE_RE: Regex = Regex::new(r#"\\\n\s*"#).unwrap();
    pub static ref DOCS_LINK: String = "https://rust-lang-nursery.github.io/rust-clippy/master/index.html".to_string();
}

#[derive(Clone, PartialEq, Debug)]
pub struct Lint {
    pub name: String,
    pub group: String,
    pub desc: String,
    pub deprecation: Option<String>,
    pub module: String,
}

impl Lint {
    pub fn new(name: &str, group: &str, desc: &str, deprecation: Option<&str>, module: &str) -> Lint {
        Lint {
            name: name.to_lowercase(),
            group: group.to_string(),
            desc: NL_ESCAPE_RE.replace(&desc.replace("\\\"", "\""), "").to_string(),
            deprecation: deprecation.map(|d| d.to_string()),
            module: module.to_string(),
        }
    }

    /// Returns all non-deprecated lints
    pub fn active_lints(lints: &[Lint]) -> impl Iterator<Item=&Lint> {
        lints.iter().filter(|l| l.deprecation.is_none())
    }

    /// Returns the lints in a HashMap, grouped by the different lint groups
    pub fn by_lint_group(lints: &[Lint]) -> HashMap<String, Vec<Lint>> {
        lints.iter().map(|lint| (lint.group.to_string(), lint.clone())).into_group_map()
    }
}

pub fn gather_all() -> impl Iterator<Item=Lint> {
    lint_files().flat_map(|f| gather_from_file(&f))
}

fn gather_from_file(dir_entry: &fs::DirEntry) -> impl Iterator<Item=Lint> {
    let mut file = fs::File::open(dir_entry.path()).unwrap();
    let mut content = String::new();
    file.read_to_string(&mut content).unwrap();
    parse_contents(&content, dir_entry.path().file_stem().unwrap().to_str().unwrap())
}

fn parse_contents(content: &str, filename: &str) -> impl Iterator<Item=Lint> {
    let lints = DEC_CLIPPY_LINT_RE
        .captures_iter(content)
        .map(|m| Lint::new(&m["name"], &m["cat"], &m["desc"], None, filename));
    let deprecated = DEC_DEPRECATED_LINT_RE
        .captures_iter(content)
        .map(|m| Lint::new( &m["name"], "Deprecated", &m["desc"], Some(&m["desc"]), filename));
    // Removing the `.collect::<Vec<Lint>>().into_iter()` causes some lifetime issues due to the map
    lints.chain(deprecated).collect::<Vec<Lint>>().into_iter()
}

/// Collects all .rs files in the `clippy_lints/src` directory
fn lint_files() -> impl Iterator<Item=fs::DirEntry> {
    fs::read_dir("../clippy_lints/src")
        .unwrap()
        .filter_map(|f| f.ok())
        .filter(|f| f.path().extension() == Some(OsStr::new("rs")))
}

#[test]
fn test_parse_contents() {
    let result: Vec<Lint> = parse_contents(
        r#"
declare_clippy_lint! {
    pub PTR_ARG,
    style,
    "really long \
     text"
}

declare_clippy_lint!{
    pub DOC_MARKDOWN,
    pedantic,
    "single line"
}

/// some doc comment
declare_deprecated_lint! {
    pub SHOULD_ASSERT_EQ,
    "`assert!()` will be more flexible with RFC 2011"
}
    "#,
    "module_name").collect();

    let expected = vec![
        Lint::new("ptr_arg", "style", "really long text", None, "module_name"),
        Lint::new("doc_markdown", "pedantic", "single line", None, "module_name"),
        Lint::new(
            "should_assert_eq",
            "Deprecated",
            "`assert!()` will be more flexible with RFC 2011",
            Some("`assert!()` will be more flexible with RFC 2011"),
            "module_name"
        ),
    ];
    assert_eq!(expected, result);
}

#[test]
fn test_active_lints() {
    let lints = vec![
        Lint::new("should_assert_eq", "Deprecated", "abc", Some("Reason"), "module_name"),
        Lint::new("should_assert_eq2", "Not Deprecated", "abc", None, "module_name")
    ];
    let expected = vec![
        Lint::new("should_assert_eq2", "Not Deprecated", "abc", None, "module_name")
    ];
    assert_eq!(expected, Lint::active_lints(&lints).cloned().collect::<Vec<Lint>>());
}

#[test]
fn test_by_lint_group() {
    let lints = vec![
        Lint::new("should_assert_eq", "group1", "abc", None, "module_name"),
        Lint::new("should_assert_eq2", "group2", "abc", None, "module_name"),
        Lint::new("incorrect_match", "group1", "abc", None, "module_name"),
    ];
    let mut expected: HashMap<String, Vec<Lint>> = HashMap::new();
    expected.insert("group1".to_string(), vec![
        Lint::new("should_assert_eq", "group1", "abc", None, "module_name"),
        Lint::new("incorrect_match", "group1", "abc", None, "module_name"),
    ]);
    expected.insert("group2".to_string(), vec![
        Lint::new("should_assert_eq2", "group2", "abc", None, "module_name")
    ]);
    assert_eq!(expected, Lint::by_lint_group(&lints));
}
<|endoftext|>


<commit_before>extern crate libc;

use std;
use std::mem;
use libc::c_char;

use crate::rparser::*;

use ipsec_parser::*;

pub struct IPsecBuilder {}
impl RBuilder for IPsecBuilder {
    fn new(&self) -> Box<dyn RParser> { Box::new(IPsecParser::new(b"IKEv2")) }
    fn probe(&self, i:&[u8]) -> bool { ipsec_probe(i) }
}

pub struct IPsecParser<'a> {
    _name: Option<&'a[u8]>,

    /// The transforms proposed by the initiator
    pub client_proposals : Vec<Vec<IkeV2Transform>>,

    /// The transforms selected by the responder
    pub server_proposals : Vec<Vec<IkeV2Transform>>,

    /// The Diffie-Hellman group from the server KE message, if present.
    pub dh_group: IkeTransformDHType,
}

impl<'a> RParser for IPsecParser<'a> {
    fn parse(&mut self, i: &[u8], direction: u8) -> u32 {
        match parse_ikev2_header(i) {
            Ok((rem,ref hdr)) => {
                debug!("parse_ikev2_header: {:?}",hdr);
                if rem.len() == 0 && hdr.length == 28 {
                    return R_STATUS_OK;
                }
                // Rule 0: check version
                if hdr.maj_ver != 2 || hdr.min_ver != 0 {
                    warn!("Unknown header version: {}.{}", hdr.maj_ver, hdr.min_ver);
                }
                match parse_ikev2_payload_list(rem,hdr.next_payload) {
                    Ok((_,Ok(ref p))) => {
                        debug!("parse_ikev2_payload_with_type: {:?}",p);
                        for payload in p {
                            match payload.content {
                                IkeV2PayloadContent::SA(ref prop) => {
                                    // if hdr.flags & IKEV2_FLAG_INITIATOR != 0 {
                                        self.add_proposals(prop, direction);
                                    // }
                                },
                                IkeV2PayloadContent::KE(ref kex) => {
                                    debug!("KEX {:?}", kex.dh_group);
                                    if direction == STREAM_TOCLIENT {
                                        self.dh_group = kex.dh_group;
                                    }
                                },
                                IkeV2PayloadContent::Nonce(ref n) => {
                                    debug!("Nonce: {:?}", n);
                                },
                                IkeV2PayloadContent::Notify(ref n) => {
                                    debug!("Notify: {:?}", n);
                                },
                                _ => {
                                    debug!("Unknown payload content {:?}", payload.content);
                                },
                            }
                        }
                    },
                    e => warn!("parse_ikev2_payload_with_type: {:?}",e),
                };
            },
            e => warn!("parse_ikev2_header: {:?}",e),
        };
        R_STATUS_OK
    }
}

impl<'a> IPsecParser<'a> {
    pub fn new(name: &'a[u8]) -> IPsecParser<'a> {
        IPsecParser{
            _name: Some(name),
            client_proposals: Vec::new(),
            server_proposals: Vec::new(),
            dh_group: IkeTransformDHType::None,
        }
    }

    fn add_proposals(&mut self, prop: &Vec<IkeV2Proposal>, direction: u8) {
        debug!("num_proposals: {}",prop.len());
        for ref p in prop {
            debug!("proposal: {:?}",p);
            debug!("num_transforms: {}",p.num_transforms);
            for ref xform in &p.transforms {
                debug!("transform: {:?}", xform);
                debug!("\ttype: {:?}", xform.transform_type);
                match xform.transform_type {
                    IkeTransformType::EncryptionAlgorithm => {
                        debug!("\tEncryptionAlgorithm: {:?}",IkeTransformEncType(xform.transform_id));
                    },
                    IkeTransformType::PseudoRandomFunction => {
                        debug!("\tPseudoRandomFunction: {:?}",IkeTransformPRFType(xform.transform_id));
                    },
                    IkeTransformType::IntegrityAlgorithm => {
                        debug!("\tIntegrityAlgorithm: {:?}",IkeTransformAuthType(xform.transform_id));
                    },
                    IkeTransformType::DiffieHellmanGroup => {
                        debug!("\tDiffieHellmanGroup: {:?}",IkeTransformDHType(xform.transform_id));
                    },
                    IkeTransformType::ExtendedSequenceNumbers => {
                        debug!("\tExtendedSequenceNumbers: {:?}",IkeTransformESNType(xform.transform_id));
                    },
                    _ => warn!("\tUnknown transform type {:?}", xform.transform_type),
                }
                if xform.transform_id == 0 {
                    warn!("\tTransform ID == 0 (choice left to responder)");
                };
            }
            let proposals : Vec<IkeV2Transform> = p.transforms.iter().map(|x| x.into()).collect();
            debug!("Proposals\n{:?}",proposals);
            // Rule 1: warn on weak or unknown transforms
            for prop in &proposals {
                match prop {
                    &IkeV2Transform::Encryption(ref enc) => {
                        match *enc {
                            IkeTransformEncType::ENCR_DES_IV64 |
                            IkeTransformEncType::ENCR_DES |
                            IkeTransformEncType::ENCR_3DES |
                            IkeTransformEncType::ENCR_RC5 |
                            IkeTransformEncType::ENCR_IDEA |
                            IkeTransformEncType::ENCR_CAST |
                            IkeTransformEncType::ENCR_BLOWFISH |
                            IkeTransformEncType::ENCR_3IDEA |
                            IkeTransformEncType::ENCR_DES_IV32 |
                            IkeTransformEncType::ENCR_NULL => {
                                warn!("Weak Encryption: {:?}", enc);
                            },
                            _ => (),
                        }
                    },
                    &IkeV2Transform::Auth(ref auth) => {
                        match *auth {
                            IkeTransformAuthType::NONE => {
                                // Note: this could be expected with an AEAD encription alg.
                                // See rule 4
                                ()
                            },
                            IkeTransformAuthType::AUTH_HMAC_MD5_96 |
                            IkeTransformAuthType::AUTH_HMAC_SHA1_96 |
                            IkeTransformAuthType::AUTH_DES_MAC |
                            IkeTransformAuthType::AUTH_KPDK_MD5 |
                            IkeTransformAuthType::AUTH_AES_XCBC_96 |
                            IkeTransformAuthType::AUTH_HMAC_MD5_128 |
                            IkeTransformAuthType::AUTH_HMAC_SHA1_160 => {
                                warn!("Weak auth: {:?}", auth);
                            },
                            _ => (),
                        }
                    },
                    &IkeV2Transform::DH(ref dh) => {
                        match *dh {
                            IkeTransformDHType::None => {
                                warn!("'None' DH transform proposed");
                            },
                            IkeTransformDHType::Modp768 |
                            IkeTransformDHType::Modp1024 |
                            IkeTransformDHType::Modp1024s160 |
                            IkeTransformDHType::Modp1536 => {
                                warn!("Weak DH: {:?}", dh);
                            },
                            _ => (),
                        }
                    },
                    &IkeV2Transform::Unknown(tx_type,tx_id) => {
                        warn!("Unknown proposal: type={}, id={}", tx_type.0, tx_id);
                    },
                    _ => (),
                }
            }
            // Rule 2: check if no DH was proposed
            if ! proposals.iter().any(|x| {
                if let &IkeV2Transform::DH(_) = x { true } else { false }
            })
            {
                warn!("No DH transform found");
            }
            // Rule 3: check if proposing AH ([RFC7296] section 3.3.1)
            if p.protocol_id == ProtocolID::AH {
                warn!("Proposal uses protocol AH - no confidentiality");
            }
            // Rule 4: lack of integrity is accepted only if using an AEAD proposal
            // Look if no auth was proposed, including if proposal is Auth::None
            if ! proposals.iter().any(|x| {
                match *x {
                    IkeV2Transform::Auth(IkeTransformAuthType::NONE) => false,
                    IkeV2Transform::Auth(_)                          => true,
                    _                                                 => false,
                }
            })
            {
                if ! proposals.iter().any(|x| {
                    if let &IkeV2Transform::Encryption(ref enc) = x {
                        enc.is_aead()
                    } else { false }
                }) {
                    warn!("No integrity transform found");
                }
            }
            // Rule 5: Check if an integrity and no integrity are part of the same proposal ?
            // XXX
            // Finally
            if direction == STREAM_TOSERVER {
                self.client_proposals.push(proposals);
            } else {
                self.server_proposals.push(proposals);
            }
        }
        debug!("client_proposals: {:?}", self.client_proposals);
        debug!("server_proposals: {:?}", self.server_proposals);
    }
}

pub fn ipsec_probe(i: &[u8]) -> bool {
    if i.len() <= 20 { return false; }
    match parse_ikev2_header(i) {
        Ok((_,ref hdr)) => {
            if hdr.maj_ver != 2 || hdr.min_ver != 0 {
                debug!("ipsec_probe: could be ipsec, but with unsupported/invalid version {}.{}",
                      hdr.maj_ver, hdr.min_ver);
                return false;
            }
            if hdr.exch_type.0 < 34 || hdr.exch_type.0 > 37 {
                debug!("ipsec_probe: could be ipsec, but with unsupported/invalid exchange type {}",
                      hdr.exch_type.0);
                return false;
            }
            true
        }
        _ => false,
    }
}

r_declare_state_new!(r_ipsec_state_new,IPsecParser,b"IPsec state");
r_declare_state_free!(r_ipsec_state_free,IPsecParser,{ () });

r_implement_probe!(r_ipsec_probe,ipsec_probe);
r_implement_parse!(r_ipsec_parse,IPsecParser);
<commit_msg>IPsec: add keys for parsed variables<commit_after>extern crate libc;

use std;
use std::mem;
use libc::c_char;

use crate::rparser::*;
use crate::{gen_get_variants, Variant};

use ipsec_parser::*;

impl<'a> From<IkeTransformDHType> for Variant<'a> {
    fn from(input: IkeTransformDHType) -> Self {
        Variant::U16(input.0)
    }
}

pub struct IPsecBuilder {}
impl RBuilder for IPsecBuilder {
    fn new(&self) -> Box<dyn RParser> { Box::new(IPsecParser::new(b"IKEv2")) }
    fn probe(&self, i:&[u8]) -> bool { ipsec_probe(i) }
}

pub struct IPsecParser<'a> {
    _name: Option<&'a[u8]>,

    /// The transforms proposed by the initiator
    pub client_proposals : Vec<Vec<IkeV2Transform>>,

    /// The transforms selected by the responder
    pub server_proposals : Vec<Vec<IkeV2Transform>>,

    /// The Diffie-Hellman group from the server KE message, if present.
    pub dh_group: IkeTransformDHType,
}

impl<'a> RParser for IPsecParser<'a> {
    fn parse(&mut self, i: &[u8], direction: u8) -> u32 {
        match parse_ikev2_header(i) {
            Ok((rem,ref hdr)) => {
                debug!("parse_ikev2_header: {:?}",hdr);
                if rem.len() == 0 && hdr.length == 28 {
                    return R_STATUS_OK;
                }
                // Rule 0: check version
                if hdr.maj_ver != 2 || hdr.min_ver != 0 {
                    warn!("Unknown header version: {}.{}", hdr.maj_ver, hdr.min_ver);
                }
                match parse_ikev2_payload_list(rem,hdr.next_payload) {
                    Ok((_,Ok(ref p))) => {
                        debug!("parse_ikev2_payload_with_type: {:?}",p);
                        for payload in p {
                            match payload.content {
                                IkeV2PayloadContent::SA(ref prop) => {
                                    // if hdr.flags & IKEV2_FLAG_INITIATOR != 0 {
                                        self.add_proposals(prop, direction);
                                    // }
                                },
                                IkeV2PayloadContent::KE(ref kex) => {
                                    debug!("KEX {:?}", kex.dh_group);
                                    if direction == STREAM_TOCLIENT {
                                        self.dh_group = kex.dh_group;
                                    }
                                },
                                IkeV2PayloadContent::Nonce(ref n) => {
                                    debug!("Nonce: {:?}", n);
                                },
                                IkeV2PayloadContent::Notify(ref n) => {
                                    debug!("Notify: {:?}", n);
                                },
                                _ => {
                                    debug!("Unknown payload content {:?}", payload.content);
                                },
                            }
                        }
                    },
                    e => warn!("parse_ikev2_payload_with_type: {:?}",e),
                };
            },
            e => warn!("parse_ikev2_header: {:?}",e),
        };
        R_STATUS_OK
    }

    gen_get_variants!{IPsecParser,
        dh_group   => into,
        enc        => |s| { s.get_server_proposal_enc().map(|x| x.into()) },
        prf        => |s| { s.get_server_proposal_prf().map(|x| x.into()) },
        auth       => |s| { s.get_server_proposal_auth().map(|x| x.into()) },
        dh         => |s| { s.get_server_proposal_dh().map(|x| x.into()) },
        esn        => |s| { s.get_server_proposal_esn().map(|x| x.into()) },
    }
}

macro_rules! get_server_proposal {
    ( $t:tt, $n:ident ) => {
        pub fn $n(&self) -> Option<u16> {
            if let Some(xform) = self.server_proposals.first() {
                xform.iter()
                    .find_map(|x| if let IkeV2Transform::$t(e) = x {
                        Some(e.0)
                    } else {
                        None
                    })
            } else {
                None
            }
        }
    };
}

impl<'a> IPsecParser<'a> {
    pub fn new(name: &'a[u8]) -> IPsecParser<'a> {
        IPsecParser{
            _name: Some(name),
            client_proposals: Vec::new(),
            server_proposals: Vec::new(),
            dh_group: IkeTransformDHType::None,
        }
    }

    get_server_proposal!{Encryption, get_server_proposal_enc}
    get_server_proposal!{PRF, get_server_proposal_prf}
    get_server_proposal!{Auth, get_server_proposal_auth}
    get_server_proposal!{DH, get_server_proposal_dh}
    get_server_proposal!{ESN, get_server_proposal_esn}

    fn add_proposals(&mut self, prop: &Vec<IkeV2Proposal>, direction: u8) {
        debug!("num_proposals: {}",prop.len());
        for ref p in prop {
            debug!("proposal: {:?}",p);
            debug!("num_transforms: {}",p.num_transforms);
            for ref xform in &p.transforms {
                debug!("transform: {:?}", xform);
                debug!("\ttype: {:?}", xform.transform_type);
                match xform.transform_type {
                    IkeTransformType::EncryptionAlgorithm => {
                        debug!("\tEncryptionAlgorithm: {:?}",IkeTransformEncType(xform.transform_id));
                    },
                    IkeTransformType::PseudoRandomFunction => {
                        debug!("\tPseudoRandomFunction: {:?}",IkeTransformPRFType(xform.transform_id));
                    },
                    IkeTransformType::IntegrityAlgorithm => {
                        debug!("\tIntegrityAlgorithm: {:?}",IkeTransformAuthType(xform.transform_id));
                    },
                    IkeTransformType::DiffieHellmanGroup => {
                        debug!("\tDiffieHellmanGroup: {:?}",IkeTransformDHType(xform.transform_id));
                    },
                    IkeTransformType::ExtendedSequenceNumbers => {
                        debug!("\tExtendedSequenceNumbers: {:?}",IkeTransformESNType(xform.transform_id));
                    },
                    _ => warn!("\tUnknown transform type {:?}", xform.transform_type),
                }
                if xform.transform_id == 0 {
                    warn!("\tTransform ID == 0 (choice left to responder)");
                };
            }
            let proposals : Vec<IkeV2Transform> = p.transforms.iter().map(|x| x.into()).collect();
            debug!("Proposals\n{:?}",proposals);
            // Rule 1: warn on weak or unknown transforms
            for prop in &proposals {
                match prop {
                    &IkeV2Transform::Encryption(ref enc) => {
                        match *enc {
                            IkeTransformEncType::ENCR_DES_IV64 |
                            IkeTransformEncType::ENCR_DES |
                            IkeTransformEncType::ENCR_3DES |
                            IkeTransformEncType::ENCR_RC5 |
                            IkeTransformEncType::ENCR_IDEA |
                            IkeTransformEncType::ENCR_CAST |
                            IkeTransformEncType::ENCR_BLOWFISH |
                            IkeTransformEncType::ENCR_3IDEA |
                            IkeTransformEncType::ENCR_DES_IV32 |
                            IkeTransformEncType::ENCR_NULL => {
                                warn!("Weak Encryption: {:?}", enc);
                            },
                            _ => (),
                        }
                    },
                    &IkeV2Transform::Auth(ref auth) => {
                        match *auth {
                            IkeTransformAuthType::NONE => {
                                // Note: this could be expected with an AEAD encription alg.
                                // See rule 4
                                ()
                            },
                            IkeTransformAuthType::AUTH_HMAC_MD5_96 |
                            IkeTransformAuthType::AUTH_HMAC_SHA1_96 |
                            IkeTransformAuthType::AUTH_DES_MAC |
                            IkeTransformAuthType::AUTH_KPDK_MD5 |
                            IkeTransformAuthType::AUTH_AES_XCBC_96 |
                            IkeTransformAuthType::AUTH_HMAC_MD5_128 |
                            IkeTransformAuthType::AUTH_HMAC_SHA1_160 => {
                                warn!("Weak auth: {:?}", auth);
                            },
                            _ => (),
                        }
                    },
                    &IkeV2Transform::DH(ref dh) => {
                        match *dh {
                            IkeTransformDHType::None => {
                                warn!("'None' DH transform proposed");
                            },
                            IkeTransformDHType::Modp768 |
                            IkeTransformDHType::Modp1024 |
                            IkeTransformDHType::Modp1024s160 |
                            IkeTransformDHType::Modp1536 => {
                                warn!("Weak DH: {:?}", dh);
                            },
                            _ => (),
                        }
                    },
                    &IkeV2Transform::Unknown(tx_type,tx_id) => {
                        warn!("Unknown proposal: type={}, id={}", tx_type.0, tx_id);
                    },
                    _ => (),
                }
            }
            // Rule 2: check if no DH was proposed
            if ! proposals.iter().any(|x| {
                if let &IkeV2Transform::DH(_) = x { true } else { false }
            })
            {
                warn!("No DH transform found");
            }
            // Rule 3: check if proposing AH ([RFC7296] section 3.3.1)
            if p.protocol_id == ProtocolID::AH {
                warn!("Proposal uses protocol AH - no confidentiality");
            }
            // Rule 4: lack of integrity is accepted only if using an AEAD proposal
            // Look if no auth was proposed, including if proposal is Auth::None
            if ! proposals.iter().any(|x| {
                match *x {
                    IkeV2Transform::Auth(IkeTransformAuthType::NONE) => false,
                    IkeV2Transform::Auth(_)                          => true,
                    _                                                 => false,
                }
            })
            {
                if ! proposals.iter().any(|x| {
                    if let &IkeV2Transform::Encryption(ref enc) = x {
                        enc.is_aead()
                    } else { false }
                }) {
                    warn!("No integrity transform found");
                }
            }
            // Rule 5: Check if an integrity and no integrity are part of the same proposal ?
            // XXX
            // Finally
            if direction == STREAM_TOSERVER {
                self.client_proposals.push(proposals);
            } else {
                self.server_proposals.push(proposals);
            }
        }
        // The server must accept one proposal, or reject them all (RFC 5996 2.7)
        if self.server_proposals.len() > 1 {
            warn!("more than one server proposals")
        }
        debug!("client_proposals: {:?}", self.client_proposals);
        debug!("server_proposals: {:?}", self.server_proposals);
    }
}

pub fn ipsec_probe(i: &[u8]) -> bool {
    if i.len() <= 20 { return false; }
    match parse_ikev2_header(i) {
        Ok((_,ref hdr)) => {
            if hdr.maj_ver != 2 || hdr.min_ver != 0 {
                debug!("ipsec_probe: could be ipsec, but with unsupported/invalid version {}.{}",
                      hdr.maj_ver, hdr.min_ver);
                return false;
            }
            if hdr.exch_type.0 < 34 || hdr.exch_type.0 > 37 {
                debug!("ipsec_probe: could be ipsec, but with unsupported/invalid exchange type {}",
                      hdr.exch_type.0);
                return false;
            }
            true
        }
        _ => false,
    }
}

r_declare_state_new!(r_ipsec_state_new,IPsecParser,b"IPsec state");
r_declare_state_free!(r_ipsec_state_free,IPsecParser,{ () });

r_implement_probe!(r_ipsec_probe,ipsec_probe);
r_implement_parse!(r_ipsec_parse,IPsecParser);
<|endoftext|>