<commit_before>use super::Shape;
use russell_lab::{Matrix, Vector};

const NDIM: usize = 2;
const NPOINT: usize = 4;
const NEDGE: usize = 4;
const NFACE: usize = 0;

pub struct Qua4 {
    coords: Vec<Vector>, // natural coordinates (npoint, ndim)
    interp: Vector,      // interpolation functions @ natural coordinate (npoint)
    deriv: Matrix,       // derivatives of interpolation functions w.r.t natural coordinate (npoint, ndim)
}

/// Implements a quadrilateral with 4 points
///
/// The natural coordinates range from -1 to +1 with the geometry centred @ 0
///
/// ```text
/// 3-----------2
/// |     s     |
/// |     |     |
/// |     +--r  |
/// |           |
/// |           |
/// 0-----------1
/// ```
impl Qua4 {
    pub fn new() -> Self {
        Qua4 {
            #[rustfmt::skip]
            coords: vec![
                Vector::from(&[-1.0, -1.0]),
                Vector::from(&[ 1.0, -1.0]),
                Vector::from(&[ 1.0,  1.0]),
                Vector::from(&[-1.0,  1.0]),
            ],
            interp: Vector::new(NPOINT),
            deriv: Matrix::new(NPOINT, NDIM),
        }
    }
}

impl Shape for Qua4 {
    fn calc_interp(&mut self, ksi: &Vector) {
        let (r, s) = (ksi[0], ksi[1]);

        self.interp[0] = (1.0 - r - s + r * s) / 4.0;
        self.interp[1] = (1.0 + r - s - r * s) / 4.0;
        self.interp[2] = (1.0 + r + s + r * s) / 4.0;
        self.interp[3] = (1.0 - r + s - r * s) / 4.0;
    }

    fn calc_deriv(&mut self, ksi: &Vector) {
        let (r, s) = (ksi[0], ksi[1]);

        self.deriv[0][0] = (-1.0 + s) / 4.0;
        self.deriv[0][1] = (-1.0 + r) / 4.0;

        self.deriv[1][0] = (1.0 - s) / 4.0;
        self.deriv[1][1] = (-1.0 - r) / 4.0;

        self.deriv[2][0] = (1.0 + s) / 4.0;
        self.deriv[2][1] = (1.0 + r) / 4.0;

        self.deriv[3][0] = (-1.0 - s) / 4.0;
        self.deriv[3][1] = (1.0 - r) / 4.0;
    }

    fn get_interp(&self, m: usize) -> f64 {
        self.interp[m]
    }

    fn get_deriv(&self, deriv: &mut Vector, m: usize) {
        deriv[0] = self.deriv[m][0];
        deriv[1] = self.deriv[m][1];
    }

    fn get_ndim(&self) -> usize {
        NDIM
    }

    fn get_npoint(&self) -> usize {
        NPOINT
    }

    fn get_nedge(&self) -> usize {
        NEDGE
    }

    fn get_nface(&self) -> usize {
        NFACE
    }

    fn get_ksi(&self, ksi: &mut Vector, m: usize) {
        ksi[0] = self.coords[m][0];
        ksi[1] = self.coords[m][1];
    }
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

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

    // Holds arguments for numerical differentiation
    struct Arguments {
        shape: Qua4,    // shape
        at_ksi: Vector, // at nat coord value
        ksi: Vector,    // temporary nat coord
        m: usize,       // point index
        i: usize,       // dimension index
    }

    // Computes the interpolation fn @ m as a function of x = ksi[i]
    fn sm(x: f64, args: &mut Arguments) -> f64 {
        args.ksi[0] = args.at_ksi[0];
        args.ksi[1] = args.at_ksi[1];
        args.ksi[args.i] = x;
        args.shape.calc_interp(&args.ksi);
        args.shape.get_interp(args.m)
    }

    #[test]
    fn new_works() {
        let geo = Qua4::new();
        assert_eq!(geo.coords.len(), NPOINT);
        assert_eq!(geo.interp.dim(), NPOINT);
        assert_eq!(geo.deriv.dims(), (NPOINT, NDIM));
    }

    #[test]
    fn calc_interp_works() {
        let mut geo = Qua4::new();
        let mut ksi = Vector::new(NDIM);
        for m in 0..NPOINT {
            geo.get_ksi(&mut ksi, m);
            geo.calc_interp(&ksi);
            for n in 0..NPOINT {
                let smn = geo.get_interp(n);
                if m == n {
                    assert_approx_eq!(smn, 1.0, 1e-15);
                } else {
                    assert_approx_eq!(smn, 0.0, 1e-15);
                }
            }
        }
    }

    #[test]
    fn calc_deriv_works() {
        let args = &mut Arguments {
            shape: Qua4::new(),
            at_ksi: Vector::from(&[0.25, 0.25]),
            ksi: Vector::new(NDIM),
            m: 0,
            i: 0,
        };
        let mut geo = Qua4::new();
        let mut dsm_dksi = Vector::new(NDIM);
        geo.calc_deriv(&args.at_ksi);
        for m in 0..NPOINT {
            geo.get_deriv(&mut dsm_dksi, m);
            args.m = m;
            for i in 0..NDIM {
                args.i = i;
                assert_deriv_approx_eq!(dsm_dksi[i], args.at_ksi[i], sm, args, 1e-13);
            }
        }
    }

    #[test]
    fn getters_work() {
        let geo = Qua4::new();
        assert_eq!(geo.get_ndim(), NDIM);
        assert_eq!(geo.get_npoint(), NPOINT);
        assert_eq!(geo.get_nedge(), NEDGE);
        assert_eq!(geo.get_nface(), NFACE);
    }
}
<commit_msg>Fix doc<commit_after>use super::Shape;
use russell_lab::{Matrix, Vector};

const NDIM: usize = 2;
const NPOINT: usize = 4;
const NEDGE: usize = 4;
const NFACE: usize = 0;

/// Implements a quadrilateral with 4 points
///
/// The natural coordinates range from -1 to +1 with the geometry centred @ 0
///
/// ```text
/// 3-----------2
/// |     s     |
/// |     |     |
/// |     +--r  |
/// |           |
/// |           |
/// 0-----------1
/// ```
pub struct Qua4 {
    coords: Vec<Vector>, // natural coordinates (npoint, ndim)
    interp: Vector,      // interpolation functions @ natural coordinate (npoint)
    deriv: Matrix,       // derivatives of interpolation functions w.r.t natural coordinate (npoint, ndim)
}

impl Qua4 {
    pub fn new() -> Self {
        Qua4 {
            #[rustfmt::skip]
            coords: vec![
                Vector::from(&[-1.0, -1.0]),
                Vector::from(&[ 1.0, -1.0]),
                Vector::from(&[ 1.0,  1.0]),
                Vector::from(&[-1.0,  1.0]),
            ],
            interp: Vector::new(NPOINT),
            deriv: Matrix::new(NPOINT, NDIM),
        }
    }
}

impl Shape for Qua4 {
    fn calc_interp(&mut self, ksi: &Vector) {
        let (r, s) = (ksi[0], ksi[1]);

        self.interp[0] = (1.0 - r - s + r * s) / 4.0;
        self.interp[1] = (1.0 + r - s - r * s) / 4.0;
        self.interp[2] = (1.0 + r + s + r * s) / 4.0;
        self.interp[3] = (1.0 - r + s - r * s) / 4.0;
    }

    fn calc_deriv(&mut self, ksi: &Vector) {
        let (r, s) = (ksi[0], ksi[1]);

        self.deriv[0][0] = (-1.0 + s) / 4.0;
        self.deriv[0][1] = (-1.0 + r) / 4.0;

        self.deriv[1][0] = (1.0 - s) / 4.0;
        self.deriv[1][1] = (-1.0 - r) / 4.0;

        self.deriv[2][0] = (1.0 + s) / 4.0;
        self.deriv[2][1] = (1.0 + r) / 4.0;

        self.deriv[3][0] = (-1.0 - s) / 4.0;
        self.deriv[3][1] = (1.0 - r) / 4.0;
    }

    fn get_interp(&self, m: usize) -> f64 {
        self.interp[m]
    }

    fn get_deriv(&self, deriv: &mut Vector, m: usize) {
        deriv[0] = self.deriv[m][0];
        deriv[1] = self.deriv[m][1];
    }

    fn get_ndim(&self) -> usize {
        NDIM
    }

    fn get_npoint(&self) -> usize {
        NPOINT
    }

    fn get_nedge(&self) -> usize {
        NEDGE
    }

    fn get_nface(&self) -> usize {
        NFACE
    }

    fn get_ksi(&self, ksi: &mut Vector, m: usize) {
        ksi[0] = self.coords[m][0];
        ksi[1] = self.coords[m][1];
    }
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

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

    // Holds arguments for numerical differentiation
    struct Arguments {
        shape: Qua4,    // shape
        at_ksi: Vector, // at nat coord value
        ksi: Vector,    // temporary nat coord
        m: usize,       // point index
        i: usize,       // dimension index
    }

    // Computes the interpolation fn @ m as a function of x = ksi[i]
    fn sm(x: f64, args: &mut Arguments) -> f64 {
        args.ksi[0] = args.at_ksi[0];
        args.ksi[1] = args.at_ksi[1];
        args.ksi[args.i] = x;
        args.shape.calc_interp(&args.ksi);
        args.shape.get_interp(args.m)
    }

    #[test]
    fn new_works() {
        let geo = Qua4::new();
        assert_eq!(geo.coords.len(), NPOINT);
        assert_eq!(geo.interp.dim(), NPOINT);
        assert_eq!(geo.deriv.dims(), (NPOINT, NDIM));
    }

