<commit_before>// Copyright (c) 2016 The vulkano developers
// Licensed under the Apache License, Version 2.0
// <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT
// license <LICENSE-MIT or http://opensource.org/licenses/MIT>,
// at your option. All files in the project carrying such
// notice may not be copied, modified, or distributed except
// according to those terms.

use enums;
use parse;

use format_from_id;
use is_builtin;
use location_decoration;
use name_from_id;

pub fn write_entry_point(doc: &parse::Spirv, instruction: &parse::Instruction) -> (String, String) {
    let (execution, id, ep_name, interface) = match instruction {
        &parse::Instruction::EntryPoint {
            ref execution,
            id,
            ref name,
            ref interface,
            ..
        } => {
            (execution, id, name, interface)
        },
        _ => unreachable!(),
    };

    let capitalized_ep_name: String = ep_name
        .chars()
        .take(1)
        .flat_map(|c| c.to_uppercase())
        .chain(ep_name.chars().skip(1))
        .collect();

    let interface_structs =
        write_interface_structs(doc,
                                &capitalized_ep_name,
                                interface,
                                match *execution {
                                    enums::ExecutionModel::ExecutionModelTessellationControl =>
                                        true,
                                    enums::ExecutionModel::ExecutionModelTessellationEvaluation =>
                                        true,
                                    enums::ExecutionModel::ExecutionModelGeometry => true,
                                    _ => false,
                                },
                                match *execution {
                                    enums::ExecutionModel::ExecutionModelTessellationControl =>
                                        true,
                                    _ => false,
                                });

    let (ty, f_call) = match *execution {
        enums::ExecutionModel::ExecutionModelVertex => {
            let t = format!("::vulkano::pipeline::shader::VertexShaderEntryPoint<(), {0}Input, \
                             {0}Output, Layout>",
                            capitalized_ep_name);
            let f = format!("vertex_shader_entry_point(::std::ffi::CStr::from_ptr(NAME.as_ptr() \
                             as *const _), {0}Input, {0}Output, Layout(ShaderStages {{ vertex: \
                             true, .. ShaderStages::none() }}))",
                            capitalized_ep_name);
            (t, f)
        },

        enums::ExecutionModel::ExecutionModelTessellationControl => {
            let t = format!("::vulkano::pipeline::shader::TessControlShaderEntryPoint<(), \
                             {0}Input, {0}Output, Layout>",
                            capitalized_ep_name);
            let f = format!("tess_control_shader_entry_point(::std::ffi::CStr::from_ptr(NAME.\
                             as_ptr() as *const _), {0}Input, {0}Output, Layout(ShaderStages {{ \
                             tessellation_control: true, .. ShaderStages::none() }}))",
                            capitalized_ep_name);
            (t, f)
        },

        enums::ExecutionModel::ExecutionModelTessellationEvaluation => {
            let t = format!("::vulkano::pipeline::shader::TessEvaluationShaderEntryPoint<(), \
                             {0}Input, {0}Output, Layout>",
                            capitalized_ep_name);
            let f = format!("tess_evaluation_shader_entry_point(::std::ffi::CStr::from_ptr(NAME.\
                             as_ptr() as *const _), {0}Input, {0}Output, Layout(ShaderStages {{ \
                             tessellation_evaluation: true, .. ShaderStages::none() }}))",
                            capitalized_ep_name);
            (t, f)
        },

        enums::ExecutionModel::ExecutionModelGeometry => {
            let mut execution_mode = "Points"; // fallback value

            for instruction in doc.instructions.iter() {
                if let &parse::Instruction::ExecutionMode { target_id, ref mode, .. } = instruction {
                    if target_id != id {
                        continue;
                    }
                    execution_mode = match mode {
                        &enums::ExecutionMode::ExecutionModeInputPoints => "Points",
                        &enums::ExecutionMode::ExecutionModeInputLines => "Lines",
                        &enums::ExecutionMode::ExecutionModeInputLinesAdjacency => "LinesWithAdjacency",
                        &enums::ExecutionMode::ExecutionModeTriangles => "Triangles",
                        &enums::ExecutionMode::ExecutionModeInputTrianglesAdjacency => "TrianglesWithAdjacency",
                        _ => continue,
                    };
                    break;
                }
            }

            let execution_mode = format!("::vulkano::pipeline::shader::GeometryShaderExecutionMode::{0}", execution_mode);

            let t = format!("::vulkano::pipeline::shader::GeometryShaderEntryPoint<(), {0}Input, \
                             {0}Output, Layout>",
                            capitalized_ep_name);
            let f = format!("geometry_shader_entry_point(::std::ffi::CStr::from_ptr(NAME.\
                             as_ptr() as *const _), {1}, {0}Input, {0}Output, Layout(ShaderStages {{ \
                             geometry: true, .. ShaderStages::none() }}))",
                            capitalized_ep_name,
                            execution_mode);
            (t, f)
        },

        enums::ExecutionModel::ExecutionModelFragment => {
            let t = format!("::vulkano::pipeline::shader::FragmentShaderEntryPoint<(), {0}Input, \
                             {0}Output, Layout>",
                            capitalized_ep_name);
            let f = format!("fragment_shader_entry_point(::std::ffi::CStr::from_ptr(NAME.\
                             as_ptr() as *const _), {0}Input, {0}Output, Layout(ShaderStages {{ \
                             fragment: true, .. ShaderStages::none() }}))",
                            capitalized_ep_name);
            (t, f)
        },

        enums::ExecutionModel::ExecutionModelGLCompute => {
            (format!("::vulkano::pipeline::shader::ComputeShaderEntryPoint<(), Layout>"),
             format!("compute_shader_entry_point(::std::ffi::CStr::from_ptr(NAME.as_ptr() as \
                      *const _), Layout(ShaderStages {{ compute: true, .. ShaderStages::none() \
                      }}))"))
        },

        enums::ExecutionModel::ExecutionModelKernel => panic!("Kernels are not supported"),
    };

    let entry_point = format!(
        r#"
    /// Returns a logical struct describing the entry point named `{ep_name}`.
    #[inline]
    #[allow(unsafe_code)]
    pub fn {ep_name}_entry_point(&self) -> {ty} {{
        unsafe {{
            #[allow(dead_code)]
            static NAME: [u8; {ep_name_lenp1}] = [{encoded_ep_name}, 0];     // "{ep_name}"
            self.shader.{f_call}
        }}
    }}
            "#,
        ep_name = ep_name,
        ep_name_lenp1 = ep_name.chars().count() + 1,
        ty = ty,
        encoded_ep_name = ep_name
            .chars()
            .map(|c| (c as u32).to_string())
            .collect::<Vec<String>>()
            .join(", "),
        f_call = f_call
    );

    (interface_structs, entry_point)
}

fn write_interface_structs(doc: &parse::Spirv, capitalized_ep_name: &str, interface: &[u32],
                           ignore_first_array_in: bool, ignore_first_array_out: bool)
                           -> String {
    let mut input_elements = Vec::new();
    let mut output_elements = Vec::new();

    // Filling `input_elements` and `output_elements`.
    for interface in interface.iter() {
        for i in doc.instructions.iter() {
            match i {
                &parse::Instruction::Variable {
                    result_type_id,
                    result_id,
                    ref storage_class,
                    ..
                } if &result_id == interface => {
                    if is_builtin(doc, result_id) {
                        continue;
                    }

                    let (to_write, ignore_first_array) = match storage_class {
                        &enums::StorageClass::StorageClassInput => (&mut input_elements,
                                                                    ignore_first_array_in),
                        &enums::StorageClass::StorageClassOutput => (&mut output_elements,
                                                                     ignore_first_array_out),
                        _ => continue,
                    };

                    let name = name_from_id(doc, result_id);
                    if name == "__unnamed" {
                        continue;
                    } // FIXME: hack

                    let loc = match location_decoration(doc, result_id) {
                        Some(l) => l,
                        None => panic!("Attribute `{}` (id {}) is missing a location",
                                       name,
                                       result_id),
                    };

                    to_write
                        .push((loc, name, format_from_id(doc, result_type_id, ignore_first_array)));
                },
                _ => (),
            }
        }
    }

    write_interface_struct(&format!("{}Input", capitalized_ep_name), &input_elements) +
        &write_interface_struct(&format!("{}Output", capitalized_ep_name), &output_elements)
}