    #[test]
    fn calc_interp_works() {
        let mut geo = Qua4::new();
        let mut ksi = Vector::new(NDIM);
        for m in 0..NPOINT {
            geo.get_ksi(&mut ksi, m);
            geo.calc_interp(&ksi);
            for n in 0..NPOINT {
                let smn = geo.get_interp(n);
                if m == n {
                    assert_approx_eq!(smn, 1.0, 1e-15);
                } else {
                    assert_approx_eq!(smn, 0.0, 1e-15);
                }
            }
        }
    }

    #[test]
    fn calc_deriv_works() {
        let args = &mut Arguments {
            shape: Qua4::new(),
            at_ksi: Vector::from(&[0.25, 0.25]),
            ksi: Vector::new(NDIM),
            m: 0,
            i: 0,
        };
        let mut geo = Qua4::new();
        let mut dsm_dksi = Vector::new(NDIM);
        geo.calc_deriv(&args.at_ksi);
        for m in 0..NPOINT {
            geo.get_deriv(&mut dsm_dksi, m);
            args.m = m;
            for i in 0..NDIM {
                args.i = i;
                assert_deriv_approx_eq!(dsm_dksi[i], args.at_ksi[i], sm, args, 1e-13);
            }
        }
    }

    #[test]
    fn getters_work() {
        let geo = Qua4::new();
        assert_eq!(geo.get_ndim(), NDIM);
        assert_eq!(geo.get_npoint(), NPOINT);
        assert_eq!(geo.get_nedge(), NEDGE);
        assert_eq!(geo.get_nface(), NFACE);
    }
}
<|endoftext|>


<commit_before>// Copyright (c) 2015, The Radare Project. All rights preserved.
// See the COPYING file at the top-level directory of this distribution.
// Licensed under the BSD 3-Clause License:
// <http://opensource.org/licenses/BSD-3-Clause>
// This file may not be copied, modified, or distributed
// except according to those terms.

//! This Module provides information about stack offset with variable,
//! which will help other modules analyze.

use std::collections::{HashMap, HashSet, VecDeque};
use middle::ir::MOpcode;
use middle::ssa::cfg_traits::CFG;
use middle::ssa::ssa_traits::{SSA, SSAMod, SSAExtra, SSAWalk};
use middle::ssa::ssastorage::SSAStorage;

type LValueRef = <SSAStorage as SSA>::ValueRef;

/// Analyze stack offset backward, by assuming the stack of last
/// SP register is ZERO.
/// You have to offer RadecoIL SSA and SP register name into analyzer.
pub fn backward_analysis(ssa:&SSAStorage, SP_name: String)
        -> HashMap<LValueRef, i64> {
    let mut stack_offset: HashMap<LValueRef, i64> = HashMap::new();
    let mut worklist: VecDeque<LValueRef> = VecDeque::new();
    let mut visited: HashSet<LValueRef> = HashSet::new();

    // Initial the last SP register offset to ZERO.
    let reg_state = ssa.registers_at(&ssa.exit_node());
    let nodes = ssa.args_of(reg_state);
    for node in &nodes {
        if ssa.get_register(node).contains(&SP_name) {
            stack_offset.insert(*node, 0);
            worklist.push_back(*node);
        }
    }

    while let Some(node) = worklist.pop_front() {
        if !visited.contains(&node) {
            visited.insert(node);
        } else {
            continue;
        }

        let base = stack_offset.get(&node).unwrap().clone();
        let args = ssa.get_operands(&node);

        let users = ssa.get_uses(&node);
        for user in users {
            match ssa.get_opcode(&user) {
                Some(MOpcode::OpWiden(_)) |
                Some(MOpcode::OpNarrow(_)) => {
                    stack_offset.insert(user, base);
                    worklist.push_back(user);
                }
                _ => { }
            }
        }

        // The node maybe a comment, for call statements made it
        if ssa.get_comment(&node).is_some() {
            continue;
        }

        // Every SP met at one phi node will have the same value.
        if ssa.is_phi(&node) {
            for arg in args {
                stack_offset.insert(arg, base);
                worklist.push_back(arg);
            }
            continue;
        }

        // Consider exprission.
        if ssa.get_opcode(&node).is_none() {
            continue;
        }

        let opc = ssa.get_opcode(&node).unwrap();
        match opc {
            MOpcode::OpWiden(_) |
            MOpcode::OpNarrow(_) => {
                stack_offset.insert(args[0], base);
                worklist.push_back(args[0]);
            }
            MOpcode::OpSub => {
                if let Some(MOpcode::OpConst(num)) = ssa.get_opcode(&args[1]) {
                    stack_offset.insert(args[0], base + (num as i64));
                    worklist.push_back(args[0]);
                }
            }
            MOpcode::OpAdd => {
                if let Some(MOpcode::OpConst(num)) = ssa.get_opcode(&args[0]) {
                    stack_offset.insert(args[1], base - (num as i64));
                    worklist.push_back(args[1]);
                }
            }
            _ => { }
        }
    }

    radeco_trace!("CallFixer|Stack_offset: {:?}", stack_offset);
    stack_offset
}

/// Analyze stack offset frontward, only for first basic block.
/// You have to offer RadecoIL SSA and SP & BP register name into analyzer.
pub fn frontward_analysis(ssa: &SSAStorage,
                       SP_name: String,
                       BP_name: String)
        -> HashMap<LValueRef, i64> {
   generic_frontward_analysis(ssa, SP_name, BP_name, false)
}

/// Analyze stack offset frontward, for the whole SSA.
/// You have to offer RadecoIL SSA and SP & BP register name into analyzer.
pub fn rounded_analysis(ssa: &SSAStorage,
                       SP_name: String,
                       BP_name: String)
        -> HashMap<LValueRef, i64> {
   generic_frontward_analysis(ssa, SP_name, BP_name, true)
}

// Analyze stack offset frontward, for the first block or whole SSA.
fn generic_frontward_analysis(ssa: &SSAStorage,
                         SP_name: String,
                         BP_name: String,
                         is_global: bool)
        -> HashMap<LValueRef, i64> {
    let mut stack_offset: HashMap<LValueRef, i64> = HashMap::new();
    {
        let reg_state = ssa.registers_at(&ssa.start_node());
        let nodes = ssa.args_of(reg_state);
        for node in &nodes {
            if ssa.get_comment(node) != Some(SP_name.clone()) {
                continue;
            }
            stack_offset.insert(*node, 0);
            break;
        }
    }

    let nodes = if is_global {
        let mut nodes: Vec<LValueRef> = Vec::new();
        let mut walker = ssa.bfs_walk().nodes;
        while let Some(node) = walker.pop_front() {
            nodes.push(node);
        }
        nodes
    } else {
        let blocks = ssa.succs_of(ssa.start_node());
        assert_eq!(blocks.len(), 1);
        ssa.exprs_in(&blocks[0])
    };

    for node in &nodes {
        if let Some(opc) = ssa.get_opcode(node) {
            if opc == MOpcode::OpCall && !is_global {
                break;
            }

            match opc {
                MOpcode::OpWiden(_) | MOpcode::OpNarrow(_) => {
                    let args = ssa.get_operands(node);
                    if stack_offset.contains_key(&args[0]) {
                        let num = stack_offset.get(&args[0])
                                                .unwrap()
                                                .clone();
                        stack_offset.insert(*node, num);
                        continue;
                    }
                }
                _ => {  }
            }

            // We only consider SP/BP.
            if ssa.get_register(node).is_empty() {
                continue;
            }
            let regnames = ssa.get_register(node);
            if !regnames.contains(&SP_name) &&
                !regnames.contains(&BP_name) {
                    continue;
                }

            let args = ssa.get_operands(node);
            if args.len() != 2 {
                continue;
            }

            let const_arg: i64;
            let opcode_arg: i64;
            match opc {
                MOpcode::OpSub => {
                    const_arg = 1;
                    opcode_arg = 0;
                }
                MOpcode::OpAdd => {
                    const_arg = 0;
                    opcode_arg = 1;
                }
                // Some compiler will initial SP with and 0xfffffff0
                MOpcode::OpAnd => {
                    stack_offset.clear();
                    stack_offset.insert(*node, 0);
                    continue;
                }
                _ => {
                    continue;
                }
            }
            if ssa.get_opcode(&args[opcode_arg as usize]).is_some() ||
                ssa.get_comment(&args[opcode_arg as usize]).is_some() ||
                (ssa.is_phi(&args[opcode_arg as usize]) && is_global) {
                if let Some(MOpcode::OpConst(num)) =
                            ssa.get_opcode(&args[const_arg as usize]) {
                    // TODO: Some special cases may by not consided
                    if !stack_offset.contains_key(&args[opcode_arg as usize]) {
                        continue;
                    }
                    let base = stack_offset.get(&args[opcode_arg as usize])
                                                            .unwrap()
                                                            .clone() as i64;
                    stack_offset.insert(*node,
                                base + (opcode_arg - const_arg) * (num as i64));
                    continue;
                }
            }
            radeco_warn!("No SP/BP algorithm Found!");
        }

        // If we are doing a global search, we should consider phi node.
        if ssa.is_phi(node) && is_global {
            let args = ssa.get_operands(node);
            let mut nums: Vec<i64> = Vec::new();
            for arg in &args {
                if stack_offset.contains_key(arg) {
                    let num = stack_offset.get(arg).unwrap().clone();
                    if !nums.contains(&num) {
                        nums.push(num);
                    }
                }
            }
            if nums.len() == 1 {
                stack_offset.insert(*node, nums[0]);
            }
        }
    }
    radeco_trace!("CallFixer|Stack_offset: {:?}", stack_offset);
    stack_offset
}

<commit_msg>Add test for digstack<commit_after>// Copyright (c) 2015, The Radare Project. All rights preserved.
// See the COPYING file at the top-level directory of this distribution.
// Licensed under the BSD 3-Clause License:
// <http://opensource.org/licenses/BSD-3-Clause>
// This file may not be copied, modified, or distributed
// except according to those terms.

//! This Module provides information about stack offset with variable,
//! which will help other modules analyze.

use std::collections::{HashMap, HashSet, VecDeque};
use middle::ir::MOpcode;
use middle::ssa::cfg_traits::CFG;
use middle::ssa::ssa_traits::{SSA, SSAMod, SSAExtra, SSAWalk};
use middle::ssa::ssastorage::SSAStorage;

type LValueRef = <SSAStorage as SSA>::ValueRef;

/// Analyze stack offset backward, by assuming the stack of last
/// SP register is ZERO.
/// You have to offer RadecoIL SSA and SP register name into analyzer.
pub fn backward_analysis(ssa:&SSAStorage, SP_name: String)
        -> HashMap<LValueRef, i64> {
    let mut stack_offset: HashMap<LValueRef, i64> = HashMap::new();
    let mut worklist: VecDeque<LValueRef> = VecDeque::new();
    let mut visited: HashSet<LValueRef> = HashSet::new();

    // Initial the last SP register offset to ZERO.
    let reg_state = ssa.registers_at(&ssa.exit_node());
    let nodes = ssa.args_of(reg_state);
    for node in &nodes {
        if ssa.get_register(node).contains(&SP_name) {
            stack_offset.insert(*node, 0);
            worklist.push_back(*node);
        }
    }

    while let Some(node) = worklist.pop_front() {
        if !visited.contains(&node) {
            visited.insert(node);
        } else {
            continue;
        }

        let base = stack_offset.get(&node).unwrap().clone();
        let args = ssa.get_operands(&node);

        let users = ssa.get_uses(&node);
        for user in users {
            match ssa.get_opcode(&user) {
                Some(MOpcode::OpWiden(_)) |
                Some(MOpcode::OpNarrow(_)) => {
                    stack_offset.insert(user, base);
                    worklist.push_back(user);
                }
                _ => { }
            }
        }

        // The node maybe a comment, for call statements made it
        if ssa.get_comment(&node).is_some() {
            continue;
        }

        // Every SP met at one phi node will have the same value.
        if ssa.is_phi(&node) {
            for arg in args {
                stack_offset.insert(arg, base);
                worklist.push_back(arg);
            }
            continue;
        }

        // Consider exprission.
        if ssa.get_opcode(&node).is_none() {
            continue;
        }

        let opc = ssa.get_opcode(&node).unwrap();
        match opc {
            MOpcode::OpWiden(_) |
            MOpcode::OpNarrow(_) => {
                stack_offset.insert(args[0], base);
                worklist.push_back(args[0]);
            }
            MOpcode::OpSub => {
                if let Some(MOpcode::OpConst(num)) = ssa.get_opcode(&args[1]) {
                    stack_offset.insert(args[0], base + (num as i64));
                    worklist.push_back(args[0]);
                }
            }
            MOpcode::OpAdd => {
                if let Some(MOpcode::OpConst(num)) = ssa.get_opcode(&args[0]) {
                    stack_offset.insert(args[1], base - (num as i64));
                    worklist.push_back(args[1]);
                }
            }
            _ => { }
        }
    }

    radeco_trace!("CallFixer|Stack_offset: {:?}", stack_offset);
    stack_offset
}

/// Analyze stack offset frontward, only for first basic block.
/// You have to offer RadecoIL SSA and SP & BP register name into analyzer.
pub fn frontward_analysis(ssa: &SSAStorage,
                       SP_name: String,
                       BP_name: String)
        -> HashMap<LValueRef, i64> {
   generic_frontward_analysis(ssa, SP_name, BP_name, false)
}

/// Analyze stack offset frontward, for the whole SSA.
/// You have to offer RadecoIL SSA and SP & BP register name into analyzer.
pub fn rounded_analysis(ssa: &SSAStorage,
                       SP_name: String,
                       BP_name: String)
        -> HashMap<LValueRef, i64> {
   generic_frontward_analysis(ssa, SP_name, BP_name, true)
}

// Analyze stack offset frontward, for the first block or whole SSA.
fn generic_frontward_analysis(ssa: &SSAStorage,
                         SP_name: String,
                         BP_name: String,
                         is_global: bool)
        -> HashMap<LValueRef, i64> {
    let mut stack_offset: HashMap<LValueRef, i64> = HashMap::new();
    {
        let reg_state = ssa.registers_at(&ssa.start_node());
        let nodes = ssa.args_of(reg_state);
        for node in &nodes {
            if ssa.get_comment(node) != Some(SP_name.clone()) {
                continue;
            }
            stack_offset.insert(*node, 0);
            break;
        }
    }

    let nodes = if is_global {
        let mut nodes: Vec<LValueRef> = Vec::new();
        let mut walker = ssa.bfs_walk().nodes;
        while let Some(node) = walker.pop_front() {
            nodes.push(node);
        }
        nodes
    } else {
        let blocks = ssa.succs_of(ssa.start_node());
        assert_eq!(blocks.len(), 1);
        ssa.exprs_in(&blocks[0])
    };

    for node in &nodes {
        if let Some(opc) = ssa.get_opcode(node) {
            if opc == MOpcode::OpCall && !is_global {
                break;
            }

            match opc {
                MOpcode::OpWiden(_) | MOpcode::OpNarrow(_) => {
                    let args = ssa.get_operands(node);
                    if stack_offset.contains_key(&args[0]) {
                        let num = stack_offset.get(&args[0])
                                                .unwrap()
                                                .clone();
                        stack_offset.insert(*node, num);
                        continue;
                    }
                }
                _ => {  }
            }

            // We only consider SP/BP.
            if ssa.get_register(node).is_empty() {
                continue;
            }
            let regnames = ssa.get_register(node);
            if !regnames.contains(&SP_name) &&
                !regnames.contains(&BP_name) {
                    continue;
                }

            let args = ssa.get_operands(node);
            if args.len() != 2 {
                continue;
            }

            let const_arg: i64;
            let opcode_arg: i64;
            match opc {
                MOpcode::OpSub => {
                    const_arg = 1;
                    opcode_arg = 0;
                }
                MOpcode::OpAdd => {
                    const_arg = 0;
                    opcode_arg = 1;
                }
                // Some compiler will initial SP with and 0xfffffff0
                MOpcode::OpAnd => {
                    stack_offset.clear();
                    stack_offset.insert(*node, 0);
                    continue;
                }
                _ => {
                    continue;
                }
            }
            if ssa.get_opcode(&args[opcode_arg as usize]).is_some() ||
                ssa.get_comment(&args[opcode_arg as usize]).is_some() ||
                (ssa.is_phi(&args[opcode_arg as usize]) && is_global) {
                if let Some(MOpcode::OpConst(num)) =
                            ssa.get_opcode(&args[const_arg as usize]) {
                    // TODO: Some special cases may by not consided
                    if !stack_offset.contains_key(&args[opcode_arg as usize]) {
                        continue;
                    }
                    let base = stack_offset.get(&args[opcode_arg as usize])
                                                            .unwrap()
                                                            .clone() as i64;
                    stack_offset.insert(*node,
                                base + (opcode_arg - const_arg) * (num as i64));
                    continue;
                }
            }
            radeco_warn!("No SP/BP algorithm Found!");
        }

        // If we are doing a global search, we should consider phi node.
        if ssa.is_phi(node) && is_global {
            let args = ssa.get_operands(node);
            let mut nums: Vec<i64> = Vec::new();
            for arg in &args {
                if stack_offset.contains_key(arg) {
                    let num = stack_offset.get(arg).unwrap().clone();
                    if !nums.contains(&num) {
                        nums.push(num);
                    }
                }
            }
            if nums.len() == 1 {
                stack_offset.insert(*node, nums[0]);
            }
        }
    }
    radeco_trace!("CallFixer|Stack_offset: {:?}", stack_offset);
    stack_offset
}

#[cfg(test)]
mod test {
    use super::*;
    use serde_json;
    use r2api::structs::{LFunctionInfo, LRegInfo};
    use std::fs::File;
    use std::io::prelude::*;

    use frontend::ssaconstructor::SSAConstruct;
    use middle::ssa::ssastorage::SSAStorage;
    use middle::dce;

    const REGISTER_PROFILE: &'static str = "test_files/x86_register_profile.json";
    const BIN_LS_INSTRUCTIONS: &'static str = "test_files/bin_ls_instructions.json";
    const CT1_INSTRUCTIONS: &'static str = "test_files/ct1_instructions.json";

    #[test]
    fn bin_ls_test() {
        let mut instructions: LFunctionInfo;
        let mut register_profile = File::open(REGISTER_PROFILE).unwrap();
        let mut s = String::new();
        register_profile.read_to_string(&mut s).unwrap();
        let reg_profile = serde_json::from_str(&*s).unwrap();
        let mut instruction_file = File::open(BIN_LS_INSTRUCTIONS).unwrap();
        let mut s = String::new();
        instruction_file.read_to_string(&mut s).unwrap();
        instructions = serde_json::from_str(&*s).unwrap();
        let mut ssa = SSAStorage::new();
        {
            let mut constructor = SSAConstruct::new(&mut ssa, &reg_profile);
            constructor.run(instructions.ops.unwrap());
        }
        {
            dce::collect(&mut ssa);
        }

        frontward_analysis(&ssa, "rsp".to_string(), "rbp".to_string());
        backward_analysis(&ssa, "rsp".to_string());
        rounded_analysis(&ssa, "rsp".to_string(), "rbp".to_string());
    }