fn write_interface_struct(struct_name: &str, attributes: &[(u32, String, (String, usize))])
                          -> String {
    // Checking for overlapping elements.
    for (offset, &(loc, ref name, (_, loc_len))) in attributes.iter().enumerate() {
        for &(loc2, ref name2, (_, loc_len2)) in attributes.iter().skip(offset + 1) {
            if loc == loc2 || (loc < loc2 && loc + loc_len as u32 > loc2) ||
                (loc2 < loc && loc2 + loc_len2 as u32 > loc)
            {
                panic!("The locations of attributes `{}` (start={}, size={}) \
                        and `{}` (start={}, size={}) overlap",
                       name,
                       loc,
                       loc_len,
                       name2,
                       loc2,
                       loc_len2);
            }
        }
    }

    let body = attributes
        .iter()
        .enumerate()
        .map(|(num, &(loc, ref name, (ref ty, num_locs)))| {
            assert!(num_locs >= 1);

            format!(
                "if self.num == {} {{
            self.num += 1;

            return Some(::vulkano::pipeline::shader::ShaderInterfaceDefEntry {{
                location: {} .. {},
                format: ::vulkano::format::Format::{},
                name: Some(::std::borrow::Cow::Borrowed(\"{}\"))
            }});
        }}",
                num,
                loc,
                loc as usize + num_locs,
                ty,
                name
            )
        })
        .collect::<Vec<_>>()
        .join("");

    format!(
        "
        #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
        pub struct {name};

        \
         #[allow(unsafe_code)]
        unsafe impl ::vulkano::pipeline::shader::ShaderInterfaceDef for \
         {name} {{
            type Iter = {name}Iter;
            fn elements(&self) -> {name}Iter {{
                \
         {name}Iter {{ num: 0 }}
            }}
        }}

        #[derive(Debug, Copy, Clone)]
        \
         pub struct {name}Iter {{ num: u16 }}
        impl Iterator for {name}Iter {{
            type \
         Item = ::vulkano::pipeline::shader::ShaderInterfaceDefEntry;

            #[inline]
            \
         fn next(&mut self) -> Option<Self::Item> {{
                {body}
                None
            \
         }}

            #[inline]
            fn size_hint(&self) -> (usize, Option<usize>) {{
                \
         let len = ({len} - self.num) as usize;
                (len, Some(len))
            }}
        \
         }}

        impl ExactSizeIterator for {name}Iter {{}}
    ",
        name = struct_name,
        body = body,
        len = attributes.len()
    )
}
<commit_msg>Remove fallback value in execution mode<commit_after>// Copyright (c) 2016 The vulkano developers
// Licensed under the Apache License, Version 2.0
// <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT
// license <LICENSE-MIT or http://opensource.org/licenses/MIT>,
// at your option. All files in the project carrying such
// notice may not be copied, modified, or distributed except
// according to those terms.

use enums;
use parse;

use format_from_id;
use is_builtin;
use location_decoration;
use name_from_id;

pub fn write_entry_point(doc: &parse::Spirv, instruction: &parse::Instruction) -> (String, String) {
    let (execution, id, ep_name, interface) = match instruction {
        &parse::Instruction::EntryPoint {
            ref execution,
            id,
            ref name,
            ref interface,
            ..
        } => {
            (execution, id, name, interface)
        },
        _ => unreachable!(),
    };

    let capitalized_ep_name: String = ep_name
        .chars()
        .take(1)
        .flat_map(|c| c.to_uppercase())
        .chain(ep_name.chars().skip(1))
        .collect();

    let interface_structs =
        write_interface_structs(doc,
                                &capitalized_ep_name,
                                interface,
                                match *execution {
                                    enums::ExecutionModel::ExecutionModelTessellationControl =>
                                        true,
                                    enums::ExecutionModel::ExecutionModelTessellationEvaluation =>
                                        true,
                                    enums::ExecutionModel::ExecutionModelGeometry => true,
                                    _ => false,
                                },
                                match *execution {
                                    enums::ExecutionModel::ExecutionModelTessellationControl =>
                                        true,
                                    _ => false,
                                });

    let (ty, f_call) = match *execution {
        enums::ExecutionModel::ExecutionModelVertex => {
            let t = format!("::vulkano::pipeline::shader::VertexShaderEntryPoint<(), {0}Input, \
                             {0}Output, Layout>",
                            capitalized_ep_name);
            let f = format!("vertex_shader_entry_point(::std::ffi::CStr::from_ptr(NAME.as_ptr() \
                             as *const _), {0}Input, {0}Output, Layout(ShaderStages {{ vertex: \
                             true, .. ShaderStages::none() }}))",
                            capitalized_ep_name);
            (t, f)
        },

        enums::ExecutionModel::ExecutionModelTessellationControl => {
            let t = format!("::vulkano::pipeline::shader::TessControlShaderEntryPoint<(), \
                             {0}Input, {0}Output, Layout>",
                            capitalized_ep_name);
            let f = format!("tess_control_shader_entry_point(::std::ffi::CStr::from_ptr(NAME.\
                             as_ptr() as *const _), {0}Input, {0}Output, Layout(ShaderStages {{ \
                             tessellation_control: true, .. ShaderStages::none() }}))",
                            capitalized_ep_name);
            (t, f)
        },

        enums::ExecutionModel::ExecutionModelTessellationEvaluation => {
            let t = format!("::vulkano::pipeline::shader::TessEvaluationShaderEntryPoint<(), \
                             {0}Input, {0}Output, Layout>",
                            capitalized_ep_name);
            let f = format!("tess_evaluation_shader_entry_point(::std::ffi::CStr::from_ptr(NAME.\
                             as_ptr() as *const _), {0}Input, {0}Output, Layout(ShaderStages {{ \
                             tessellation_evaluation: true, .. ShaderStages::none() }}))",
                            capitalized_ep_name);
            (t, f)
        },

        enums::ExecutionModel::ExecutionModelGeometry => {
            let mut execution_mode = None;

            for instruction in doc.instructions.iter() {
                if let &parse::Instruction::ExecutionMode { target_id, ref mode, .. } = instruction {
                    if target_id != id {
                        continue;
                    }
                    execution_mode = match mode {
                        &enums::ExecutionMode::ExecutionModeInputPoints => Some("Points"),
                        &enums::ExecutionMode::ExecutionModeInputLines => Some("Lines"),
                        &enums::ExecutionMode::ExecutionModeInputLinesAdjacency => Some("LinesWithAdjacency"),
                        &enums::ExecutionMode::ExecutionModeTriangles => Some("Triangles"),
                        &enums::ExecutionMode::ExecutionModeInputTrianglesAdjacency => Some("TrianglesWithAdjacency"),
                        _ => continue,
                    };
                    break;
                }
            }

            let execution_mode = format!("::vulkano::pipeline::shader::GeometryShaderExecutionMode::{0}", execution_mode.unwrap());

            let t = format!("::vulkano::pipeline::shader::GeometryShaderEntryPoint<(), {0}Input, \
                             {0}Output, Layout>",
                            capitalized_ep_name);
            let f = format!("geometry_shader_entry_point(::std::ffi::CStr::from_ptr(NAME.\
                             as_ptr() as *const _), {1}, {0}Input, {0}Output, Layout(ShaderStages {{ \
                             geometry: true, .. ShaderStages::none() }}))",
                            capitalized_ep_name,
                            execution_mode);
            (t, f)
        },

        enums::ExecutionModel::ExecutionModelFragment => {
            let t = format!("::vulkano::pipeline::shader::FragmentShaderEntryPoint<(), {0}Input, \
                             {0}Output, Layout>",
                            capitalized_ep_name);
            let f = format!("fragment_shader_entry_point(::std::ffi::CStr::from_ptr(NAME.\
                             as_ptr() as *const _), {0}Input, {0}Output, Layout(ShaderStages {{ \
                             fragment: true, .. ShaderStages::none() }}))",
                            capitalized_ep_name);
            (t, f)
        },

        enums::ExecutionModel::ExecutionModelGLCompute => {
            (format!("::vulkano::pipeline::shader::ComputeShaderEntryPoint<(), Layout>"),
             format!("compute_shader_entry_point(::std::ffi::CStr::from_ptr(NAME.as_ptr() as \
                      *const _), Layout(ShaderStages {{ compute: true, .. ShaderStages::none() \
                      }}))"))
        },

        enums::ExecutionModel::ExecutionModelKernel => panic!("Kernels are not supported"),
    };

    let entry_point = format!(
        r#"
    /// Returns a logical struct describing the entry point named `{ep_name}`.
    #[inline]
    #[allow(unsafe_code)]
    pub fn {ep_name}_entry_point(&self) -> {ty} {{
        unsafe {{
            #[allow(dead_code)]
            static NAME: [u8; {ep_name_lenp1}] = [{encoded_ep_name}, 0];     // "{ep_name}"
            self.shader.{f_call}
        }}
    }}
            "#,
        ep_name = ep_name,
        ep_name_lenp1 = ep_name.chars().count() + 1,
        ty = ty,
        encoded_ep_name = ep_name
            .chars()
            .map(|c| (c as u32).to_string())
            .collect::<Vec<String>>()
            .join(", "),
        f_call = f_call
    );

    (interface_structs, entry_point)
}

fn write_interface_structs(doc: &parse::Spirv, capitalized_ep_name: &str, interface: &[u32],
                           ignore_first_array_in: bool, ignore_first_array_out: bool)
                           -> String {
    let mut input_elements = Vec::new();
    let mut output_elements = Vec::new();

    // Filling `input_elements` and `output_elements`.
    for interface in interface.iter() {
        for i in doc.instructions.iter() {
            match i {
                &parse::Instruction::Variable {
                    result_type_id,
                    result_id,
                    ref storage_class,
                    ..
                } if &result_id == interface => {
                    if is_builtin(doc, result_id) {
                        continue;
                    }

                    let (to_write, ignore_first_array) = match storage_class {
                        &enums::StorageClass::StorageClassInput => (&mut input_elements,
                                                                    ignore_first_array_in),
                        &enums::StorageClass::StorageClassOutput => (&mut output_elements,
                                                                     ignore_first_array_out),
                        _ => continue,
                    };

                    let name = name_from_id(doc, result_id);
                    if name == "__unnamed" {
                        continue;
                    } // FIXME: hack

                    let loc = match location_decoration(doc, result_id) {
                        Some(l) => l,
                        None => panic!("Attribute `{}` (id {}) is missing a location",
                                       name,
                                       result_id),
                    };

                    to_write
                        .push((loc, name, format_from_id(doc, result_type_id, ignore_first_array)));
                },
                _ => (),
            }
        }
    }

    write_interface_struct(&format!("{}Input", capitalized_ep_name), &input_elements) +
        &write_interface_struct(&format!("{}Output", capitalized_ep_name), &output_elements)
}