    #[test]
    fn ct1_test() {
        let mut instructions: LFunctionInfo;
        let mut register_profile = File::open(REGISTER_PROFILE).unwrap();
        let mut s = String::new();
        register_profile.read_to_string(&mut s).unwrap();
        let reg_profile = serde_json::from_str(&*s).unwrap();
        let mut instruction_file = File::open(CT1_INSTRUCTIONS).unwrap();
        let mut s = String::new();
        instruction_file.read_to_string(&mut s).unwrap();
        instructions = serde_json::from_str(&*s).unwrap();
        let mut ssa = SSAStorage::new();
        {
            let mut constructor = SSAConstruct::new(&mut ssa, &reg_profile);
            constructor.run(instructions.ops.unwrap());
        }
        {
            dce::collect(&mut ssa);
        }

        frontward_analysis(&ssa, "rsp".to_string(), "rbp".to_string());
        backward_analysis(&ssa, "rsp".to_string());
        rounded_analysis(&ssa, "rsp".to_string(), "rbp".to_string());
    }
}
<|endoftext|>


<commit_before>// Copyright 2013-2014 The rust-url 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. This file may not be copied, modified, or distributed
// except according to those terms.

use crate::test::TestFn;
use std::char;

use idna::Errors;

pub fn collect_tests<F: FnMut(String, TestFn)>(add_test: &mut F) {
    // https://www.unicode.org/Public/idna/13.0.0/IdnaTestV2.txt
    for (i, line) in include_str!("IdnaTestV2.txt").lines().enumerate() {
        if line == "" || line.starts_with('#') {
            continue;
        }

        // Remove comments
        let line = match line.find('#') {
            Some(index) => &line[0..index],
            None => line,
        };

        let mut pieces = line.split(';').map(|x| x.trim()).collect::<Vec<&str>>();
        let source = unescape(&pieces.remove(0));

        // ToUnicode
        let mut to_unicode = unescape(&pieces.remove(0));
        if to_unicode.is_empty() {
            to_unicode = source.clone();
        }
        let to_unicode_status = status(pieces.remove(0));

        // ToAsciiN
        let to_ascii_n = pieces.remove(0);
        let to_ascii_n = if to_ascii_n.is_empty() {
            to_unicode.clone()
        } else {
            to_ascii_n.to_owned()
        };
        let to_ascii_n_status = pieces.remove(0);
        let to_ascii_n_status = if to_ascii_n_status.is_empty() {
            to_unicode_status.clone()
        } else {
            status(to_ascii_n_status)
        };

        // ToAsciiT
        let to_ascii_t = pieces.remove(0);
        let to_ascii_t = if to_ascii_t.is_empty() {
            to_ascii_n.clone()
        } else {
            to_ascii_t.to_owned()
        };
        let to_ascii_t_status = pieces.remove(0);
        let to_ascii_t_status = if to_ascii_t_status.is_empty() {
            to_ascii_n_status.clone()
        } else {
            status(to_ascii_t_status)
        };

        let test_name = format!("UTS #46 line {}", i + 1);
        add_test(
            test_name,
            TestFn::dyn_test_fn(move || {
                let config = idna::Config::default()
                    .use_std3_ascii_rules(true)
                    .verify_dns_length(true)
                    .check_hyphens(true);

                // http://unicode.org/reports/tr46/#Deviations
                // applications that perform IDNA2008 lookup are not required to check
                // for these contexts, so we skip all tests annotated with C*

                // Everybody ignores V2
                // https://github.com/servo/rust-url/pull/240
                // https://github.com/whatwg/url/issues/53#issuecomment-181528158
                // http://www.unicode.org/review/pri317/

                // "The special error codes X3 and X4_2 are now returned where a toASCII error code
                // was formerly being generated in toUnicode due to an empty label."
                // This is not implemented yet, so we skip toUnicode X4_2 tests for now, too.

                let (to_unicode_value, to_unicode_result) =
                    config.transitional_processing(false).to_unicode(&source);
                let to_unicode_result = to_unicode_result.map(|()| to_unicode_value);
                check(
                    &source,
                    (&to_unicode, &to_unicode_status),
                    to_unicode_result,
                    |e| e.starts_with('C') || e == "V2" || e == "X4_2",
                );

                let to_ascii_n_result = config.transitional_processing(false).to_ascii(&source);
                check(
                    &source,
                    (&to_ascii_n, &to_ascii_n_status),
                    to_ascii_n_result,
                    |e| e.starts_with('C') || e == "V2",
                );

                let to_ascii_t_result = config.transitional_processing(true).to_ascii(&source);
                check(
                    &source,
                    (&to_ascii_t, &to_ascii_t_status),
                    to_ascii_t_result,
                    |e| e.starts_with('C') || e == "V2",
                );
            }),
        )
    }
}

fn check<F>(source: &str, expected: (&str, &[&str]), actual: Result<String, Errors>, ignore: F)
where
    F: Fn(&str) -> bool,
{
    if !expected.1.is_empty() {
        if !expected.1.iter().copied().any(ignore) {
            let res = actual.ok();
            assert_eq!(
                res.clone(),
                None,
                "Expected error {:?}. result: {} | source: {}",
                expected.1,
                res.unwrap(),
                source,
            );
        }
    } else {
        assert!(
            actual.is_ok(),
            "Couldn't parse {} | error: {:?}",
            source,
            actual.err().unwrap(),
        );
        assert_eq!(actual.unwrap(), expected.0, "source: {}", source);
    }
}

fn unescape(input: &str) -> String {
    let mut output = String::new();
    let mut chars = input.chars();
    loop {
        match chars.next() {
            None => return output,
            Some(c) => {
                if c == '\\' {
                    match chars.next().unwrap() {
                        '\\' => output.push('\\'),
                        'u' => {
                            let c1 = chars.next().unwrap().to_digit(16).unwrap();
                            let c2 = chars.next().unwrap().to_digit(16).unwrap();
                            let c3 = chars.next().unwrap().to_digit(16).unwrap();
                            let c4 = chars.next().unwrap().to_digit(16).unwrap();
                            match char::from_u32(((c1 * 16 + c2) * 16 + c3) * 16 + c4) {
                                Some(c) => output.push(c),
                                None => {
                                    output
                                        .push_str(&format!("\\u{:X}{:X}{:X}{:X}", c1, c2, c3, c4));
                                }
                            };
                        }
                        _ => panic!("Invalid test data input"),
                    }
                } else {
                    output.push(c);
                }
            }
        }
    }
}

fn status(status: &str) -> Vec<&str> {
    if status.is_empty() || status == "[]" {
        return Vec::new();
    }

    let mut result = status.split(", ").collect::<Vec<_>>();
    assert!(result[0].starts_with('['));
    result[0] = &result[0][1..];

    let idx = result.len() - 1;
    let last = &mut result[idx];
    assert!(last.ends_with(']'));
    *last = &last[..last.len() - 1];

    result
}
<commit_msg>chore: silence false positive clippy warning<commit_after>// Copyright 2013-2014 The rust-url 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. This file may not be copied, modified, or distributed
// except according to those terms.

use crate::test::TestFn;
use std::char;

use idna::Errors;

pub fn collect_tests<F: FnMut(String, TestFn)>(add_test: &mut F) {
    // https://www.unicode.org/Public/idna/13.0.0/IdnaTestV2.txt
    for (i, line) in include_str!("IdnaTestV2.txt").lines().enumerate() {
        if line == "" || line.starts_with('#') {
            continue;
        }

        // Remove comments
        let line = match line.find('#') {
            Some(index) => &line[0..index],
            None => line,
        };

        let mut pieces = line.split(';').map(|x| x.trim()).collect::<Vec<&str>>();
        let source = unescape(&pieces.remove(0));

        // ToUnicode
        let mut to_unicode = unescape(&pieces.remove(0));
        if to_unicode.is_empty() {
            to_unicode = source.clone();
        }
        let to_unicode_status = status(pieces.remove(0));

        // ToAsciiN
        let to_ascii_n = pieces.remove(0);
        let to_ascii_n = if to_ascii_n.is_empty() {
            to_unicode.clone()
        } else {
            to_ascii_n.to_owned()
        };
        let to_ascii_n_status = pieces.remove(0);
        let to_ascii_n_status = if to_ascii_n_status.is_empty() {
            to_unicode_status.clone()
        } else {
            status(to_ascii_n_status)
        };

        // ToAsciiT
        let to_ascii_t = pieces.remove(0);
        let to_ascii_t = if to_ascii_t.is_empty() {
            to_ascii_n.clone()
        } else {
            to_ascii_t.to_owned()
        };
        let to_ascii_t_status = pieces.remove(0);
        let to_ascii_t_status = if to_ascii_t_status.is_empty() {
            to_ascii_n_status.clone()
        } else {
            status(to_ascii_t_status)
        };

        let test_name = format!("UTS #46 line {}", i + 1);
        add_test(
            test_name,
            TestFn::dyn_test_fn(move || {
                let config = idna::Config::default()
                    .use_std3_ascii_rules(true)
                    .verify_dns_length(true)
                    .check_hyphens(true);

                // http://unicode.org/reports/tr46/#Deviations
                // applications that perform IDNA2008 lookup are not required to check
                // for these contexts, so we skip all tests annotated with C*

                // Everybody ignores V2
                // https://github.com/servo/rust-url/pull/240
                // https://github.com/whatwg/url/issues/53#issuecomment-181528158
                // http://www.unicode.org/review/pri317/

                // "The special error codes X3 and X4_2 are now returned where a toASCII error code
                // was formerly being generated in toUnicode due to an empty label."
                // This is not implemented yet, so we skip toUnicode X4_2 tests for now, too.

                let (to_unicode_value, to_unicode_result) =
                    config.transitional_processing(false).to_unicode(&source);
                let to_unicode_result = to_unicode_result.map(|()| to_unicode_value);
                check(
                    &source,
                    (&to_unicode, &to_unicode_status),
                    to_unicode_result,
                    |e| e.starts_with('C') || e == "V2" || e == "X4_2",
                );

                let to_ascii_n_result = config.transitional_processing(false).to_ascii(&source);
                check(
                    &source,
                    (&to_ascii_n, &to_ascii_n_status),
                    to_ascii_n_result,
                    |e| e.starts_with('C') || e == "V2",
                );

                let to_ascii_t_result = config.transitional_processing(true).to_ascii(&source);
                check(
                    &source,
                    (&to_ascii_t, &to_ascii_t_status),
                    to_ascii_t_result,
                    |e| e.starts_with('C') || e == "V2",
                );
            }),
        )
    }
}

#[allow(clippy::redundant_clone)]
fn check<F>(source: &str, expected: (&str, &[&str]), actual: Result<String, Errors>, ignore: F)
where
    F: Fn(&str) -> bool,
{
    if !expected.1.is_empty() {
        if !expected.1.iter().copied().any(ignore) {
            let res = actual.ok();
            assert_eq!(
                res.clone(),
                None,
                "Expected error {:?}. result: {} | source: {}",
                expected.1,
                res.unwrap(),
                source,
            );
        }
    } else {
        assert!(
            actual.is_ok(),
            "Couldn't parse {} | error: {:?}",
            source,
            actual.err().unwrap(),
        );
        assert_eq!(actual.unwrap(), expected.0, "source: {}", source);
    }
}

fn unescape(input: &str) -> String {
    let mut output = String::new();
    let mut chars = input.chars();
    loop {
        match chars.next() {
            None => return output,
            Some(c) => {
                if c == '\\' {
                    match chars.next().unwrap() {
                        '\\' => output.push('\\'),
                        'u' => {
                            let c1 = chars.next().unwrap().to_digit(16).unwrap();
                            let c2 = chars.next().unwrap().to_digit(16).unwrap();
                            let c3 = chars.next().unwrap().to_digit(16).unwrap();
                            let c4 = chars.next().unwrap().to_digit(16).unwrap();
                            match char::from_u32(((c1 * 16 + c2) * 16 + c3) * 16 + c4) {
                                Some(c) => output.push(c),
                                None => {
                                    output
                                        .push_str(&format!("\\u{:X}{:X}{:X}{:X}", c1, c2, c3, c4));
                                }
                            };
                        }
                        _ => panic!("Invalid test data input"),
                    }
                } else {
                    output.push(c);
                }
            }
        }
    }
}

fn status(status: &str) -> Vec<&str> {
    if status.is_empty() || status == "[]" {
        return Vec::new();
    }

    let mut result = status.split(", ").collect::<Vec<_>>();
    assert!(result[0].starts_with('['));
    result[0] = &result[0][1..];

    let idx = result.len() - 1;
    let last = &mut result[idx];
    assert!(last.ends_with(']'));
    *last = &last[..last.len() - 1];

    result
}
<|endoftext|>


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

// Spans are encoded using 1-bit tag and 2 different encoding formats (one for each tag value).
// One format is used for keeping span data inline,
// another contains index into an out-of-line span interner.
// The encoding format for inline spans were obtained by optimizing over crates in rustc/libstd.
// See https://internals.rust-lang.org/t/rfc-compiler-refactoring-spans/1357/28

use GLOBALS;
use {BytePos, SpanData};
use hygiene::SyntaxContext;

use rustc_data_structures::fx::FxHashMap;
use std::hash::{Hash, Hasher};

/// A compressed span.
/// Contains either fields of `SpanData` inline if they are small, or index into span interner.
/// The primary goal of `Span` is to be as small as possible and fit into other structures
/// (that's why it uses `packed` as well). Decoding speed is the second priority.
/// See `SpanData` for the info on span fields in decoded representation.
#[repr(packed)]
pub struct Span(u32);

impl Copy for Span {}
impl Clone for Span {
    fn clone(&self) -> Span {
        *self
    }
}
impl PartialEq for Span {
    fn eq(&self, other: &Span) -> bool {
        let a = self.0;
        let b = other.0;
        a == b
    }
}
impl Eq for Span {}
impl Hash for Span {
    fn hash<H: Hasher>(&self, state: &mut H) {
        let a = self.0;
        a.hash(state)
    }
}

/// Dummy span, both position and length are zero, syntax context is zero as well.
/// This span is kept inline and encoded with format 0.
pub const DUMMY_SP: Span = Span(0);

impl Span {
    #[inline]
    pub fn new(lo: BytePos, hi: BytePos, ctxt: SyntaxContext) -> Self {
        encode(&match lo <= hi {
            true => SpanData { lo, hi, ctxt },
            false => SpanData { lo: hi, hi: lo, ctxt },
        })
    }

    #[inline]
    pub fn data(self) -> SpanData {
        decode(self)
    }
}

// Tags
const TAG_INLINE: u32 = 0;
const TAG_INTERNED: u32 = 1;
const TAG_MASK: u32 = 1;

// Fields indexes
const BASE_INDEX: usize = 0;
const LEN_INDEX: usize = 1;
const CTXT_INDEX: usize = 2;

// Tag = 0, inline format.
// -------------------------------------------------------------
// | base 31:8  | len 7:1  | ctxt (currently 0 bits) | tag 0:0 |
// -------------------------------------------------------------
// Since there are zero bits for ctxt, only SpanData with a 0 SyntaxContext
// can be inline.
const INLINE_SIZES: [u32; 3] = [24, 7, 0];
const INLINE_OFFSETS: [u32; 3] = [8, 1, 1];

// Tag = 1, interned format.
// ------------------------
// | index 31:1 | tag 0:0 |
// ------------------------
const INTERNED_INDEX_SIZE: u32 = 31;
const INTERNED_INDEX_OFFSET: u32 = 1;

#[inline]
fn encode(sd: &SpanData) -> Span {
    let (base, len, ctxt) = (sd.lo.0, sd.hi.0 - sd.lo.0, sd.ctxt.0);

    let val = if (base >> INLINE_SIZES[BASE_INDEX]) == 0 &&
                 (len >> INLINE_SIZES[LEN_INDEX]) == 0 &&
                 (ctxt >> INLINE_SIZES[CTXT_INDEX]) == 0 {
        (base << INLINE_OFFSETS[BASE_INDEX]) | (len << INLINE_OFFSETS[LEN_INDEX]) |
        (ctxt << INLINE_OFFSETS[CTXT_INDEX]) | TAG_INLINE
    } else {
        let index = with_span_interner(|interner| interner.intern(sd));
        (index << INTERNED_INDEX_OFFSET) | TAG_INTERNED
    };
    Span(val)
}

#[inline]
fn decode(span: Span) -> SpanData {
    let val = span.0;

    // Extract a field at position `pos` having size `size`.
    let extract = |pos: u32, size: u32| {
        let mask = ((!0u32) as u64 >> (32 - size)) as u32; // Can't shift u32 by 32
        (val >> pos) & mask
    };

    let (base, len, ctxt) = if val & TAG_MASK == TAG_INLINE {(
        extract(INLINE_OFFSETS[BASE_INDEX], INLINE_SIZES[BASE_INDEX]),
        extract(INLINE_OFFSETS[LEN_INDEX], INLINE_SIZES[LEN_INDEX]),
        extract(INLINE_OFFSETS[CTXT_INDEX], INLINE_SIZES[CTXT_INDEX]),
    )} else {
        let index = extract(INTERNED_INDEX_OFFSET, INTERNED_INDEX_SIZE);
        return with_span_interner(|interner| *interner.get(index));
    };
    SpanData { lo: BytePos(base), hi: BytePos(base + len), ctxt: SyntaxContext(ctxt) }
}

#[derive(Default)]
pub struct SpanInterner {
    spans: FxHashMap<SpanData, u32>,
    span_data: Vec<SpanData>,
}

impl SpanInterner {
    fn intern(&mut self, span_data: &SpanData) -> u32 {
        if let Some(index) = self.spans.get(span_data) {
            return *index;
        }

        let index = self.spans.len() as u32;
        self.span_data.push(*span_data);
        self.spans.insert(*span_data, index);
        index
    }

    #[inline]
    fn get(&self, index: u32) -> &SpanData {
        &self.span_data[index as usize]
    }
}

// If an interner exists, return it. Otherwise, prepare a fresh one.
#[inline]
fn with_span_interner<T, F: FnOnce(&mut SpanInterner) -> T>(f: F) -> T {
    GLOBALS.with(|globals| f(&mut *globals.span_interner.lock()))
}
<commit_msg>Rollup merge of #50564 - nnethercote:inline-Span-methods, r=petrochenkov<commit_after>// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

// Spans are encoded using 1-bit tag and 2 different encoding formats (one for each tag value).
// One format is used for keeping span data inline,
// another contains index into an out-of-line span interner.
// The encoding format for inline spans were obtained by optimizing over crates in rustc/libstd.
// See https://internals.rust-lang.org/t/rfc-compiler-refactoring-spans/1357/28

use GLOBALS;
use {BytePos, SpanData};
use hygiene::SyntaxContext;

use rustc_data_structures::fx::FxHashMap;
use std::hash::{Hash, Hasher};

/// A compressed span.
/// Contains either fields of `SpanData` inline if they are small, or index into span interner.
/// The primary goal of `Span` is to be as small as possible and fit into other structures
/// (that's why it uses `packed` as well). Decoding speed is the second priority.
/// See `SpanData` for the info on span fields in decoded representation.
#[repr(packed)]
pub struct Span(u32);

impl Copy for Span {}
impl Clone for Span {
    #[inline]
    fn clone(&self) -> Span {
        *self
    }
}
impl PartialEq for Span {
    #[inline]
    fn eq(&self, other: &Span) -> bool {
        let a = self.0;
        let b = other.0;
        a == b
    }
}
impl Eq for Span {}
impl Hash for Span {
    #[inline]
    fn hash<H: Hasher>(&self, state: &mut H) {
        let a = self.0;
        a.hash(state)
    }
}

/// Dummy span, both position and length are zero, syntax context is zero as well.
/// This span is kept inline and encoded with format 0.
pub const DUMMY_SP: Span = Span(0);

impl Span {
    #[inline]
    pub fn new(lo: BytePos, hi: BytePos, ctxt: SyntaxContext) -> Self {
        encode(&match lo <= hi {
            true => SpanData { lo, hi, ctxt },
            false => SpanData { lo: hi, hi: lo, ctxt },
        })
    }