fn write_interface_struct(struct_name: &str, attributes: &[(u32, String, (String, usize))])
                          -> String {
    // Checking for overlapping elements.
    for (offset, &(loc, ref name, (_, loc_len))) in attributes.iter().enumerate() {
        for &(loc2, ref name2, (_, loc_len2)) in attributes.iter().skip(offset + 1) {
            if loc == loc2 || (loc < loc2 && loc + loc_len as u32 > loc2) ||
                (loc2 < loc && loc2 + loc_len2 as u32 > loc)
            {
                panic!("The locations of attributes `{}` (start={}, size={}) \
                        and `{}` (start={}, size={}) overlap",
                       name,
                       loc,
                       loc_len,
                       name2,
                       loc2,
                       loc_len2);
            }
        }
    }

    let body = attributes
        .iter()
        .enumerate()
        .map(|(num, &(loc, ref name, (ref ty, num_locs)))| {
            assert!(num_locs >= 1);

            format!(
                "if self.num == {} {{
            self.num += 1;

            return Some(::vulkano::pipeline::shader::ShaderInterfaceDefEntry {{
                location: {} .. {},
                format: ::vulkano::format::Format::{},
                name: Some(::std::borrow::Cow::Borrowed(\"{}\"))
            }});
        }}",
                num,
                loc,
                loc as usize + num_locs,
                ty,
                name
            )
        })
        .collect::<Vec<_>>()
        .join("");

    format!(
        "
        #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
        pub struct {name};

        \
         #[allow(unsafe_code)]
        unsafe impl ::vulkano::pipeline::shader::ShaderInterfaceDef for \
         {name} {{
            type Iter = {name}Iter;
            fn elements(&self) -> {name}Iter {{
                \
         {name}Iter {{ num: 0 }}
            }}
        }}

        #[derive(Debug, Copy, Clone)]
        \
         pub struct {name}Iter {{ num: u16 }}
        impl Iterator for {name}Iter {{
            type \
         Item = ::vulkano::pipeline::shader::ShaderInterfaceDefEntry;

            #[inline]
            \
         fn next(&mut self) -> Option<Self::Item> {{
                {body}
                None
            \
         }}

            #[inline]
            fn size_hint(&self) -> (usize, Option<usize>) {{
                \
         let len = ({len} - self.num) as usize;
                (len, Some(len))
            }}
        \
         }}

        impl ExactSizeIterator for {name}Iter {{}}
    ",
        name = struct_name,
        body = body,
        len = attributes.len()
    )
}
<|endoftext|>


<commit_before>use std::iter::FromIterator;
use std::mem;
use union_find::{Union, UnionFind, UnionResult, QuickFindUf as Uf};
use slsr_core::puzzle::{Edge, Puzzle, Side};
use slsr_core::geom::{CellId, Geom, Point, Move, OUTSIDE_CELL_ID};

use ::{Error, State, SolverResult};
use ::model::side_map::SideMap;

#[derive(Debug)]
pub struct Area {
    coord: CellId,
    side: State<Side>,
    unknown_edge: Vec<CellId>,
    sum_of_hint: u32,
    size: usize
}

impl Clone for Area {
    fn clone(&self) -> Area {
        Area {
            coord: self.coord,
            side: self.side,
            unknown_edge: self.unknown_edge.clone(),
            sum_of_hint: self.sum_of_hint,
            size: self.size
        }
    }

    fn clone_from(&mut self, other: &Area) {
        self.coord = other.coord;
        self.side = other.side;
        self.unknown_edge.clone_from(&other.unknown_edge);
        self.sum_of_hint = other.sum_of_hint;
        self.size = other.size;
    }
}

impl Area {
    pub fn coord(&self) -> CellId { self.coord }
    pub fn side(&self) -> State<Side> { self.side }
    pub fn unknown_edge(&self) -> &[CellId] { &self.unknown_edge }
    pub fn sum_of_hint(&self) -> u32 { self.sum_of_hint }
}

impl Area {
    fn new(p: Point, puzzle: &Puzzle, side_map: &mut SideMap) -> Area {
        let cp = puzzle.point_to_cellid(p);
        let sum = puzzle.hint(p).unwrap_or(0) as u32;

        let mut edge = vec![];
        if cp != OUTSIDE_CELL_ID {
            for &r in &Move::ALL_DIRECTIONS {
                let cp_r = puzzle.point_to_cellid(p + r);
                if side_map.get_edge(cp, cp_r) == State::Unknown {
                    edge.push(cp_r);
                }
            }
        } else {
            let points = puzzle.points_in_column(0)
                .chain(puzzle.points_in_column(puzzle.column() - 1))
                .chain(puzzle.points_in_row(0))
                .chain(puzzle.points_in_row(puzzle.row() - 1));
            for p2 in points {
                let cp2 = puzzle.point_to_cellid(p2);
                if side_map.get_edge(cp, cp2) == State::Unknown {
                    edge.push(cp2);
                }
            }
        }
        edge.sort();
        edge.dedup();

        Area {
            coord: cp,
            side: side_map.get_side(cp),
            unknown_edge: edge,
            sum_of_hint: sum,
            size: 1
        }
    }
}

impl Union for Area {
    fn union(mut lval: Area, mut rval: Area) -> UnionResult<Area> {
        let coord = if lval.coord < rval.coord {
            lval.coord
        } else {
            rval.coord
        };
        let side = match (lval.side, rval.side) {
            (State::Conflict, _) | (_, State::Conflict) => State::Conflict,
            (State::Unknown, x) | (x, State::Unknown) => x,
            (State::Fixed(l), State::Fixed(r)) => {
                if l == r {
                    State::Fixed(l)
                } else {
                    State::Conflict
                }
            }
        };
        let unknown_edge = {
            if lval.unknown_edge.is_empty() {
                rval.unknown_edge
            } else {
                lval.unknown_edge.append(&mut rval.unknown_edge);
                lval.unknown_edge
            }
        };
        let area = Area {
            coord: coord,
            side: side,
            unknown_edge: unknown_edge,
            sum_of_hint: lval.sum_of_hint + rval.sum_of_hint,
            size: lval.size + rval.size
        };
        if lval.size >= rval.size {
            UnionResult::Left(area)
        } else {
            UnionResult::Right(area)
        }
    }
}

#[derive(Debug)]
pub struct ConnectMap {
    sum_of_hint: u32,
    uf: Uf<Area>
}

impl Clone for ConnectMap {
    fn clone(&self) -> ConnectMap {
        ConnectMap {
            sum_of_hint: self.sum_of_hint,
            uf: self.uf.clone()
        }
    }

    fn clone_from(&mut self, other: &ConnectMap) {
        self.sum_of_hint = other.sum_of_hint;
        self.uf.clone_from(&other.uf);
    }
}

impl ConnectMap {
    pub fn new(puzzle: &Puzzle, side_map: &mut SideMap) -> ConnectMap {
        let size = puzzle.size();
        let cell_len = size.cell_len();

        let mut uf = Uf::from_iter(
            (0..cell_len)
                .map(|id| size.cellid_to_point(CellId::new(id)))
                .map(|p| Area::new(p, puzzle, side_map)));

        let mut sum_of_hint = 0;
        for i in 0..cell_len {
            sum_of_hint += uf.get(i).sum_of_hint;
        }

        let mut conn_map = ConnectMap {
            sum_of_hint: sum_of_hint,
            uf: uf
        };

        for p in size.points() {
            let cp = size.point_to_cellid(p);
            for &r in &Move::ALL_DIRECTIONS {
                let p2 = p + r;
                let cp2 = size.point_to_cellid(p2);
                if side_map.get_edge(cp, cp2) == State::Fixed(Edge::Cross) {
                    conn_map.union(cp, cp2);
                }
            }
        }
        conn_map
    }

    pub fn cell_len(&self) -> usize { self.uf.size() }
    pub fn sum_of_hint(&self) -> u32 { self.sum_of_hint }

    pub fn sync(&mut self, side_map: &mut SideMap) -> SolverResult<()> {
        loop {
            let mut updated = false;
            for i in 0..self.cell_len() {
                let c = CellId::new(i);
                updated |= update_conn(side_map, self, c)
            }
            if !updated {
                break
            }
        }

        for i in 0..self.cell_len() {
            let c = CellId::new(i);
            try!(update_area(side_map, self, c));
        }

        Ok(())
    }

    pub fn count_area(&mut self) -> usize {
        (0..self.cell_len())
            .map(CellId::new)
            .filter(|&c| self.get(c).coord() == c)
            .count()
    }