    #[inline]
    pub fn data(self) -> SpanData {
        decode(self)
    }
}

// Tags
const TAG_INLINE: u32 = 0;
const TAG_INTERNED: u32 = 1;
const TAG_MASK: u32 = 1;

// Fields indexes
const BASE_INDEX: usize = 0;
const LEN_INDEX: usize = 1;
const CTXT_INDEX: usize = 2;

// Tag = 0, inline format.
// -------------------------------------------------------------
// | base 31:8  | len 7:1  | ctxt (currently 0 bits) | tag 0:0 |
// -------------------------------------------------------------
// Since there are zero bits for ctxt, only SpanData with a 0 SyntaxContext
// can be inline.
const INLINE_SIZES: [u32; 3] = [24, 7, 0];
const INLINE_OFFSETS: [u32; 3] = [8, 1, 1];

// Tag = 1, interned format.
// ------------------------
// | index 31:1 | tag 0:0 |
// ------------------------
const INTERNED_INDEX_SIZE: u32 = 31;
const INTERNED_INDEX_OFFSET: u32 = 1;

#[inline]
fn encode(sd: &SpanData) -> Span {
    let (base, len, ctxt) = (sd.lo.0, sd.hi.0 - sd.lo.0, sd.ctxt.0);

    let val = if (base >> INLINE_SIZES[BASE_INDEX]) == 0 &&
                 (len >> INLINE_SIZES[LEN_INDEX]) == 0 &&
                 (ctxt >> INLINE_SIZES[CTXT_INDEX]) == 0 {
        (base << INLINE_OFFSETS[BASE_INDEX]) | (len << INLINE_OFFSETS[LEN_INDEX]) |
        (ctxt << INLINE_OFFSETS[CTXT_INDEX]) | TAG_INLINE
    } else {
        let index = with_span_interner(|interner| interner.intern(sd));
        (index << INTERNED_INDEX_OFFSET) | TAG_INTERNED
    };
    Span(val)
}

#[inline]
fn decode(span: Span) -> SpanData {
    let val = span.0;

    // Extract a field at position `pos` having size `size`.
    let extract = |pos: u32, size: u32| {
        let mask = ((!0u32) as u64 >> (32 - size)) as u32; // Can't shift u32 by 32
        (val >> pos) & mask
    };

    let (base, len, ctxt) = if val & TAG_MASK == TAG_INLINE {(
        extract(INLINE_OFFSETS[BASE_INDEX], INLINE_SIZES[BASE_INDEX]),
        extract(INLINE_OFFSETS[LEN_INDEX], INLINE_SIZES[LEN_INDEX]),
        extract(INLINE_OFFSETS[CTXT_INDEX], INLINE_SIZES[CTXT_INDEX]),
    )} else {
        let index = extract(INTERNED_INDEX_OFFSET, INTERNED_INDEX_SIZE);
        return with_span_interner(|interner| *interner.get(index));
    };
    SpanData { lo: BytePos(base), hi: BytePos(base + len), ctxt: SyntaxContext(ctxt) }
}

#[derive(Default)]
pub struct SpanInterner {
    spans: FxHashMap<SpanData, u32>,
    span_data: Vec<SpanData>,
}

impl SpanInterner {
    fn intern(&mut self, span_data: &SpanData) -> u32 {
        if let Some(index) = self.spans.get(span_data) {
            return *index;
        }

        let index = self.spans.len() as u32;
        self.span_data.push(*span_data);
        self.spans.insert(*span_data, index);
        index
    }

    #[inline]
    fn get(&self, index: u32) -> &SpanData {
        &self.span_data[index as usize]
    }
}

// If an interner exists, return it. Otherwise, prepare a fresh one.
#[inline]
fn with_span_interner<T, F: FnOnce(&mut SpanInterner) -> T>(f: F) -> T {
    GLOBALS.with(|globals| f(&mut *globals.span_interner.lock()))
}
<|endoftext|>


<commit_before>use analysis::rust_type::Result;
use env::Env;
use gobjects::GStatus;
use library;
use nameutil::module_name;

pub fn ffi_type(env: &Env, type_id: library::TypeId) -> Result {
    use library::Type::*;
    use library::Fundamental::*;
    let type_ = env.library.type_(type_id);
    match type_ {
        &Fundamental(fund) => {
            let ok = |s: &str| Ok(s.into());
            let err = |s: &str| Err(s.into());
            match fund {
                None => err("()"),
                Boolean => ok("gboolean"),
                Int8 => ok("i8"),
                UInt8 => ok("u8"),
                Int16 => ok("i16"),
                UInt16 => ok("u16"),
                Int32 => ok("i32"),
                UInt32 => ok("u32"),
                Int64 => ok("i64"),
                UInt64 => ok("u64"),

                Int => ok("c_int"),      //maybe dependent on target system
                UInt => ok("c_uint"),     //maybe dependent on target system

                Float => ok("c_float"),
                Double => ok("c_double"),

                Utf8 => ok("*const c_char"),

                Type => ok("GType"),
                Unsupported => err("Unsupported"),
                _ => err(&format!("Fundamental: {:?}", fund)),
            }
        },

        &Enumeration(ref enum_) => Ok(format!("enums::{}", enum_.name)),
        &Interface(ref interface) => to_mut_ptr(fix_external_name(env, type_id, &interface.glib_type_name)),
        &Class(ref klass) => to_mut_ptr(fix_external_name(env, type_id, &klass.glib_type_name)),
        _ => Err(format!("Unknown rust type: {:?}", type_.get_name() )),
        //TODO: check usage library::Type::get_name() when no _ in this
    }
}

fn fix_external_name(env: &Env, type_id: library::TypeId, name: &str) -> Result {
    if type_id.ns_id == library::MAIN_NAMESPACE || type_id.ns_id == library::INTERNAL_NAMESPACE {
        Ok(name.into())
    } else {
        let name_with_prefix = format!("{}_ffi::{}",
            fix_namespace(env, type_id), name);
        if env.type_status(&type_id.full_name(&env.library)) == GStatus::Ignore {
            Err(name_with_prefix.into())
        } else {
            Ok(name_with_prefix)
        }
    }
}

fn to_mut_ptr(res: Result) -> Result {
    match res {
        Ok(s) => Ok(format!("*mut {}", s)),
        Err(s) => Err(format!("*mut {}", s)),
    }
}

//TODO: check if need to use in non sys codegen
fn fix_namespace(env: &Env, type_id: library::TypeId) -> String {
    let mut name: &str = &module_name(&env.library.namespace(type_id.ns_id).name);
    name = match name {
        "gdk_pixbuf" => "gdk",
        "gio" => "glib",
        "gobject" => "glib",
        _ => name,
    };
    name.into()
}
<commit_msg>Reference the enum and bitfield types correctly<commit_after>use analysis::rust_type::Result;
use env::Env;
use gobjects::GStatus;
use library;
use nameutil::module_name;

pub fn ffi_type(env: &Env, type_id: library::TypeId) -> Result {
    use library::Type::*;
    use library::Fundamental::*;
    let type_ = env.library.type_(type_id);
    let res = match type_ {
        &Fundamental(fund) => {
            let ok = |s: &str| Ok(s.into());
            let err = |s: &str| Err(s.into());
            match fund {
                None => err("()"),
                Boolean => ok("gboolean"),
                Int8 => ok("i8"),
                UInt8 => ok("u8"),
                Int16 => ok("i16"),
                UInt16 => ok("u16"),
                Int32 => ok("i32"),
                UInt32 => ok("u32"),
                Int64 => ok("i64"),
                UInt64 => ok("u64"),

                Int => ok("c_int"),      //maybe dependent on target system
                UInt => ok("c_uint"),     //maybe dependent on target system

                Float => ok("c_float"),
                Double => ok("c_double"),

                Utf8 => ok("*const c_char"),

                Type => ok("GType"),
                Unsupported => err("Unsupported"),
                _ => err(&format!("Fundamental: {:?}", fund)),
            }
        },

        &Bitfield(ref bitfield) => fix_external_name(env, type_id, &bitfield.name),
        &Enumeration(ref enum_) => fix_external_name(env, type_id, &enum_.name),
        &Interface(ref interface) => to_mut_ptr(fix_external_name(env, type_id, &interface.glib_type_name)),
        &Class(ref klass) => to_mut_ptr(fix_external_name(env, type_id, &klass.glib_type_name)),
        _ => Err(format!("Unknown rust type: {:?}", type_.get_name() )),
        //TODO: check usage library::Type::get_name() when no _ in this
    };
    trace!("ffi_type({:?}) -> {:?}", type_id, res);
    res
}

fn fix_external_name(env: &Env, type_id: library::TypeId, name: &str) -> Result {
    if type_id.ns_id == library::MAIN_NAMESPACE || type_id.ns_id == library::INTERNAL_NAMESPACE {
        Ok(name.into())
    } else {
        let name_with_prefix = format!("{}_ffi::{}",
            fix_namespace(env, type_id), name);
        if env.type_status(&type_id.full_name(&env.library)) == GStatus::Ignore {
            Err(name_with_prefix.into())
        } else {
            Ok(name_with_prefix)
        }
    }
}

fn to_mut_ptr(res: Result) -> Result {
    match res {
        Ok(s) => Ok(format!("*mut {}", s)),
        Err(s) => Err(format!("*mut {}", s)),
    }
}

//TODO: check if need to use in non sys codegen
fn fix_namespace(env: &Env, type_id: library::TypeId) -> String {
    let mut name: &str = &module_name(&env.library.namespace(type_id.ns_id).name);
    name = match name {
        "gdk_pixbuf" => "gdk",
        "gio" => "glib",
        "gobject" => "glib",
        _ => name,
    };
    name.into()
}
<|endoftext|>


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