    pub fn union(&mut self, i: CellId, j: CellId) -> bool {
        self.uf.union(i.id(), j.id())
    }
    pub fn get(&mut self, i: CellId) -> &Area {
        self.uf.get(i.id())
    }
    pub fn get_mut(&mut self, i: CellId) -> &mut Area {
        self.uf.get_mut(i.id())
    }
}

fn update_conn(side_map: &mut SideMap, conn_map: &mut ConnectMap, p: CellId)
               -> bool
{
    let mut unknown_edge = {
        let a = conn_map.get_mut(p);
        if a.coord != p { return false }
        mem::replace(&mut a.unknown_edge, vec![])
    };

    let mut updated = false;
    for &p2 in &unknown_edge {
        if side_map.get_edge(p, p2) == State::Fixed(Edge::Cross) {
            updated |= conn_map.union(p, p2);
        }
    }

    let mut area = conn_map.get_mut(p);
    if area.unknown_edge.is_empty() {
        area.unknown_edge = unknown_edge;
    } else {
        area.unknown_edge.append(&mut unknown_edge);
    }

    updated
}

fn update_area(side_map: &mut SideMap, conn_map: &mut ConnectMap, p: CellId)
               -> SolverResult<()>
{
    let mut unknown_edge = {
        let a = conn_map.get_mut(p);
        if a.coord != p { return Ok(())}
        mem::replace(&mut a.unknown_edge, vec![])
    };

    unsafe {
        let ptr = unknown_edge.as_mut_ptr();
        let mut w = 0;
        for r in 0..unknown_edge.len() {
            let read = ptr.offset(r as isize);
            match side_map.get_edge(p, *read) {
                State::Fixed(_) => {}
                State::Unknown => {
                    *read = conn_map.get(*read).coord();

                    let write = ptr.offset(w as isize);
                    mem::swap(&mut *read, &mut *write);
                    w += 1;
                }
                State::Conflict => {
                    return Err(Error::invalid_board())
                }
            }
        }

        unknown_edge.truncate(w);
    }

    unknown_edge.sort();
    unknown_edge.dedup();

    let mut area = conn_map.get_mut(p);
    area.side = side_map.get_side(p);
    area.unknown_edge = unknown_edge;

    Ok(())
}
<commit_msg>solver: small performance improvements for ConnectMap::sync<commit_after>use std::iter::FromIterator;
use std::mem;
use union_find::{Union, UnionFind, UnionResult, QuickFindUf as Uf};
use slsr_core::puzzle::{Edge, Puzzle, Side};
use slsr_core::geom::{CellId, Geom, Point, Move, OUTSIDE_CELL_ID};

use ::{Error, State, SolverResult};
use ::model::side_map::SideMap;

#[derive(Debug)]
pub struct Area {
    coord: CellId,
    side: State<Side>,
    unknown_edge: Vec<CellId>,
    sum_of_hint: u32,
    size: usize
}

impl Clone for Area {
    fn clone(&self) -> Area {
        Area {
            coord: self.coord,
            side: self.side,
            unknown_edge: self.unknown_edge.clone(),
            sum_of_hint: self.sum_of_hint,
            size: self.size
        }
    }

    fn clone_from(&mut self, other: &Area) {
        self.coord = other.coord;
        self.side = other.side;
        self.unknown_edge.clone_from(&other.unknown_edge);
        self.sum_of_hint = other.sum_of_hint;
        self.size = other.size;
    }
}

impl Area {
    pub fn coord(&self) -> CellId { self.coord }
    pub fn side(&self) -> State<Side> { self.side }
    pub fn unknown_edge(&self) -> &[CellId] { &self.unknown_edge }
    pub fn sum_of_hint(&self) -> u32 { self.sum_of_hint }
}

impl Area {
    fn new(p: Point, puzzle: &Puzzle, side_map: &mut SideMap) -> Area {
        let cp = puzzle.point_to_cellid(p);
        let sum = puzzle.hint(p).unwrap_or(0) as u32;

        let mut edge = vec![];
        if cp != OUTSIDE_CELL_ID {
            for &r in &Move::ALL_DIRECTIONS {
                let cp_r = puzzle.point_to_cellid(p + r);
                if side_map.get_edge(cp, cp_r) == State::Unknown {
                    edge.push(cp_r);
                }
            }
        } else {
            let points = puzzle.points_in_column(0)
                .chain(puzzle.points_in_column(puzzle.column() - 1))
                .chain(puzzle.points_in_row(0))
                .chain(puzzle.points_in_row(puzzle.row() - 1));
            for p2 in points {
                let cp2 = puzzle.point_to_cellid(p2);
                if side_map.get_edge(cp, cp2) == State::Unknown {
                    edge.push(cp2);
                }
            }
        }
        edge.sort();
        edge.dedup();

        Area {
            coord: cp,
            side: side_map.get_side(cp),
            unknown_edge: edge,
            sum_of_hint: sum,
            size: 1
        }
    }
}

impl Union for Area {
    fn union(mut lval: Area, mut rval: Area) -> UnionResult<Area> {
        let coord = if lval.coord < rval.coord {
            lval.coord
        } else {
            rval.coord
        };
        let side = match (lval.side, rval.side) {
            (State::Conflict, _) | (_, State::Conflict) => State::Conflict,
            (State::Unknown, x) | (x, State::Unknown) => x,
            (State::Fixed(l), State::Fixed(r)) => {
                if l == r {
                    State::Fixed(l)
                } else {
                    State::Conflict
                }
            }
        };
        let unknown_edge = {
            if lval.unknown_edge.is_empty() {
                rval.unknown_edge
            } else {
                lval.unknown_edge.append(&mut rval.unknown_edge);
                lval.unknown_edge
            }
        };
        let area = Area {
            coord: coord,
            side: side,
            unknown_edge: unknown_edge,
            sum_of_hint: lval.sum_of_hint + rval.sum_of_hint,
            size: lval.size + rval.size
        };
        if lval.size >= rval.size {
            UnionResult::Left(area)
        } else {
            UnionResult::Right(area)
        }
    }
}

#[derive(Debug)]
pub struct ConnectMap {
    sum_of_hint: u32,
    uf: Uf<Area>
}

impl Clone for ConnectMap {
    fn clone(&self) -> ConnectMap {
        ConnectMap {
            sum_of_hint: self.sum_of_hint,
            uf: self.uf.clone()
        }
    }

    fn clone_from(&mut self, other: &ConnectMap) {
        self.sum_of_hint = other.sum_of_hint;
        self.uf.clone_from(&other.uf);
    }
}

impl ConnectMap {
    pub fn new(puzzle: &Puzzle, side_map: &mut SideMap) -> ConnectMap {
        let size = puzzle.size();
        let cell_len = size.cell_len();

        let mut uf = Uf::from_iter(
            (0..cell_len)
                .map(|id| size.cellid_to_point(CellId::new(id)))
                .map(|p| Area::new(p, puzzle, side_map)));

        let mut sum_of_hint = 0;
        for i in 0..cell_len {
            sum_of_hint += uf.get(i).sum_of_hint;
        }

        let mut conn_map = ConnectMap {
            sum_of_hint: sum_of_hint,
            uf: uf
        };

        for p in size.points() {
            let cp = size.point_to_cellid(p);
            for &r in &Move::ALL_DIRECTIONS {
                let p2 = p + r;
                let cp2 = size.point_to_cellid(p2);
                if side_map.get_edge(cp, cp2) == State::Fixed(Edge::Cross) {
                    conn_map.union(cp, cp2);
                }
            }
        }
        conn_map
    }

    pub fn cell_len(&self) -> usize { self.uf.size() }
    pub fn sum_of_hint(&self) -> u32 { self.sum_of_hint }

    pub fn sync(&mut self, side_map: &mut SideMap) -> SolverResult<()> {
        for i in 0..self.cell_len() {
            let c = CellId::new(i);
            update_conn(side_map, self, c);
        }
        for i in 0..self.cell_len() {
            let c = CellId::new(i);
            try!(update_area(side_map, self, c));
        }

        Ok(())
    }

    pub fn count_area(&mut self) -> usize {
        (0..self.cell_len())
            .map(CellId::new)
            .filter(|&c| self.get(c).coord() == c)
            .count()
    }

    pub fn union(&mut self, i: CellId, j: CellId) -> bool {
        self.uf.union(i.id(), j.id())
    }
    pub fn get(&mut self, i: CellId) -> &Area {
        self.uf.get(i.id())
    }
    pub fn get_mut(&mut self, i: CellId) -> &mut Area {
        self.uf.get_mut(i.id())
    }
}

fn update_conn(side_map: &mut SideMap, conn_map: &mut ConnectMap, p: CellId) {
    let mut unknown_edge = {
        let a = conn_map.get_mut(p);
        if a.coord != p { return }
        mem::replace(&mut a.unknown_edge, vec![])
    };

    for &p2 in &unknown_edge {
        if side_map.get_edge(p, p2) == State::Fixed(Edge::Cross) {
            conn_map.union(p, p2);
        }
    }

    let mut need_update = None;
    {
        let mut area = conn_map.get_mut(p);
        if area.unknown_edge.is_empty() {
            area.unknown_edge = unknown_edge;
        } else {
            area.unknown_edge.append(&mut unknown_edge);
            if area.coord <= p {
                need_update = Some(area.coord);
            }
        }
    }

    if let Some(coord) = need_update {
        update_conn(side_map, conn_map, coord);
    }
}

fn update_area(side_map: &mut SideMap, conn_map: &mut ConnectMap, p: CellId)
               -> SolverResult<()>
{
    let mut unknown_edge = {
        let a = conn_map.get_mut(p);
        if a.coord != p { return Ok(())}
        mem::replace(&mut a.unknown_edge, vec![])
    };

    unsafe {
        // Assume the elements of unknown_edge is copyable.
        let ptr = unknown_edge.as_mut_ptr();
        let mut w = 0;
        for r in 0..unknown_edge.len() {
            let read = ptr.offset(r as isize);
            match side_map.get_edge(p, *read) {
                State::Fixed(_) => {}
                State::Unknown => {
                    let write = ptr.offset(w as isize);
                    *write = conn_map.get(*read).coord();
                    w += 1;
                }
                State::Conflict => {
                    return Err(Error::invalid_board())
                }
            }
        }
        unknown_edge.truncate(w);
    }

    unknown_edge.sort();
    unknown_edge.dedup();

    let mut area = conn_map.get_mut(p);
    area.side = side_map.get_side(p);
    area.unknown_edge = unknown_edge;

    Ok(())
}
<|endoftext|>


<commit_before>// Code for annotating snippets.

use crate::Level;

#[derive(Clone, Debug, PartialOrd, Ord, PartialEq, Eq)]
pub struct Line {
    pub line_index: usize,
    pub annotations: Vec<Annotation>,
}

#[derive(Clone, Debug, PartialOrd, Ord, PartialEq, Eq)]
pub struct MultilineAnnotation {
    pub depth: usize,
    pub line_start: usize,
    pub line_end: usize,
    pub start_col: usize,
    pub end_col: usize,
    pub is_primary: bool,
    pub label: Option<String>,
    pub overlaps: bool,
}

impl MultilineAnnotation {
    pub fn increase_depth(&mut self) {
        self.depth += 1;
    }

    /// Compare two `MultilineAnnotation`s considering only the `Span` they cover.
    pub fn same_span(&self, other: &MultilineAnnotation) -> bool {
        self.line_start == other.line_start && self.line_end == other.line_end
            && self.start_col == other.start_col && self.end_col == other.end_col
    }

    pub fn as_start(&self) -> Annotation {
        Annotation {
            start_col: self.start_col,
            end_col: self.start_col + 1,
            is_primary: self.is_primary,
            label: None,
            annotation_type: AnnotationType::MultilineStart(self.depth)
        }
    }

    pub fn as_end(&self) -> Annotation {
        Annotation {
            start_col: self.end_col.saturating_sub(1),
            end_col: self.end_col,
            is_primary: self.is_primary,
            label: self.label.clone(),
            annotation_type: AnnotationType::MultilineEnd(self.depth)
        }
    }

    pub fn as_line(&self) -> Annotation {
        Annotation {
            start_col: 0,
            end_col: 0,
            is_primary: self.is_primary,
            label: None,
            annotation_type: AnnotationType::MultilineLine(self.depth)
        }
    }
}

#[derive(Clone, Debug, PartialOrd, Ord, PartialEq, Eq)]
pub enum AnnotationType {
    /// Annotation under a single line of code
    Singleline,

    /// Annotation enclosing the first and last character of a multiline span
    Multiline(MultilineAnnotation),

    // The Multiline type above is replaced with the following three in order
    // to reuse the current label drawing code.
    //
    // Each of these corresponds to one part of the following diagram:
    //
    //     x |   foo(1 + bar(x,
    //       |  _________^              < MultilineStart
    //     x | |             y),        < MultilineLine
    //       | |______________^ label   < MultilineEnd
    //     x |       z);
    /// Annotation marking the first character of a fully shown multiline span
    MultilineStart(usize),
    /// Annotation marking the last character of a fully shown multiline span
    MultilineEnd(usize),
    /// Line at the left enclosing the lines of a fully shown multiline span
    // Just a placeholder for the drawing algorithm, to know that it shouldn't skip the first 4
    // and last 2 lines of code. The actual line is drawn in `emit_message_default` and not in
    // `draw_multiline_line`.
    MultilineLine(usize),
}

#[derive(Clone, Debug, PartialOrd, Ord, PartialEq, Eq)]
pub struct Annotation {
    /// Start column, 0-based indexing -- counting *characters*, not
    /// utf-8 bytes. Note that it is important that this field goes
    /// first, so that when we sort, we sort orderings by start
    /// column.
    pub start_col: usize,

    /// End column within the line (exclusive)
    pub end_col: usize,

    /// Is this annotation derived from primary span
    pub is_primary: bool,

    /// Optional label to display adjacent to the annotation.
    pub label: Option<String>,

    /// Is this a single line, multiline or multiline span minimized down to a
    /// smaller span.
    pub annotation_type: AnnotationType,
}

impl Annotation {
    /// Whether this annotation is a vertical line placeholder.
    pub fn is_line(&self) -> bool {
        if let AnnotationType::MultilineLine(_) = self.annotation_type {
            true
        } else {
            false
        }
    }

    pub fn is_multiline(&self) -> bool {
        match self.annotation_type {
            AnnotationType::Multiline(_) |
            AnnotationType::MultilineStart(_) |
            AnnotationType::MultilineLine(_) |
            AnnotationType::MultilineEnd(_) => true,
            _ => false,
        }
    }

    pub fn len(&self) -> usize {
        // Account for usize underflows
        if self.end_col > self.start_col {
            self.end_col - self.start_col
        } else {
            self.start_col - self.end_col
        }
    }

    pub fn has_label(&self) -> bool {
        if let Some(ref label) = self.label {
            // Consider labels with no text as effectively not being there
            // to avoid weird output with unnecessary vertical lines, like:
            //
            //     X | fn foo(x: u32) {
            //       | -------^------
            //       | |      |
            //       | |
            //       |
            //
            // Note that this would be the complete output users would see.
            label.len() > 0
        } else {
            false
        }
    }

    pub fn takes_space(&self) -> bool {
        // Multiline annotations always have to keep vertical space.
        match self.annotation_type {
            AnnotationType::MultilineStart(_) |
            AnnotationType::MultilineEnd(_) => true,
            _ => false,
        }
    }
}

#[derive(Debug)]
pub struct StyledString {
    pub text: String,
    pub style: Style,
}

#[derive(Copy, Clone, Debug, PartialEq, Hash, RustcEncodable, RustcDecodable)]
pub enum Style {
    MainHeaderMsg,
    HeaderMsg,
    LineAndColumn,
    LineNumber,
    Quotation,
    UnderlinePrimary,
    UnderlineSecondary,
    LabelPrimary,
    LabelSecondary,
    OldSchoolNoteText,
    NoStyle,
    Level(Level),
    Highlight,
}
<commit_msg>Fix MultilineAnnotation field name<commit_after>// Code for annotating snippets.

use crate::Level;

#[derive(Clone, Debug, PartialOrd, Ord, PartialEq, Eq)]
pub struct Line {
    pub line_index: usize,
    pub annotations: Vec<Annotation>,
}

#[derive(Clone, Debug, PartialOrd, Ord, PartialEq, Eq)]
pub struct MultilineAnnotation {
    pub depth: usize,
    pub line_start: usize,
    pub line_end: usize,
    pub start_col: usize,
    pub end_col: usize,
    pub is_primary: bool,
    pub label: Option<String>,
    pub overlaps_exactly: bool,
}

impl MultilineAnnotation {
    pub fn increase_depth(&mut self) {
        self.depth += 1;
    }

    /// Compare two `MultilineAnnotation`s considering only the `Span` they cover.
    pub fn same_span(&self, other: &MultilineAnnotation) -> bool {
        self.line_start == other.line_start && self.line_end == other.line_end
            && self.start_col == other.start_col && self.end_col == other.end_col
    }

    pub fn as_start(&self) -> Annotation {
        Annotation {
            start_col: self.start_col,
            end_col: self.start_col + 1,
            is_primary: self.is_primary,
            label: None,
            annotation_type: AnnotationType::MultilineStart(self.depth)
        }
    }

    pub fn as_end(&self) -> Annotation {
        Annotation {
            start_col: self.end_col.saturating_sub(1),
            end_col: self.end_col,
            is_primary: self.is_primary,
            label: self.label.clone(),
            annotation_type: AnnotationType::MultilineEnd(self.depth)
        }
    }

    pub fn as_line(&self) -> Annotation {
        Annotation {
            start_col: 0,
            end_col: 0,
            is_primary: self.is_primary,
            label: None,
            annotation_type: AnnotationType::MultilineLine(self.depth)
        }
    }
}

#[derive(Clone, Debug, PartialOrd, Ord, PartialEq, Eq)]
pub enum AnnotationType {
    /// Annotation under a single line of code
    Singleline,

    /// Annotation enclosing the first and last character of a multiline span
    Multiline(MultilineAnnotation),