//! The Pareto distribution.

use Rng;
use distributions::{Distribution, OpenClosed01};

/// Samples floating-point numbers according to the Pareto distribution
///
/// # Example
/// ```
/// use rand::prelude::*;
/// use rand::distributions::Pareto;
///
/// let val: f64 = SmallRng::from_entropy().sample(Pareto::new(1., 2.));
/// println!("{}", val);
/// ```
#[derive(Clone, Copy, Debug)]
pub struct Pareto {
    scale: f64,
    shape: f64,
}

impl Pareto {
    /// Construct a new Pareto distribution with given `scale` and `shape`.
    ///
    /// # Panics
    ///
    /// `scale` and `shape` have to be non-zero and positive.
    pub fn new(scale: f64, shape: f64) -> Pareto {
        assert!((scale > 0.) & (shape > 0.));
        Pareto { scale, shape }
    }
}

impl Distribution<f64> for Pareto {
    fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> f64 {
        let u: f64 = rng.sample(OpenClosed01);
        self.scale * u.powf(-1.0 / self.shape)
    }
}

#[cfg(test)]
mod tests {
    use distributions::Distribution;
    use super::Pareto;

    #[test]
    #[should_panic]
    fn invalid() {
        Pareto::new(0., 0.);
    }

    #[test]
    fn sample() {
        let d = Pareto::new(1.0, 2.0);
        let mut rng = ::test::rng(1);
        for _ in 0..1000 {
            d.sample(&mut rng);
        }
    }
}
<commit_msg>Add common names for Pareto parameters<commit_after>// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// https://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! The Pareto distribution.

use Rng;
use distributions::{Distribution, OpenClosed01};

/// Samples floating-point numbers according to the Pareto distribution
///
/// # Example
/// ```
/// use rand::prelude::*;
/// use rand::distributions::Pareto;
///
/// let val: f64 = SmallRng::from_entropy().sample(Pareto::new(1., 2.));
/// println!("{}", val);
/// ```
#[derive(Clone, Copy, Debug)]
pub struct Pareto {
    scale: f64,
    shape: f64,
}

impl Pareto {
    /// Construct a new Pareto distribution with given `scale` and `shape`.
    ///
    /// In the literature, `scale` is commonly written as xm or k and
    /// `shape` is often written as α.
    ///
    /// # Panics
    ///
    /// `scale` and `shape` have to be non-zero and positive.
    pub fn new(scale: f64, shape: f64) -> Pareto {
        assert!((scale > 0.) & (shape > 0.));
        Pareto { scale, shape }
    }
}

impl Distribution<f64> for Pareto {
    fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> f64 {
        let u: f64 = rng.sample(OpenClosed01);
        self.scale * u.powf(-1.0 / self.shape)
    }
}

#[cfg(test)]
mod tests {
    use distributions::Distribution;
    use super::Pareto;

    #[test]
    #[should_panic]
    fn invalid() {
        Pareto::new(0., 0.);
    }

    #[test]
    fn sample() {
        let d = Pareto::new(1.0, 2.0);
        let mut rng = ::test::rng(1);
        for _ in 0..1000 {
            d.sample(&mut rng);
        }
    }
}
<|endoftext|>


<commit_before>use std::fs;
use std::path::PathBuf;

use cfg::CargonautsConfig;
use heck::KebabCase;
use quote::{ToTokens, Tokens, Ident};

use ast::*;

pub struct Routes {
    routes: Vec<Route>,
}

impl Routes {
    pub fn new(resources: &[Resource], cfg: &CargonautsConfig) -> Routes {
        Routes {
            routes: Route::build(resources, cfg),
        }
    }
}

impl ToTokens for Routes {
    fn to_tokens(&self, tokens: &mut Tokens) {
        let routes = &self.routes;
        tokens.append(quote! ({
            use ::cargonauts::server::NewService;
            let routes = vec!#routes.into_iter().collect();
            ::cargonauts::routing::RoutingTable::new(routes, assets, asset_handler, env)
        }));
    }
}

#[derive(Clone)]
struct Route {
    resource: String,
    endpoint: String,
    method: String,
    format: String,
    rel: Option<String>,
    rel_endpoint: Option<String>,
    middleware: Option<String>,
    template_root: PathBuf,
}

impl Route {
    fn build(resources: &[Resource], cfg: &CargonautsConfig) -> Vec<Route> {
        let mut vec = vec![];

        let root = cfg.templates();

        for resource in resources {
            let endpoint = resource.header.endpoint.clone().unwrap_or_else(|| {
                resource.header.ty.to_kebab_case()
            });

            let resource_ty = &resource.header.ty;

            for (method, attrs) in resource.members.iter().filter_map(|m| m.as_method()) {
                let middleware = attrs.iter().filter_map(|attr| attr.as_middleware()).next();
                for m in &method.methods {
                    vec.push(Route {
                        resource: resource_ty.clone(),
                        endpoint: endpoint.clone(),
                        method: m.clone(),
                        format: method.format.clone(),
                        rel: None,
                        rel_endpoint: None,
                        middleware: middleware.clone(),
                        template_root: root.clone(),
                    })
                }
            }

            for relation in resource.members.iter().filter_map(|m| m.as_relation()) {
                for (method, attrs) in relation.members.iter().filter_map(|m| m.as_method()) {
                    let middleware = attrs.iter().filter_map(|attr| attr.as_middleware()).next();
                    for m in &method.methods {
                        vec.push(Route {
                            resource: resource_ty.clone(),
                            endpoint: endpoint.clone(),
                            method: m.clone(),
                            format: method.format.clone(),
                            rel: None,
                            rel_endpoint: None,
                            middleware: middleware.clone(),
                            template_root: root.clone(),
                        })
                    }
                }
            }
        }

        vec
    }
}