    // The Multiline type above is replaced with the following three in order
    // to reuse the current label drawing code.
    //
    // Each of these corresponds to one part of the following diagram:
    //
    //     x |   foo(1 + bar(x,
    //       |  _________^              < MultilineStart
    //     x | |             y),        < MultilineLine
    //       | |______________^ label   < MultilineEnd
    //     x |       z);
    /// Annotation marking the first character of a fully shown multiline span
    MultilineStart(usize),
    /// Annotation marking the last character of a fully shown multiline span
    MultilineEnd(usize),
    /// Line at the left enclosing the lines of a fully shown multiline span
    // Just a placeholder for the drawing algorithm, to know that it shouldn't skip the first 4
    // and last 2 lines of code. The actual line is drawn in `emit_message_default` and not in
    // `draw_multiline_line`.
    MultilineLine(usize),
}

#[derive(Clone, Debug, PartialOrd, Ord, PartialEq, Eq)]
pub struct Annotation {
    /// Start column, 0-based indexing -- counting *characters*, not
    /// utf-8 bytes. Note that it is important that this field goes
    /// first, so that when we sort, we sort orderings by start
    /// column.
    pub start_col: usize,

    /// End column within the line (exclusive)
    pub end_col: usize,

    /// Is this annotation derived from primary span
    pub is_primary: bool,

    /// Optional label to display adjacent to the annotation.
    pub label: Option<String>,

    /// Is this a single line, multiline or multiline span minimized down to a
    /// smaller span.
    pub annotation_type: AnnotationType,
}

impl Annotation {
    /// Whether this annotation is a vertical line placeholder.
    pub fn is_line(&self) -> bool {
        if let AnnotationType::MultilineLine(_) = self.annotation_type {
            true
        } else {
            false
        }
    }

    pub fn is_multiline(&self) -> bool {
        match self.annotation_type {
            AnnotationType::Multiline(_) |
            AnnotationType::MultilineStart(_) |
            AnnotationType::MultilineLine(_) |
            AnnotationType::MultilineEnd(_) => true,
            _ => false,
        }
    }

    pub fn len(&self) -> usize {
        // Account for usize underflows
        if self.end_col > self.start_col {
            self.end_col - self.start_col
        } else {
            self.start_col - self.end_col
        }
    }

    pub fn has_label(&self) -> bool {
        if let Some(ref label) = self.label {
            // Consider labels with no text as effectively not being there
            // to avoid weird output with unnecessary vertical lines, like:
            //
            //     X | fn foo(x: u32) {
            //       | -------^------
            //       | |      |
            //       | |
            //       |
            //
            // Note that this would be the complete output users would see.
            label.len() > 0
        } else {
            false
        }
    }

    pub fn takes_space(&self) -> bool {
        // Multiline annotations always have to keep vertical space.
        match self.annotation_type {
            AnnotationType::MultilineStart(_) |
            AnnotationType::MultilineEnd(_) => true,
            _ => false,
        }
    }
}

#[derive(Debug)]
pub struct StyledString {
    pub text: String,
    pub style: Style,
}

#[derive(Copy, Clone, Debug, PartialEq, Hash, RustcEncodable, RustcDecodable)]
pub enum Style {
    MainHeaderMsg,
    HeaderMsg,
    LineAndColumn,
    LineNumber,
    Quotation,
    UnderlinePrimary,
    UnderlineSecondary,
    LabelPrimary,
    LabelSecondary,
    OldSchoolNoteText,
    NoStyle,
    Level(Level),
    Highlight,
}
<|endoftext|>


<commit_before>//! #Password Hashing
//!
//! Secret keys used to encrypt or sign confidential data have to be chosen from
//! a very large keyspace. However, passwords are usually short, human-generated
//! strings, making dictionary attacks practical.
//!
//! The pwhash operation derives a secret key of any size from a password and a
//! salt.
//!
//! - The generated key has the size defined by the application, no matter what
//!   the password length is.
//! - The same password hashed with same parameters will
//!   always produce the same key.
//! - The same password hashed with different salts
//!   will produce different keys.
//! - The function deriving a key from a password
//!   and a salt is CPU intensive and intentionally requires a fair amount of
//!   memory. Therefore, it mitigates brute-force attacks by requiring a
//!   significant effort to verify each password.
//!
//! Common use cases:
//!
//! - Protecting an on-disk secret key with a password,
//! - Password storage, or rather: storing what it takes to verify a password
//!   without having to store the actual password.
pub use self::scryptsalsa208sha256::*;
pub mod scryptsalsa208sha256;
<commit_msg>Small documentation update<commit_after>//! Password Hashing
//!
//! Secret keys used to encrypt or sign confidential data have to be chosen from
//! a very large keyspace. However, passwords are usually short, human-generated
//! strings, making dictionary attacks practical.
//!
//! The pwhash operation derives a secret key of any size from a password and a
//! salt.
//!
//! - The generated key has the size defined by the application, no matter what
//!   the password length is.
//! - The same password hashed with same parameters will
//!   always produce the same key.
//! - The same password hashed with different salts
//!   will produce different keys.
//! - The function deriving a key from a password
//!   and a salt is CPU intensive and intentionally requires a fair amount of
//!   memory. Therefore, it mitigates brute-force attacks by requiring a
//!   significant effort to verify each password.
//!
//! Common use cases:
//!
//! - Protecting an on-disk secret key with a password,
//! - Password storage, or rather: storing what it takes to verify a password
//!   without having to store the actual password.
pub use self::scryptsalsa208sha256::*;
pub mod scryptsalsa208sha256;
<|endoftext|>


<commit_before>use libc::{c_char, c_uint};
use llvm_sys::prelude::{LLVMValueRef, LLVMModuleRef};
use llvm_sys::analysis::LLVMVerifierFailureAction;
use llvm_sys::{analysis, core, linker, LLVMModule};
use llvm_sys::transforms::pass_manager_builder as builder;
use llvm_sys::transforms::ipo;
use llvm_sys::bit_writer as writer;
use llvm_sys::bit_reader as reader;
use llvm_sys::ir_reader;
use cbox::{CBox, CSemiBox};
use std::ffi::CString;
use std::iter::{Iterator, IntoIterator};
use std::io::{Error, ErrorKind};
use std::io::Result as IoResult;
use std::{env, fmt, mem, ptr};
use std::marker::PhantomData;
use std::path::Path;
use std::process::{Command, Child};
use super::buffer::MemoryBuffer;
use super::context::{Context, GetContext};
use super::value::{Alias, Function, GlobalValue, GlobalVariable, Value};
use super::types::Type;
use super::util;

/// Represents a single compilation unit of code.
///
/// This is attached to the lifetime of the context that constructs it, but is owned by the `CSemiBox`.
pub struct Module(PhantomData<[u8]>);
native_ref!(&Module = LLVMModuleRef);
impl Module {
    /// Create a new module in the context given with the name given.
    ///
    /// The lifetime of the module will match the lifetime of the context
    /// you instance it in because the context contains it.
    ///
    /// ```rust
    /// use llvm::*;
    /// let context = Context::new();
    /// let context = context.as_semi();
    /// let module = Module::new("name", &context);
    /// println!("{:?}", module)
    /// ```
    pub fn new<'a>(name: &str, context: &'a Context) -> CSemiBox<'a, Module> {
        let c_name = CString::new(name).unwrap();
        unsafe {
            CSemiBox::new(core::LLVMModuleCreateWithNameInContext(
                c_name.as_ptr(),
                context.into(),
            ))
        }
    }
    /// Add a global to the module with the given type and name.
    pub fn add_global<'a>(&'a self, name: &str, ty: &'a Type) -> &'a GlobalVariable {
        util::with_cstr(name, |ptr| unsafe {
            core::LLVMAddGlobal(self.into(), ty.into(), ptr).into()
        })
    }
    /// Add a global variable to the module with the given type, name and initial value.
    pub fn add_global_in_address_space<'a>(
        &'a self,
        name: &str,
        ty: &'a Type,
        address: AddressSpace,
    ) -> &'a GlobalVariable {
        util::with_cstr(name, |ptr| unsafe {
            core::LLVMAddGlobalInAddressSpace(self.into(), ty.into(), ptr, address as u32).into()
        })
    }
    /// Add a global variable to the module with the given type, name and initial value.
    pub fn add_global_variable<'a>(&'a self, name: &str, val: &'a Value) -> &'a GlobalVariable {
        let global = self.add_global(name, val.get_type());
        global.set_initializer(val);
        global
    }
    /// Add a global to the module with the given type and name.
    pub fn add_global_alias<'a>(&'a self, name: &str, val: &'a GlobalValue) -> &'a Alias {
        util::with_cstr(name, |ptr| unsafe {
            core::LLVMAddAlias(self.into(), val.get_type().into(), val.into(), ptr).into()
        })
    }
    /// Get the global with the name given, or `None` if no global with that name exists.
    pub fn get_global<'a>(&'a self, name: &str) -> Option<&'a GlobalValue> {
        util::with_cstr(name, |ptr| unsafe {
            let ptr = core::LLVMGetNamedGlobal(self.into(), ptr);
            util::ptr_to_null(ptr)
        })
    }
    /// Parse this bitcode file into a module, or return an error string.
    pub fn parse_bitcode<'a>(
        context: &'a Context,
        path: &str,
    ) -> Result<CSemiBox<'a, Module>, CBox<str>> {
        unsafe {
            let mut out = mem::uninitialized();
            let err = mem::uninitialized();
            let buf = try!(MemoryBuffer::new_from_file(path));
            if reader::LLVMParseBitcodeInContext2(context.into(), buf.as_ptr(), &mut out) == 1 {
                // TODO: Read error from diagnostics
                Err(CBox::new(err))
            } else {
                Ok(CSemiBox::new(out))
            }
        }
    }
    /// Write this module's bitcode to the path given.
    pub fn write_bitcode(&self, path: &str) -> IoResult<()> {
        util::with_cstr(path, |cpath| unsafe {
            if writer::LLVMWriteBitcodeToFile(self.into(), cpath) != 0 {
                Err(Error::new(
                    ErrorKind::Other,
                    &format!("could not write to {}", path) as &str,
                ))
            } else {
                Ok(())
            }
        })
    }
    /// Parse IR assembly unto a module, or return an error string.
    pub fn parse_ir_from_str<'a>(
        context: &'a Context,
        s: &str,
    ) -> Result<CSemiBox<'a, Module>, CBox<str>> {
        unsafe {
            let mut out = mem::uninitialized();
            let mut err = mem::uninitialized();
            let buf = try!(MemoryBuffer::new_from_str(s, None));
            if ir_reader::LLVMParseIRInContext(
                context.into(),
                buf.as_ptr(),
                &mut out,
                &mut err,
            ) == 1
            {
                Err(CBox::new(err))
            } else {
                Ok(CSemiBox::new(out))
            }
        }
    }
    /// Add a function to the module with the name given.
    pub fn add_function<'a>(&'a self, name: &str, sig: &'a Type) -> &'a mut Function {
        let c_name = CString::new(name).unwrap();
        unsafe { core::LLVMAddFunction(self.into(), c_name.as_ptr(), sig.into()) }.into()
    }
    /// Returns the function with the name given, or `None` if no function with that name exists.
    pub fn get_function<'a>(&'a self, name: &str) -> Option<&'a Function> {
        let c_name = CString::new(name).unwrap();
        unsafe {
            let ty = core::LLVMGetNamedFunction(self.into(), c_name.as_ptr());
            util::ptr_to_null(ty)
        }
    }
    /// Returns the type with the name given, or `None`` if no type with that name exists.
    pub fn get_type<'a>(&'a self, name: &str) -> Option<&'a Type> {
        let c_name = CString::new(name).unwrap();
        unsafe {
            let ty = core::LLVMGetTypeByName(self.into(), c_name.as_ptr());
            util::ptr_to_null(ty)
        }
    }
    /// Clone this module.
    pub fn clone<'a>(&'a self) -> CSemiBox<'a, Module> {
        CSemiBox::new(unsafe { core::LLVMCloneModule(self.into()) })
    }

    /// Optimize this module with the given optimization level and size level.
    ///
    /// This runs passes depending on the levels given.
    pub fn optimize(&self, opt_level: usize, size_level: usize) {
        unsafe {
            let builder = builder::LLVMPassManagerBuilderCreate();
            builder::LLVMPassManagerBuilderSetOptLevel(builder, opt_level as c_uint);
            builder::LLVMPassManagerBuilderSetSizeLevel(builder, size_level as c_uint);

            let pass_manager = core::LLVMCreatePassManager();

            if opt_level > 1 {
                builder::LLVMPassManagerBuilderUseInlinerWithThreshold(
                    builder,
                    size_level as c_uint,
                );
            } else {
                // otherwise, we will add the builder to the top of the list of passes.
                // This is not exactly what llvm-opt does, but it is pretty close
                ipo::LLVMAddAlwaysInlinerPass(pass_manager);
            }

            builder::LLVMPassManagerBuilderPopulateModulePassManager(builder, pass_manager);
            builder::LLVMPassManagerBuilderDispose(builder);
            core::LLVMRunPassManager(pass_manager, self.into());
        }
    }

    /// Returns the target data of this module represented as a string
    pub fn get_target(&self) -> &str {
        unsafe {
            let target = core::LLVMGetTarget(self.into());
            util::to_str(target as *mut c_char)
        }
    }

    /// Set the target data of this module to the target data string given.
    pub fn set_target(&self, target: &str) {
        let c_target = CString::new(target).unwrap();
        unsafe { core::LLVMSetTarget(self.into(), c_target.as_ptr()) }
    }

    /// Verify that the module is safe to run, returning a string detailing the error
    /// when an error occurs.
    pub fn verify(&self) -> Result<(), CBox<str>> {
        unsafe {
            let mut error = mem::uninitialized();
            let action = LLVMVerifierFailureAction::LLVMReturnStatusAction;
            if analysis::LLVMVerifyModule(self.into(), action, &mut error) == 1 {
                Err(CBox::new(error))
            } else {
                Ok(())
            }
        }
    }

    /// Compile the module into an object file at the given location.
    ///
    /// Note that this uses the LLVM tool `llc` to do this, which may or may not be
    /// installed on the user's machine.
    pub fn compile(&self, path: &Path, opt_level: usize) -> IoResult<Child> {
        let dir = env::temp_dir();
        let path = path.to_str().unwrap();
        let mod_path = dir.join("module.bc");
        let mod_path = mod_path.to_str().unwrap();
        try!(self.write_bitcode(mod_path));
        Command::new("llc")
            .arg(&format!("-O={}", opt_level))
            .arg("-filetype=obj")
            .arg("-o")
            .arg(path)
            .arg(mod_path)
            .spawn()
    }

    /// Link a module into this module, returning an error string if an error occurs.
    ///
    /// This *does not* destroy the source module.
    pub fn link(&self, src: &Module) -> Result<(), CBox<str>> {
        unsafe {
            let dest = self.into();
            let src = src.into();
            if linker::LLVMLinkModules2(dest, src) == 1 {
                // TODO: Read error string from diagnostics
                Err(CBox::new(ptr::null_mut()))
            } else {
                Ok(())
            }
        }
    }
}
impl<'a> IntoIterator for &'a Module {
    type Item = &'a Function;
    type IntoIter = Functions<'a>;
    /// Iterate through the functions in the module
    fn into_iter(self) -> Functions<'a> {
        Functions {
            index: 0,
            value: unsafe { core::LLVMGetFirstFunction(self.into()) },
            marker: PhantomData,
        }
    }
}
get_context!(Module, LLVMGetModuleContext);
to_str!(Module, LLVMPrintModuleToString);
dispose!(Module, LLVMModule, core::LLVMDisposeModule);
#[derive(Copy, Clone)]
/// An iterator through the functions contained in a module.
pub struct Functions<'a> {
    index: usize,
    value: LLVMValueRef,
    marker: PhantomData<&'a ()>,
}
impl<'a> Iterator for Functions<'a> {
    type Item = &'a Function;
    fn next(&mut self) -> Option<&'a Function> {
        let o = if self.value.is_null() {
            None
        } else if self.index == 0 {
            Some(self.value.into())
        } else {
            let c_next = unsafe { core::LLVMGetNextFunction(self.value) };
            self.value = c_next;
            Some(self.value.into())
        };

        self.index += 1;
        o
    }
}

#[derive(Copy, Clone, Debug, Eq, PartialEq)]
#[repr(C)]
pub enum AddressSpace {
    Generic = 0,
    Global = 1,
    Shared = 3,
    Const = 4,
    Local = 5,
}
<commit_msg>Compile llvm module to obj with PIC<commit_after>use libc::{c_char, c_uint};
use llvm_sys::prelude::{LLVMValueRef, LLVMModuleRef};
use llvm_sys::analysis::LLVMVerifierFailureAction;
use llvm_sys::{analysis, core, linker, LLVMModule};
use llvm_sys::transforms::pass_manager_builder as builder;
use llvm_sys::transforms::ipo;
use llvm_sys::bit_writer as writer;
use llvm_sys::bit_reader as reader;
use llvm_sys::ir_reader;
use cbox::{CBox, CSemiBox};
use std::ffi::CString;
use std::iter::{Iterator, IntoIterator};
use std::io::{Error, ErrorKind};
use std::io::Result as IoResult;
use std::{env, fmt, mem, ptr};
use std::marker::PhantomData;
use std::path::Path;
use std::process::{Command, Child};
use super::buffer::MemoryBuffer;
use super::context::{Context, GetContext};
use super::value::{Alias, Function, GlobalValue, GlobalVariable, Value};
use super::types::Type;
use super::util;