impl ToTokens for Route {
    fn to_tokens(&self, tokens: &mut Tokens) {
        let endpoint = &self.endpoint;
        let template = load_template(self.template_root.clone(),
                                     &self.resource,
                                     &self.method,
                                     self.rel.as_ref());
        let resource = Ident::new(&self.resource[..]);
        let format = Ident::new(&self.format[..]);
        let method = method_for(&self.method, self.rel.as_ref(), &resource);

        let route_key = if let Some(ref rel) = self.rel_endpoint {
            quote!(::cargonauts::routing::RouteKey::new(#endpoint, <#method as ::cargonauts::method::Method<#resource>>::ROUTE, Some(#rel)))
        } else {
            quote!(::cargonauts::routing::RouteKey::new(#endpoint, <#method as ::cargonauts::method::Method<#resource>>::ROUTE, None))
        };

        if let Some(ref middleware) = self.middleware {
            let middleware = Ident::new(&middleware[..]);
            tokens.append(quote!({
                let route_key = #route_key;
                let service = ::cargonauts::routing::EndpointService::<_, _, (#resource, #format, #method)>::new(#template);
                let middleware = <#middleware as Default>::default();
                let service = ::cargonauts::middleware::Middleware::wrap(middleware, service);
                (route_key, Box::new(service) as ::cargonauts::routing::Handler)
            }));
        } else {
            tokens.append(quote!({
                let route_key = #route_key;
                let service = ::cargonauts::routing::EndpointService::<_, _, (#resource, #format, #method)>::new(#template);
                (route_key, Box::new(service) as ::cargonauts::routing::Handler)
            }));
        }

    }
}

fn method_for(method: &str, rel: Option<&String>, resource: &Ident) -> Tokens {
    // Special cases to allow mainsail methods to have associated types
    match method {
        "Post"  => {
            quote!(Post<Identifier = <#resource as ::cargonauts::api::Resource>::Identifier, Post = <#resource as ::cargonauts::api::Post>::Post>)
        }
        "Patch" => {
            quote!(Patch<Identifier = <#resource as ::cargonauts::api::Resource>::Identifier, Patch = <#resource as ::cargonauts::api::Patch>::Patch>)
        }
        "PostRelated" => {
            let rel = Ident::new(&rel.unwrap()[..]);
            quote!(PostRelated<#rel, Identifier = <#resource as ::cargonauts::api::Resource>::Identifier, Post = <#resource as ::cargonauts::api::PostRelated<#rel>::Post>)
        }
        "UpdateRelated" => {
            let rel = Ident::new(&rel.unwrap()[..]);
            quote!(UpdateRelated<#rel, Identifier = <#resource as ::cargonauts::api::Resource>::Identifier, Update = <#resource as ::cargonauts::api::UpdateRelated<#rel>::Update>)
        }
        _       => {
            let method = Ident::new(method);
            match rel {
                Some(rel)   => {
                    let rel = Ident::new(&rel[..]);
                    quote!(#method<#rel, Identifier = <#resource as ::cargonauts::api::Resource>::Identifier>)
                }
                None        => {
                    quote!(#method<Identifier = <#resource as ::cargonauts::api::Resource>::Identifier>)
                }
            }
        }
    }
}

fn load_template(mut path: PathBuf, resource: &str, method: &str, rel: Option<&String>) -> Tokens {
    path.push(resource);
    if let Some(rel) = rel { path.push(rel); }

    let match_method = |entry: &fs::DirEntry| {
        entry.file_name().into_string().unwrap().starts_with(&method.to_kebab_case())
    };

    let mut walk_dir = fs::read_dir(path).into_iter().flat_map(|ls| ls.into_iter().map(|e| e.unwrap()));

    if let Some(entry) = walk_dir.find(match_method) {
        let path = entry.path();
        let path = path.to_string_lossy();
        quote!(Some(::cargonauts::format::Template::static_prepare(include_str!(#path))))
    } else {
        quote!(None)
    }
}
<commit_msg>Fix bug in rel routes gen.<commit_after>use std::fs;
use std::path::PathBuf;

use cfg::CargonautsConfig;
use heck::KebabCase;
use quote::{ToTokens, Tokens, Ident};

use ast::*;

pub struct Routes {
    routes: Vec<Route>,
}

impl Routes {
    pub fn new(resources: &[Resource], cfg: &CargonautsConfig) -> Routes {
        Routes {
            routes: Route::build(resources, cfg),
        }
    }
}

impl ToTokens for Routes {
    fn to_tokens(&self, tokens: &mut Tokens) {
        let routes = &self.routes;
        tokens.append(quote! ({
            use ::cargonauts::server::NewService;
            let routes = vec!#routes.into_iter().collect();
            ::cargonauts::routing::RoutingTable::new(routes, assets, asset_handler, env)
        }));
    }
}

#[derive(Clone)]
struct Route {
    resource: String,
    endpoint: String,
    method: String,
    format: String,
    rel: Option<String>,
    rel_endpoint: Option<String>,
    middleware: Option<String>,
    template_root: PathBuf,
}

impl Route {
    fn build(resources: &[Resource], cfg: &CargonautsConfig) -> Vec<Route> {
        let mut vec = vec![];

        let root = cfg.templates();

        for resource in resources {
            let endpoint = resource.header.endpoint.clone().unwrap_or_else(|| {
                resource.header.ty.to_kebab_case()
            });

            let resource_ty = &resource.header.ty;

            for (method, attrs) in resource.members.iter().filter_map(|m| m.as_method()) {
                let middleware = attrs.iter().filter_map(|attr| attr.as_middleware()).next();
                for m in &method.methods {
                    vec.push(Route {
                        resource: resource_ty.clone(),
                        endpoint: endpoint.clone(),
                        method: m.clone(),
                        format: method.format.clone(),
                        rel: None,
                        rel_endpoint: None,
                        middleware: middleware.clone(),
                        template_root: root.clone(),
                    })
                }
            }

            for relation in resource.members.iter().filter_map(|m| m.as_relation()) {
                for (method, attrs) in relation.members.iter().filter_map(|m| m.as_method()) {
                    let middleware = attrs.iter().filter_map(|attr| attr.as_middleware()).next();
                    for m in &method.methods {
                        vec.push(Route {
                            resource: resource_ty.clone(),
                            endpoint: endpoint.clone(),
                            method: m.clone(),
                            format: method.format.clone(),
                            rel: Some(relation.rel.clone()),
                            rel_endpoint: relation.endpoint.clone().or_else(|| Some(relation.rel.to_kebab_case())),
                            middleware: middleware.clone(),
                            template_root: root.clone(),
                        })
                    }
                }
            }
        }

        vec
    }
}

impl ToTokens for Route {
    fn to_tokens(&self, tokens: &mut Tokens) {
        let endpoint = &self.endpoint;
        let template = load_template(self.template_root.clone(),
                                     &self.resource,
                                     &self.method,
                                     self.rel.as_ref());
        let resource = Ident::new(&self.resource[..]);
        let format = Ident::new(&self.format[..]);
        let method = method_for(&self.method, self.rel.as_ref(), &resource);

        let route_key = if let Some(ref rel) = self.rel_endpoint {
            quote!(::cargonauts::routing::RouteKey::new(#endpoint, <#method as ::cargonauts::method::Method<#resource>>::ROUTE, Some(#rel)))
        } else {
            quote!(::cargonauts::routing::RouteKey::new(#endpoint, <#method as ::cargonauts::method::Method<#resource>>::ROUTE, None))
        };

        if let Some(ref middleware) = self.middleware {
            let middleware = Ident::new(&middleware[..]);
            tokens.append(quote!({
                let route_key = #route_key;
                let service = ::cargonauts::routing::EndpointService::<_, _, (#resource, #format, #method)>::new(#template);
                let middleware = <#middleware as Default>::default();
                let service = ::cargonauts::middleware::Middleware::wrap(middleware, service);
                (route_key, Box::new(service) as ::cargonauts::routing::Handler)
            }));
        } else {
            tokens.append(quote!({
                let route_key = #route_key;
                let service = ::cargonauts::routing::EndpointService::<_, _, (#resource, #format, #method)>::new(#template);
                (route_key, Box::new(service) as ::cargonauts::routing::Handler)
            }));
        }

    }
}

fn method_for(method: &str, rel: Option<&String>, resource: &Ident) -> Tokens {
    // Special cases to allow mainsail methods to have associated types
    match method {
        "Post"  => {
            quote!(Post<Identifier = <#resource as ::cargonauts::api::Resource>::Identifier, Post = <#resource as ::cargonauts::api::Post>::Post>)
        }
        "Patch" => {
            quote!(Patch<Identifier = <#resource as ::cargonauts::api::Resource>::Identifier, Patch = <#resource as ::cargonauts::api::Patch>::Patch>)
        }
        "PostRelated" => {
            let rel = Ident::new(&rel.unwrap()[..]);
            quote!(PostRelated<#rel, Identifier = <#resource as ::cargonauts::api::Resource>::Identifier, Post = <#resource as ::cargonauts::api::PostRelated<#rel>::Post>)
        }
        "UpdateRelated" => {
            let rel = Ident::new(&rel.unwrap()[..]);
            quote!(UpdateRelated<#rel, Identifier = <#resource as ::cargonauts::api::Resource>::Identifier, Update = <#resource as ::cargonauts::api::UpdateRelated<#rel>::Update>)
        }
        _       => {
            let method = Ident::new(method);
            match rel {
                Some(rel)   => {
                    let rel = Ident::new(&rel[..]);
                    quote!(#method<#rel, Identifier = <#resource as ::cargonauts::api::Resource>::Identifier>)
                }
                None        => {
                    quote!(#method<Identifier = <#resource as ::cargonauts::api::Resource>::Identifier>)
                }
            }
        }
    }
}

fn load_template(mut path: PathBuf, resource: &str, method: &str, rel: Option<&String>) -> Tokens {
    path.push(resource);
    if let Some(rel) = rel { path.push(rel); }

    let match_method = |entry: &fs::DirEntry| {
        entry.file_name().into_string().unwrap().starts_with(&method.to_kebab_case())
    };

    let mut walk_dir = fs::read_dir(path).into_iter().flat_map(|ls| ls.into_iter().map(|e| e.unwrap()));

    if let Some(entry) = walk_dir.find(match_method) {
        let path = entry.path();
        let path = path.to_string_lossy();
        quote!(Some(::cargonauts::format::Template::static_prepare(include_str!(#path))))
    } else {
        quote!(None)
    }
}
<|endoftext|>


<commit_before>extern crate rustyham;
use rustyham::rustyham::*;

#[test]
fn test_encode() {
    assert_eq!(hamming(Hamming::Encode, "test".to_string()), "111011011001100110111100111110100000000000000000000000000000000".to_string());
}

#[test]
fn test_decode() {
    assert_eq!(hamming(Hamming::Decode, "111011011001100110111100111110100000000000000000000000000000000".to_string()), "test".to_string());
}

#[test]
fn test_encode_binary() {
    assert_eq!(hamming(Hamming::EncodeBinary, "101010".to_string()), "111101001010000");
}

#[test]
fn test_decode_binary() {
    assert_eq!(hamming(Hamming::DecodeBinary, "111101001010000".to_string()), "101010");
}
<commit_msg>add error correction test<commit_after>extern crate rustyham;
use rustyham::rustyham::*;

#[test]
fn test_encode() {
    assert_eq!(hamming(Hamming::Encode, "test".to_string()), "111011011001100110111100111110100000000000000000000000000000000".to_string());
}

#[test]
fn test_decode() {
    assert_eq!(hamming(Hamming::Decode, "111011011001100110111100111110100000000000000000000000000000000".to_string()), "test".to_string());
}

#[test]
fn test_encode_binary() {
    assert_eq!(hamming(Hamming::EncodeBinary, "101010".to_string()), "111101001010000");
}

#[test]
fn test_decode_binary() {
    assert_eq!(hamming(Hamming::DecodeBinary, "111101001010000".to_string()), "101010");
}

#[test]
fn test_error_correction() {
    let s = hamming(Hamming::Encode, "test".to_string()).into_bytes();
    for i in 0..s.len() {
        let mut s2 = s.clone();
        s2[i] = if s2[i] == 48 { 49 } else { 48 };
        assert_eq!(hamming(Hamming::Decode, String::from_utf8(s2).unwrap()), "test".to_string());
    }
}
<|endoftext|>


<commit_before>extern crate image;

use std::io::{fs, File, USER_RWX};

#[test]
fn test_open_and_save_tga() {
    let _ = fs::mkdir(&Path::new("./tests/output"), USER_RWX);
    let path = Path::new("./tests/images/tga/testsuite/ctc24.tga");
    let img = image::open(&path).unwrap();
    let fout = File::create(&Path::new("./tests/output/tga-ctc24.png")).unwrap();
    let _ = img.save(fout, image::PNG);

    let path = Path::new("./tests/images/tga/testsuite/cbw8.tga");
    let img = image::open(&path).unwrap();
    let fout = File::create(&Path::new("./tests/output/tga-cbw8.png")).unwrap();
    let _ = img.save(fout, image::PNG);
}
<commit_msg>Unstable code in tests...<commit_after>#![allow(unstable)]

extern crate image;

use std::io::{fs, File, USER_RWX};

#[test]
fn test_open_and_save_tga() {
    let _ = fs::mkdir(&Path::new("./tests/output"), USER_RWX);
    let path = Path::new("./tests/images/tga/testsuite/ctc24.tga");
    let img = image::open(&path).unwrap();
    let fout = File::create(&Path::new("./tests/output/tga-ctc24.png")).unwrap();
    let _ = img.save(fout, image::PNG);

    let path = Path::new("./tests/images/tga/testsuite/cbw8.tga");
    let img = image::open(&path).unwrap();
    let fout = File::create(&Path::new("./tests/output/tga-cbw8.png")).unwrap();
    let _ = img.save(fout, image::PNG);
}
<|endoftext|>