/// Represents a single compilation unit of code.
///
/// This is attached to the lifetime of the context that constructs it, but is owned by the `CSemiBox`.
pub struct Module(PhantomData<[u8]>);
native_ref!(&Module = LLVMModuleRef);
impl Module {
    /// Create a new module in the context given with the name given.
    ///
    /// The lifetime of the module will match the lifetime of the context
    /// you instance it in because the context contains it.
    ///
    /// ```rust
    /// use llvm::*;
    /// let context = Context::new();
    /// let context = context.as_semi();
    /// let module = Module::new("name", &context);
    /// println!("{:?}", module)
    /// ```
    pub fn new<'a>(name: &str, context: &'a Context) -> CSemiBox<'a, Module> {
        let c_name = CString::new(name).unwrap();
        unsafe {
            CSemiBox::new(core::LLVMModuleCreateWithNameInContext(
                c_name.as_ptr(),
                context.into(),
            ))
        }
    }
    /// Add a global to the module with the given type and name.
    pub fn add_global<'a>(&'a self, name: &str, ty: &'a Type) -> &'a GlobalVariable {
        util::with_cstr(name, |ptr| unsafe {
            core::LLVMAddGlobal(self.into(), ty.into(), ptr).into()
        })
    }
    /// Add a global variable to the module with the given type, name and initial value.
    pub fn add_global_in_address_space<'a>(
        &'a self,
        name: &str,
        ty: &'a Type,
        address: AddressSpace,
    ) -> &'a GlobalVariable {
        util::with_cstr(name, |ptr| unsafe {
            core::LLVMAddGlobalInAddressSpace(self.into(), ty.into(), ptr, address as u32).into()
        })
    }
    /// Add a global variable to the module with the given type, name and initial value.
    pub fn add_global_variable<'a>(&'a self, name: &str, val: &'a Value) -> &'a GlobalVariable {
        let global = self.add_global(name, val.get_type());
        global.set_initializer(val);
        global
    }
    /// Add a global to the module with the given type and name.
    pub fn add_global_alias<'a>(&'a self, name: &str, val: &'a GlobalValue) -> &'a Alias {
        util::with_cstr(name, |ptr| unsafe {
            core::LLVMAddAlias(self.into(), val.get_type().into(), val.into(), ptr).into()
        })
    }
    /// Get the global with the name given, or `None` if no global with that name exists.
    pub fn get_global<'a>(&'a self, name: &str) -> Option<&'a GlobalValue> {
        util::with_cstr(name, |ptr| unsafe {
            let ptr = core::LLVMGetNamedGlobal(self.into(), ptr);
            util::ptr_to_null(ptr)
        })
    }
    /// Parse this bitcode file into a module, or return an error string.
    pub fn parse_bitcode<'a>(
        context: &'a Context,
        path: &str,
    ) -> Result<CSemiBox<'a, Module>, CBox<str>> {
        unsafe {
            let mut out = mem::uninitialized();
            let err = mem::uninitialized();
            let buf = try!(MemoryBuffer::new_from_file(path));
            if reader::LLVMParseBitcodeInContext2(context.into(), buf.as_ptr(), &mut out) == 1 {
                // TODO: Read error from diagnostics
                Err(CBox::new(err))
            } else {
                Ok(CSemiBox::new(out))
            }
        }
    }
    /// Write this module's bitcode to the path given.
    pub fn write_bitcode(&self, path: &str) -> IoResult<()> {
        util::with_cstr(path, |cpath| unsafe {
            if writer::LLVMWriteBitcodeToFile(self.into(), cpath) != 0 {
                Err(Error::new(
                    ErrorKind::Other,
                    &format!("could not write to {}", path) as &str,
                ))
            } else {
                Ok(())
            }
        })
    }
    /// Parse IR assembly unto a module, or return an error string.
    pub fn parse_ir_from_str<'a>(
        context: &'a Context,
        s: &str,
    ) -> Result<CSemiBox<'a, Module>, CBox<str>> {
        unsafe {
            let mut out = mem::uninitialized();
            let mut err = mem::uninitialized();
            let buf = try!(MemoryBuffer::new_from_str(s, None));
            if ir_reader::LLVMParseIRInContext(
                context.into(),
                buf.as_ptr(),
                &mut out,
                &mut err,
            ) == 1
            {
                Err(CBox::new(err))
            } else {
                Ok(CSemiBox::new(out))
            }
        }
    }
    /// Add a function to the module with the name given.
    pub fn add_function<'a>(&'a self, name: &str, sig: &'a Type) -> &'a mut Function {
        let c_name = CString::new(name).unwrap();
        unsafe { core::LLVMAddFunction(self.into(), c_name.as_ptr(), sig.into()) }.into()
    }
    /// Returns the function with the name given, or `None` if no function with that name exists.
    pub fn get_function<'a>(&'a self, name: &str) -> Option<&'a Function> {
        let c_name = CString::new(name).unwrap();
        unsafe {
            let ty = core::LLVMGetNamedFunction(self.into(), c_name.as_ptr());
            util::ptr_to_null(ty)
        }
    }
    /// Returns the type with the name given, or `None`` if no type with that name exists.
    pub fn get_type<'a>(&'a self, name: &str) -> Option<&'a Type> {
        let c_name = CString::new(name).unwrap();
        unsafe {
            let ty = core::LLVMGetTypeByName(self.into(), c_name.as_ptr());
            util::ptr_to_null(ty)
        }
    }
    /// Clone this module.
    pub fn clone<'a>(&'a self) -> CSemiBox<'a, Module> {
        CSemiBox::new(unsafe { core::LLVMCloneModule(self.into()) })
    }

    /// Optimize this module with the given optimization level and size level.
    ///
    /// This runs passes depending on the levels given.
    pub fn optimize(&self, opt_level: usize, size_level: usize) {
        unsafe {
            let builder = builder::LLVMPassManagerBuilderCreate();
            builder::LLVMPassManagerBuilderSetOptLevel(builder, opt_level as c_uint);
            builder::LLVMPassManagerBuilderSetSizeLevel(builder, size_level as c_uint);

            let pass_manager = core::LLVMCreatePassManager();

            if opt_level > 1 {
                builder::LLVMPassManagerBuilderUseInlinerWithThreshold(
                    builder,
                    size_level as c_uint,
                );
            } else {
                // otherwise, we will add the builder to the top of the list of passes.
                // This is not exactly what llvm-opt does, but it is pretty close
                ipo::LLVMAddAlwaysInlinerPass(pass_manager);
            }

            builder::LLVMPassManagerBuilderPopulateModulePassManager(builder, pass_manager);
            builder::LLVMPassManagerBuilderDispose(builder);
            core::LLVMRunPassManager(pass_manager, self.into());
        }
    }

    /// Returns the target data of this module represented as a string
    pub fn get_target(&self) -> &str {
        unsafe {
            let target = core::LLVMGetTarget(self.into());
            util::to_str(target as *mut c_char)
        }
    }

    /// Set the target data of this module to the target data string given.
    pub fn set_target(&self, target: &str) {
        let c_target = CString::new(target).unwrap();
        unsafe { core::LLVMSetTarget(self.into(), c_target.as_ptr()) }
    }

    /// Verify that the module is safe to run, returning a string detailing the error
    /// when an error occurs.
    pub fn verify(&self) -> Result<(), CBox<str>> {
        unsafe {
            let mut error = mem::uninitialized();
            let action = LLVMVerifierFailureAction::LLVMReturnStatusAction;
            if analysis::LLVMVerifyModule(self.into(), action, &mut error) == 1 {
                Err(CBox::new(error))
            } else {
                Ok(())
            }
        }
    }

    /// Compile the module into an object file at the given location.
    ///
    /// Note that this uses the LLVM tool `llc` to do this, which may or may not be
    /// installed on the user's machine.
    pub fn compile(&self, path: &Path, opt_level: usize) -> IoResult<Child> {
        let dir = env::temp_dir();
        let path = path.to_str().unwrap();
        let mod_path = dir.join("module.bc");
        let mod_path = mod_path.to_str().unwrap();
        try!(self.write_bitcode(mod_path));
        Command::new("llc")
            .arg(&format!("-O={}", opt_level))
            .arg("-filetype=obj")
            .arg("-relocation-model=pic")
            .arg("-o")
            .arg(path)
            .arg(mod_path)
            .spawn()
    }

    /// Link a module into this module, returning an error string if an error occurs.
    ///
    /// This *does not* destroy the source module.
    pub fn link(&self, src: &Module) -> Result<(), CBox<str>> {
        unsafe {
            let dest = self.into();
            let src = src.into();
            if linker::LLVMLinkModules2(dest, src) == 1 {
                // TODO: Read error string from diagnostics
                Err(CBox::new(ptr::null_mut()))
            } else {
                Ok(())
            }
        }
    }
}
impl<'a> IntoIterator for &'a Module {
    type Item = &'a Function;
    type IntoIter = Functions<'a>;
    /// Iterate through the functions in the module
    fn into_iter(self) -> Functions<'a> {
        Functions {
            index: 0,
            value: unsafe { core::LLVMGetFirstFunction(self.into()) },
            marker: PhantomData,
        }
    }
}
get_context!(Module, LLVMGetModuleContext);
to_str!(Module, LLVMPrintModuleToString);
dispose!(Module, LLVMModule, core::LLVMDisposeModule);
#[derive(Copy, Clone)]
/// An iterator through the functions contained in a module.
pub struct Functions<'a> {
    index: usize,
    value: LLVMValueRef,
    marker: PhantomData<&'a ()>,
}
impl<'a> Iterator for Functions<'a> {
    type Item = &'a Function;
    fn next(&mut self) -> Option<&'a Function> {
        let o = if self.value.is_null() {
            None
        } else if self.index == 0 {
            Some(self.value.into())
        } else {
            let c_next = unsafe { core::LLVMGetNextFunction(self.value) };
            self.value = c_next;
            Some(self.value.into())
        };

        self.index += 1;
        o
    }
}

#[derive(Copy, Clone, Debug, Eq, PartialEq)]
#[repr(C)]
pub enum AddressSpace {
    Generic = 0,
    Global = 1,
    Shared = 3,
    Const = 4,
    Local = 5,
}
<|endoftext|>