<commit_before>use std::cmp::{max, min};
use std::collections::{HashMap, HashSet};
use std::fmt::Debug;
use utils::calculate_ratio;

#[derive(Debug, Clone, Copy, PartialEq, PartialOrd, Eq, Ord)]
pub struct Match {
    pub first_start: usize,
    pub second_start: usize,
    pub size: usize,
}

impl Match {
    fn new(first_start: usize, second_start: usize, size: usize) -> Match {
        Match {
            first_start: first_start,
            second_start: second_start,
            size: size,
        }
    }
}

#[derive(Debug, Clone, PartialEq)]
pub struct Opcode {
    pub tag: String,
    pub first_start: usize,
    pub first_end: usize,
    pub second_start: usize,
    pub second_end: usize,
}

impl Opcode {
    fn new(
        tag: String,
        first_start: usize,
        first_end: usize,
        second_start: usize,
        second_end: usize,
    ) -> Opcode {
        Opcode {
            tag: tag,
            first_start: first_start,
            first_end: first_end,
            second_start: second_start,
            second_end: second_end,
        }
    }
}

pub trait Sequence: Debug {
    fn len(&self) -> usize;
    fn at_index(&self, index: usize) -> Option<&str>;
}

impl Sequence for str {
    fn len(&self) -> usize {
        self.len()
    }

    fn at_index(&self, index: usize) -> Option<&str> {
        if index > self.len() {
            return None;
        }
        unsafe { Some(self.slice_unchecked(index, index + 1)) }
    }
}

impl<'a> Sequence for Vec<&'a str> {
    fn len(&self) -> usize {
        self.len()
    }

    fn at_index(&self, index: usize) -> Option<&str> {
        if index < self.len() {
            return Some(self[index]);
        }
        None
    }
}

impl Sequence for String {
    fn len(&self) -> usize {
        self.len()
    }

    fn at_index(&self, index: usize) -> Option<&str> {
        if index > self.len() {
            return None;
        }
        unsafe { Some(self.slice_unchecked(index, index + 1)) }
    }
}

impl<'a> Sequence for Vec<String> {
    fn len(&self) -> usize {
        self.len()
    }

    fn at_index(&self, index: usize) -> Option<&str> {
        if index < self.len() {
            return Some(&self[index]);
        }
        None
    }
}

pub struct SequenceMatcher<'a, T: 'a + ?Sized + Sequence> {
    first_sequence: &'a T,
    second_sequence: &'a T,
    matching_blocks: Option<Vec<Match>>,
    opcodes: Option<Vec<Opcode>>,
    is_junk: Option<fn(&str) -> bool>,
    second_sequence_elements: HashMap<&'a str, Vec<usize>>,
}

impl<'a, T: ?Sized + Sequence> SequenceMatcher<'a, T> {
    pub fn new(first_sequence: &'a T, second_sequence: &'a T) -> SequenceMatcher<'a, T> {
        let mut matcher = SequenceMatcher {
            first_sequence: first_sequence,
            second_sequence: second_sequence,
            matching_blocks: None,
            opcodes: None,
            is_junk: None,
            second_sequence_elements: HashMap::new(),
        };
        matcher.set_seqs(first_sequence, second_sequence);
        matcher
    }

    pub fn set_is_junk(&mut self, is_junk: Option<fn(&str) -> bool>) {
        self.is_junk = is_junk;
        self.set_second_seq(self.second_sequence);
    }

    pub fn set_seqs(&mut self, first_sequence: &'a T, second_sequence: &'a T) {
        self.set_first_seq(first_sequence);
        self.set_second_seq(second_sequence);
    }

    pub fn set_first_seq(&mut self, sequence: &'a T) {
        self.first_sequence = sequence;
        self.matching_blocks = None;
        self.opcodes = None;
    }

    pub fn set_second_seq(&mut self, sequence: &'a T) {
        self.second_sequence = sequence;
        self.matching_blocks = None;
        self.opcodes = None;
        self.chain_second_seq();
    }

    fn chain_second_seq(&mut self) {
        let second_sequence = self.second_sequence;
        let mut second_sequence_elements = HashMap::new();
        for i in 0..second_sequence.len() {
            let mut counter = second_sequence_elements
                .entry(second_sequence.at_index(i).unwrap())
                .or_insert(Vec::new());
            counter.push(i);
        }
        if self.is_junk.is_some() {
            let mut junk = Vec::new();
            for element in second_sequence_elements.keys() {
                if (self.is_junk.unwrap())(element) {
                    junk.push(element.clone());
                }
            }
            for element in &junk {
                second_sequence_elements.remove(element);
            }
        }
        let mut popular = HashSet::new();
        let len = second_sequence.len();
        if len >= 200 {
            let test_len = (len as f32 / 100.0).floor() as usize + 1;
            for (element, indexes) in second_sequence_elements.iter() {
                if indexes.len() > test_len {
                    popular.insert(element.clone());
                }
            }
            for element in &popular {
                second_sequence_elements.remove(element);
            }
        }
        self.second_sequence_elements = second_sequence_elements;
    }

    pub fn find_longest_match(
        &self,
        first_start: usize,
        first_end: usize,
        second_start: usize,
        second_end: usize,
    ) -> Match {
        let first_sequence = &self.first_sequence;
        let second_sequence = &self.second_sequence;
        let second_sequence_elements = &self.second_sequence_elements;
        let (mut best_i, mut best_j, mut best_size) = (first_start, second_start, 0);
        let mut j2len: HashMap<usize, usize> = HashMap::new();
        for i in first_start..first_end {
            let mut new_j2len: HashMap<usize, usize> = HashMap::new();
            match second_sequence_elements.get(first_sequence.at_index(i).unwrap()) {
                Some(indexes) => {
                    for j in indexes {
                        let j = j.clone();
                        if j < second_start {
                            continue;
                        };
                        if j >= second_end {
                            break;
                        };
                        let mut size = 0;
                        if j > 0 {
                            match j2len.get(&(j - 1)) {
                                Some(k) => {
                                    size = k.clone();
                                }
                                None => {}
                            }
                        }
                        size += 1;
                        new_j2len.insert(j, size);
                        if size > best_size {
                            best_i = i + 1 - size;
                            best_j = j + 1 - size;
                            best_size = size;
                        }
                    }
                }
                None => {}
            }
            j2len = new_j2len;
        }
        for _ in 0..2 {
            while best_i > first_start
                && best_j > second_start
                && first_sequence.at_index(best_i - 1) == second_sequence.at_index(best_j - 1)
            {
                best_i = best_i - 1;
                best_j = best_j - 1;
                best_size = best_size + 1;
            }
            while best_i + best_size < first_end && best_j + best_size < second_end
                && first_sequence.at_index(best_i + best_size)
                    == second_sequence.at_index(best_j + best_size)
            {
                best_size += 1;
            }
        }
        Match::new(best_i, best_j, best_size)
    }

    pub fn get_matching_blocks(&mut self) -> Vec<Match> {
        if self.matching_blocks.as_ref().is_some() {
            return self.matching_blocks.as_ref().unwrap().clone();
        }
        let (first_length, second_length) = (self.first_sequence.len(), self.second_sequence.len());
        let mut matches = Vec::new();
        let mut queue = vec![(0, first_length, 0, second_length)];
        while !queue.is_empty() {
            let (first_start, first_end, second_start, second_end) = queue.pop().unwrap();
            let m = self.find_longest_match(first_start, first_end, second_start, second_end);
            match m.size {
                0 => {}
                _ => {
                    if first_start < m.first_start && second_start < m.second_start {
                        queue.push((first_start, m.first_start, second_start, m.second_start));
                    }
                    if m.first_start + m.size < first_end && m.second_start + m.size < second_end {
                        queue.push((
                            m.first_start + m.size,
                            first_end,
                            m.second_start + m.size,
                            second_end,
                        ));
                    }
                    matches.push(m);
                }
            }
        }
        matches.sort_by(|a, b| a.cmp(b));
        let (mut first_start, mut second_start, mut size) = (0, 0, 0);
        let mut non_adjacent = Vec::new();
        for m in &matches {
            if first_start + size == m.first_start && second_start + size == m.second_start {
                size += m.size
            } else {
                if size != 0 {
                    non_adjacent.push(Match::new(first_start, second_start, size));
                }
                first_start = m.first_start;
                second_start = m.second_start;
                size = m.size;
            }
        }
        if size != 0 {
            non_adjacent.push(Match::new(first_start, second_start, size));
        }
        non_adjacent.push(Match::new(first_length, second_length, 0));
        self.matching_blocks = Some(non_adjacent);
        self.matching_blocks.as_ref().unwrap().clone()
    }

    pub fn get_opcodes(&mut self) -> Vec<Opcode> {
        if self.opcodes.as_ref().is_some() {
            return self.opcodes.as_ref().unwrap().clone();
        }
        let mut opcodes = Vec::new();
        let (mut i, mut j) = (0, 0);
        for m in self.get_matching_blocks() {
            let mut tag = String::new();
            if i < m.first_start && j < m.second_start {
                tag = String::from("replace");
            } else if i < m.first_start {
                tag = String::from("delete");
            } else if j < m.second_start {
                tag = String::from("insert");
            }
            if !tag.is_empty() {
                opcodes.push(Opcode::new(tag, i, m.first_start, j, m.second_start));
            }
            i = m.first_start + m.size;
            j = m.second_start + m.size;
            if m.size != 0 {
                opcodes.push(Opcode::new(
                    String::from("equal"),
                    m.first_start,
                    i,
                    m.second_start,
                    j,
                ));
            }
        }
        self.opcodes = Some(opcodes);
        return self.opcodes.as_ref().unwrap().clone();
    }

    pub fn get_grouped_opcodes(&mut self, n: usize) -> Vec<Vec<Opcode>> {
        let mut res = Vec::new();
        let mut codes = self.get_opcodes();
        if codes.is_empty() {
            codes.push(Opcode::new("equal".to_string(), 0, 1, 0, 1));
        }

        if codes.first().unwrap().tag == "equal" {
            let opcode = codes.first_mut().unwrap();
            opcode.first_start = max(opcode.first_start, opcode.first_end.saturating_sub(n));
            opcode.second_start = max(opcode.second_start, opcode.second_end.saturating_sub(n));
        }
        if codes.last().unwrap().tag == "equal" {
            let opcode = codes.last_mut().unwrap();
            opcode.first_end = min(opcode.first_start + n, opcode.first_end);
            opcode.second_end = min(opcode.second_start + n, opcode.second_end);
        }
        let nn = n + n;
        let mut group = Vec::new();
        for code in &codes {
            let (mut first_start, mut second_start) = (code.first_start, code.second_start);
            if code.tag == "equal" && code.first_end - code.first_start > nn {
                group.push(Opcode::new(
                    code.tag.clone(),
                    code.first_start,
                    min(code.first_end, code.first_start + n),
                    code.second_start,
                    min(code.second_end, code.second_start + n),
                ));
                res.push(group.clone());
                group.clear();
                first_start = max(first_start, code.first_end.saturating_sub(n));
                second_start = max(second_start, code.second_end.saturating_sub(n));
            }
            group.push(Opcode::new(
                code.tag.clone(),
                first_start,
                code.first_end,
                second_start,
                code.second_end,
            ));
        }
        if !group.is_empty() && !(group.len() == 1 && group.first().unwrap().tag == "equal") {
            res.push(group.clone());
        }
        res
    }

    pub fn ratio(&mut self) -> f32 {
        let matches = self.get_matching_blocks()
            .iter()
            .fold(0, |res, &m| res + m.size);
        calculate_ratio(
            matches,
            self.first_sequence.len() + self.second_sequence.len(),
        )
    }
}
<commit_msg>chain_second_seq(): Filter out junk and popular elements in a more idiomatic way<commit_after>use std::cmp::{max, min};
use std::collections::HashMap;
use std::fmt::Debug;
use utils::calculate_ratio;

#[derive(Debug, Clone, Copy, PartialEq, PartialOrd, Eq, Ord)]
pub struct Match {
    pub first_start: usize,
    pub second_start: usize,
    pub size: usize,
}

impl Match {
    fn new(first_start: usize, second_start: usize, size: usize) -> Match {
        Match {
            first_start: first_start,
            second_start: second_start,
            size: size,
        }
    }
}

#[derive(Debug, Clone, PartialEq)]
pub struct Opcode {
    pub tag: String,
    pub first_start: usize,
    pub first_end: usize,
    pub second_start: usize,
    pub second_end: usize,
}

impl Opcode {
    fn new(
        tag: String,
        first_start: usize,
        first_end: usize,
        second_start: usize,
        second_end: usize,
    ) -> Opcode {
        Opcode {
            tag: tag,
            first_start: first_start,
            first_end: first_end,
            second_start: second_start,
            second_end: second_end,
        }
    }
}

pub trait Sequence: Debug {
    fn len(&self) -> usize;
    fn at_index(&self, index: usize) -> Option<&str>;
}

impl Sequence for str {
    fn len(&self) -> usize {
        self.len()
    }

    fn at_index(&self, index: usize) -> Option<&str> {
        if index > self.len() {
            return None;
        }
        unsafe { Some(self.slice_unchecked(index, index + 1)) }
    }
}

impl<'a> Sequence for Vec<&'a str> {
    fn len(&self) -> usize {
        self.len()
    }

    fn at_index(&self, index: usize) -> Option<&str> {
        if index < self.len() {
            return Some(self[index]);
        }
        None
    }
}

impl Sequence for String {
    fn len(&self) -> usize {
        self.len()
    }

    fn at_index(&self, index: usize) -> Option<&str> {
        if index > self.len() {
            return None;
        }
        unsafe { Some(self.slice_unchecked(index, index + 1)) }
    }
}

impl<'a> Sequence for Vec<String> {
    fn len(&self) -> usize {
        self.len()
    }

    fn at_index(&self, index: usize) -> Option<&str> {
        if index < self.len() {
            return Some(&self[index]);
        }
        None
    }
}

pub struct SequenceMatcher<'a, T: 'a + ?Sized + Sequence> {
    first_sequence: &'a T,
    second_sequence: &'a T,
    matching_blocks: Option<Vec<Match>>,
    opcodes: Option<Vec<Opcode>>,
    is_junk: Option<fn(&str) -> bool>,
    second_sequence_elements: HashMap<&'a str, Vec<usize>>,
}

impl<'a, T: ?Sized + Sequence> SequenceMatcher<'a, T> {
    pub fn new(first_sequence: &'a T, second_sequence: &'a T) -> SequenceMatcher<'a, T> {
        let mut matcher = SequenceMatcher {
            first_sequence: first_sequence,
            second_sequence: second_sequence,
            matching_blocks: None,
            opcodes: None,
            is_junk: None,
            second_sequence_elements: HashMap::new(),
        };
        matcher.set_seqs(first_sequence, second_sequence);
        matcher
    }

    pub fn set_is_junk(&mut self, is_junk: Option<fn(&str) -> bool>) {
        self.is_junk = is_junk;
        self.set_second_seq(self.second_sequence);
    }

    pub fn set_seqs(&mut self, first_sequence: &'a T, second_sequence: &'a T) {
        self.set_first_seq(first_sequence);
        self.set_second_seq(second_sequence);
    }

    pub fn set_first_seq(&mut self, sequence: &'a T) {
        self.first_sequence = sequence;
        self.matching_blocks = None;
        self.opcodes = None;
    }

    pub fn set_second_seq(&mut self, sequence: &'a T) {
        self.second_sequence = sequence;
        self.matching_blocks = None;
        self.opcodes = None;
        self.chain_second_seq();
    }

    fn chain_second_seq(&mut self) {
        let second_sequence = self.second_sequence;
        let mut second_sequence_elements = HashMap::new();
        for i in 0..second_sequence.len() {
            let mut counter = second_sequence_elements
                .entry(second_sequence.at_index(i).unwrap())
                .or_insert(Vec::new());
            counter.push(i);
        }
        if let Some(junk_func) = self.is_junk {
            second_sequence_elements = second_sequence_elements
                .into_iter()
                .filter(|&(element, _)| !junk_func(element))
                .collect();
        }
        // Filter out popular elements
        let len = second_sequence.len();
        if len >= 200 {
            let test_len = (len as f32 / 100.0).floor() as usize + 1;
            second_sequence_elements = second_sequence_elements
                .into_iter()
                .filter(|&(_, ref indexes)| indexes.len() > test_len)
                .collect();
        }
        self.second_sequence_elements = second_sequence_elements;
    }

    pub fn find_longest_match(
        &self,
        first_start: usize,
        first_end: usize,
        second_start: usize,
        second_end: usize,
    ) -> Match {
        let first_sequence = &self.first_sequence;
        let second_sequence = &self.second_sequence;
        let second_sequence_elements = &self.second_sequence_elements;
        let (mut best_i, mut best_j, mut best_size) = (first_start, second_start, 0);
        let mut j2len: HashMap<usize, usize> = HashMap::new();
        for i in first_start..first_end {
            let mut new_j2len: HashMap<usize, usize> = HashMap::new();
            match second_sequence_elements.get(first_sequence.at_index(i).unwrap()) {
                Some(indexes) => {
                    for j in indexes {
                        let j = j.clone();
                        if j < second_start {
                            continue;
                        };
                        if j >= second_end {
                            break;
                        };
                        let mut size = 0;
                        if j > 0 {
                            match j2len.get(&(j - 1)) {
                                Some(k) => {
                                    size = k.clone();
                                }
                                None => {}
                            }
                        }
                        size += 1;
                        new_j2len.insert(j, size);
                        if size > best_size {
                            best_i = i + 1 - size;
                            best_j = j + 1 - size;
                            best_size = size;
                        }
                    }
                }
                None => {}
            }
            j2len = new_j2len;
        }
        for _ in 0..2 {
            while best_i > first_start
                && best_j > second_start
                && first_sequence.at_index(best_i - 1) == second_sequence.at_index(best_j - 1)
            {
                best_i = best_i - 1;
                best_j = best_j - 1;
                best_size = best_size + 1;
            }
            while best_i + best_size < first_end && best_j + best_size < second_end
                && first_sequence.at_index(best_i + best_size)
                    == second_sequence.at_index(best_j + best_size)
            {
                best_size += 1;
            }
        }
        Match::new(best_i, best_j, best_size)
    }

    pub fn get_matching_blocks(&mut self) -> Vec<Match> {
        if self.matching_blocks.as_ref().is_some() {
            return self.matching_blocks.as_ref().unwrap().clone();
        }
        let (first_length, second_length) = (self.first_sequence.len(), self.second_sequence.len());
        let mut matches = Vec::new();
        let mut queue = vec![(0, first_length, 0, second_length)];
        while !queue.is_empty() {
            let (first_start, first_end, second_start, second_end) = queue.pop().unwrap();
            let m = self.find_longest_match(first_start, first_end, second_start, second_end);
            match m.size {
                0 => {}
                _ => {
                    if first_start < m.first_start && second_start < m.second_start {
                        queue.push((first_start, m.first_start, second_start, m.second_start));
                    }
                    if m.first_start + m.size < first_end && m.second_start + m.size < second_end {
                        queue.push((
                            m.first_start + m.size,
                            first_end,
                            m.second_start + m.size,
                            second_end,
                        ));
                    }
                    matches.push(m);
                }
            }
        }
        matches.sort_by(|a, b| a.cmp(b));
        let (mut first_start, mut second_start, mut size) = (0, 0, 0);
        let mut non_adjacent = Vec::new();
        for m in &matches {
            if first_start + size == m.first_start && second_start + size == m.second_start {
                size += m.size
            } else {
                if size != 0 {
                    non_adjacent.push(Match::new(first_start, second_start, size));
                }
                first_start = m.first_start;
                second_start = m.second_start;
                size = m.size;
            }
        }
        if size != 0 {
            non_adjacent.push(Match::new(first_start, second_start, size));
        }
        non_adjacent.push(Match::new(first_length, second_length, 0));
        self.matching_blocks = Some(non_adjacent);
        self.matching_blocks.as_ref().unwrap().clone()
    }

    pub fn get_opcodes(&mut self) -> Vec<Opcode> {
        if self.opcodes.as_ref().is_some() {
            return self.opcodes.as_ref().unwrap().clone();
        }
        let mut opcodes = Vec::new();
        let (mut i, mut j) = (0, 0);
        for m in self.get_matching_blocks() {
            let mut tag = String::new();
            if i < m.first_start && j < m.second_start {
                tag = String::from("replace");
            } else if i < m.first_start {
                tag = String::from("delete");
            } else if j < m.second_start {
                tag = String::from("insert");
            }
            if !tag.is_empty() {
                opcodes.push(Opcode::new(tag, i, m.first_start, j, m.second_start));
            }
            i = m.first_start + m.size;
            j = m.second_start + m.size;
            if m.size != 0 {
                opcodes.push(Opcode::new(
                    String::from("equal"),
                    m.first_start,
                    i,
                    m.second_start,
                    j,
                ));
            }
        }
        self.opcodes = Some(opcodes);
        return self.opcodes.as_ref().unwrap().clone();
    }

    pub fn get_grouped_opcodes(&mut self, n: usize) -> Vec<Vec<Opcode>> {
        let mut res = Vec::new();
        let mut codes = self.get_opcodes();
        if codes.is_empty() {
            codes.push(Opcode::new("equal".to_string(), 0, 1, 0, 1));
        }

        if codes.first().unwrap().tag == "equal" {
            let opcode = codes.first_mut().unwrap();
            opcode.first_start = max(opcode.first_start, opcode.first_end.saturating_sub(n));
            opcode.second_start = max(opcode.second_start, opcode.second_end.saturating_sub(n));
        }
        if codes.last().unwrap().tag == "equal" {
            let opcode = codes.last_mut().unwrap();
            opcode.first_end = min(opcode.first_start + n, opcode.first_end);
            opcode.second_end = min(opcode.second_start + n, opcode.second_end);
        }
        let nn = n + n;
        let mut group = Vec::new();
        for code in &codes {
            let (mut first_start, mut second_start) = (code.first_start, code.second_start);
            if code.tag == "equal" && code.first_end - code.first_start > nn {
                group.push(Opcode::new(
                    code.tag.clone(),
                    code.first_start,
                    min(code.first_end, code.first_start + n),
                    code.second_start,
                    min(code.second_end, code.second_start + n),
                ));
                res.push(group.clone());
                group.clear();
                first_start = max(first_start, code.first_end.saturating_sub(n));
                second_start = max(second_start, code.second_end.saturating_sub(n));
            }
            group.push(Opcode::new(
                code.tag.clone(),
                first_start,
                code.first_end,
                second_start,
                code.second_end,
            ));
        }
        if !group.is_empty() && !(group.len() == 1 && group.first().unwrap().tag == "equal") {
            res.push(group.clone());
        }
        res
    }

    pub fn ratio(&mut self) -> f32 {
        let matches = self.get_matching_blocks()
            .iter()
            .fold(0, |res, &m| res + m.size);
        calculate_ratio(
            matches,
            self.first_sequence.len() + self.second_sequence.len(),
        )
    }
}
<|endoftext|>


<commit_before>use simd::f32x4;
use simd::x86::sse3::Sse3F32x4;
use num::complex::Complex32;

pub trait SimdExtensions
{
	type Real;
	type Complex;
	fn add_real(self, value: Self::Real) -> Self;
	fn add_complex(self, value: Self::Complex) -> Self;
	fn scale_real(self, value: Self::Real) -> Self;
	fn scale_complex(self, value: Self::Complex) -> Self;
	fn complex_abs_squared(self) -> Self;
	fn complex_abs(self) -> Self;
	fn store_half(self, target: &mut [Self::Real], index: usize);
	fn mul_complex(self, value: Self) -> Self;
	fn div_complex(self, value: Self) -> Self;
}

impl SimdExtensions for f32x4
{
	type Real = f32;
	type Complex = Complex32;

	fn add_real(self, value: f32) -> f32x4
	{
		let increment = f32x4::splat(value);
		self + increment
	}

	fn add_complex(self, value: Complex32) -> f32x4
	{
		let increment = f32x4::new(value.re, value.im, value.re, value.im);
		self + increment
	}

	fn scale_real(self, value: f32) -> f32x4
	{
		let scale_vector = f32x4::splat(value);
		self * scale_vector
	}

	fn scale_complex(self, value: Complex32) -> f32x4
	{
		let scaling_real = f32x4::splat(value.re);
		let scaling_imag = f32x4::splat(value.im);
		let parallel = scaling_real * self;
		// There should be a shufps operation which shuffles the vector self
		let shuffled = f32x4::new(self.extract(1), self.extract(0), self.extract(3), self.extract(2));
		let cross = scaling_imag * shuffled;
		parallel.addsub(cross)
	}

	fn mul_complex(self, value: f32x4) -> f32x4
	{
		let scaling_real = f32x4::new(value.extract(0), value.extract(0), value.extract(2), value.extract(2));
		let scaling_imag = f32x4::new(value.extract(1), value.extract(1), value.extract(3), value.extract(3));
		let parallel = scaling_real * self;
		// There should be a shufps operation which shuffles the vector self
		let shuffled = f32x4::new(self.extract(1), self.extract(0), self.extract(3), self.extract(2));
		let cross = scaling_imag * shuffled;
		parallel.addsub(cross)
	}

	fn div_complex(self, value: f32x4) -> f32x4
	{
		let scaling_imag = f32x4::new(self.extract(0), self.extract(0), self.extract(2), self.extract(2));
		let scaling_real = f32x4::new(self.extract(1), self.extract(1), self.extract(3), self.extract(3));
		let parallel = scaling_real * value;
		// There should be a shufps operation which shuffles the vector self
		let shuffled = f32x4::new(value.extract(1), value.extract(0), value.extract(3), value.extract(2));
		let cross = scaling_imag * shuffled;
		let mul = parallel.addsub(cross);
		let square = shuffled * shuffled;
		let square_shuffled = f32x4::new(square.extract(1), square.extract(0), square.extract(3), square.extract(2));
		let sum = square + square_shuffled;
		let div = mul / sum;
		f32x4::new(div.extract(1), div.extract(0), div.extract(3), div.extract(2))
	}

	fn complex_abs_squared(self) -> f32x4
	{
		let squared = self * self;
		squared.hadd(squared)
	}

	fn complex_abs(self) -> f32x4
	{
		let squared = self * self;
		let squared_sum = squared.hadd(squared);
		squared_sum.sqrt()
	}

	fn store_half(self, target: &mut [f32], index: usize)
	{
		let mut temp = [0.0; 4];
		self.store(&mut temp, 0);
		target[index] = temp[0];
		target[index + 1] = temp[1];
	}
} <commit_msg>Added SIMD extension for f64x2. For many of the operations in might make more sense to let the compiler do the optimization and to benchmark if the results are as expected. I guess I have a better understanding of the different instruction sets by now, so I think I've learnt that part and could now let the compiler do the work ...<commit_after>use simd::f32x4;
use simd::x86::sse3::Sse3F32x4;
use num::complex::{Complex32, Complex64};
use simd::x86::sse2::f64x2; // Using the avx f64x4 would be more attractive but isn't supported by all x86 CPUs

pub trait SimdExtensions
{
	type Real;
	type Complex;
	fn add_real(self, value: Self::Real) -> Self;
	fn add_complex(self, value: Self::Complex) -> Self;
	fn scale_real(self, value: Self::Real) -> Self;
	fn scale_complex(self, value: Self::Complex) -> Self;
	fn complex_abs_squared(self) -> Self;
	fn complex_abs(self) -> Self;
	fn store_half(self, target: &mut [Self::Real], index: usize);
	fn mul_complex(self, value: Self) -> Self;
	fn div_complex(self, value: Self) -> Self;
}

impl SimdExtensions for f32x4
{
	type Real = f32;
	type Complex = Complex32;

	fn add_real(self, value: f32) -> f32x4
	{
		let increment = f32x4::splat(value);
		self + increment
	}

	fn add_complex(self, value: Complex32) -> f32x4
	{
		let increment = f32x4::new(value.re, value.im, value.re, value.im);
		self + increment
	}

	fn scale_real(self, value: f32) -> f32x4
	{
		let scale_vector = f32x4::splat(value);
		self * scale_vector
	}

	fn scale_complex(self, value: Complex32) -> f32x4
	{
		let scaling_real = f32x4::splat(value.re);
		let scaling_imag = f32x4::splat(value.im);
		let parallel = scaling_real * self;
		// There should be a shufps operation which shuffles the vector self
		let shuffled = f32x4::new(self.extract(1), self.extract(0), self.extract(3), self.extract(2));
		let cross = scaling_imag * shuffled;
		parallel.addsub(cross)
	}

	fn mul_complex(self, value: f32x4) -> f32x4
	{
		let scaling_real = f32x4::new(value.extract(0), value.extract(0), value.extract(2), value.extract(2));
		let scaling_imag = f32x4::new(value.extract(1), value.extract(1), value.extract(3), value.extract(3));
		let parallel = scaling_real * self;
		// There should be a shufps operation which shuffles the vector self
		let shuffled = f32x4::new(self.extract(1), self.extract(0), self.extract(3), self.extract(2));
		let cross = scaling_imag * shuffled;
		parallel.addsub(cross)
	}

	fn div_complex(self, value: f32x4) -> f32x4
	{
		let scaling_imag = f32x4::new(self.extract(0), self.extract(0), self.extract(2), self.extract(2));
		let scaling_real = f32x4::new(self.extract(1), self.extract(1), self.extract(3), self.extract(3));
		let parallel = scaling_real * value;
		// There should be a shufps operation which shuffles the vector self
		let shuffled = f32x4::new(value.extract(1), value.extract(0), value.extract(3), value.extract(2));
		let cross = scaling_imag * shuffled;
		let mul = parallel.addsub(cross);
		let square = shuffled * shuffled;
		let square_shuffled = f32x4::new(square.extract(1), square.extract(0), square.extract(3), square.extract(2));
		let sum = square + square_shuffled;
		let div = mul / sum;
		f32x4::new(div.extract(1), div.extract(0), div.extract(3), div.extract(2))
	}

	fn complex_abs_squared(self) -> f32x4
	{
		let squared = self * self;
		squared.hadd(squared)
	}

	fn complex_abs(self) -> f32x4
	{
		let squared = self * self;
		let squared_sum = squared.hadd(squared);
		squared_sum.sqrt()
	}

	fn store_half(self, target: &mut [f32], index: usize)
	{
		let mut temp = [0.0; 4];
		self.store(&mut temp, 0);
		target[index] = temp[0];
		target[index + 1] = temp[1];
	}
}

impl SimdExtensions for f64x2
{
	type Real = f64;
	type Complex = Complex64;

	fn add_real(self, value: f64) -> f64x2
	{
		let increment = f64x2::splat(value);
		self + increment
	}

	fn add_complex(self, value: Complex64) -> f64x2
	{
		let increment = f64x2::new(value.re, value.im);
		self + increment
	}

	fn scale_real(self, value: f64) -> f64x2
	{
		let scale_vector = f64x2::splat(value);
		self * scale_vector
	}

	fn scale_complex(self, value: Complex64) -> f64x2
	{
		let complex = Complex64::new(self.extract(0), self.extract(1));
		let result = complex * value;
		f64x2::new(result.re, result.im)
	}

	fn mul_complex(self, value: f64x2) -> f64x2
	{
		let complex = Complex64::new(self.extract(0), self.extract(1));
		let value = Complex64::new(value.extract(0), value.extract(1));
		let result = complex * value;
		f64x2::new(result.re, result.im)
	}

	fn div_complex(self, value: f64x2) -> f64x2
	{
		let complex = Complex64::new(self.extract(0), self.extract(1));
		let value = Complex64::new(value.extract(0), value.extract(1));
		let result = complex / value;
		f64x2::new(result.re, result.im)
	}

	fn complex_abs_squared(self) -> f64x2
	{
		let a = self.extract(0);
		let b = self.extract(1);
		let result = a * a + b * b;
		f64x2::new(result, result)
	}

	fn complex_abs(self) -> f64x2
	{
		let a = self.extract(0);
		let b = self.extract(1);
		let result = (a * a + b * b).sqrt();
		f64x2::new(result, result)
	}

	fn store_half(self, target: &mut [f64], index: usize)
	{
		target[index] = self.extract(0);
	}
} <|endoftext|>


<commit_before>// Copyright (C) 2016  ParadoxSpiral
//
// This file is part of mpv-rs.
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA

use crossbeam;
use mpv::*;
use mpv::opengl_cb::*;
use parking_lot::Mutex as PMutex;
use parking_lot::Condvar;
use sdl2;
use sdl2::event::Event;
use sdl2::keyboard::Keycode;

use std::env;
use std::panic::AssertUnwindSafe;
use std::sync::{Arc, Mutex};
use std::sync::atomic::{AtomicBool, Ordering};
use std::time::{Duration, Instant};
use std::thread;

static RUNNING: AtomicBool = AtomicBool::new(true);

pub fn exec() {
    let path = env::args().nth(1).expect("Expected path to media as argument, found nil.");

    // Check for driver availability
    let driver_index = if let Some(i) = sdl2::render::drivers().position(|e| e.name == "opengl") {
        i
    } else {
        panic!("OpenGl driver not found!")
    };

    crossbeam::scope(|scope| {
        // Create SDL state
        let sdl_context = sdl2::init().unwrap();
        let video_subsystem = sdl_context.video().unwrap();
        let window = video_subsystem.window("mpv-rs sdl2 example", 1290, 720)
            .resizable()
            .position_centered()
            .opengl()
            .build()
            .unwrap();
        let renderer = window.renderer()
            .index(driver_index as _)
            .build()
            .expect("Failed to create renderer with given parameters");

        // Create mpv state
        let mpv = Parent::with_options(false,
                                       &[("vo", "opengl-cb".into()),
                                         ("cache-initial", 1.into()),
                                         ("volume", 30.into()),
                                         ("ytdl", true.into())])
                .unwrap();
        let mut mpv_ogl = mpv.create_opengl_context(move |name|
                                *AssertUnwindSafe(video_subsystem.gl_get_proc_address(name)))
                             .unwrap();
        let notifier = Arc::new(Condvar::new());
        let n = notifier.clone();
        mpv_ogl.set_update_callback(AssertUnwindSafe(n), gl_update_callback);

        // Setup input event polling at 20hz
        let n = notifier.clone();
        scope.spawn(move || {
            let mut event_pump = sdl_context.event_pump().unwrap();
            let sync = Duration::from_millis(1000 / 20);
            'main: loop {
                let initial = Instant::now();
                for event in event_pump.poll_iter() {
                    match event {
                        Event::Quit { .. } |
                        Event::KeyDown { keycode: Some(Keycode::Escape), .. } => {
                            RUNNING.store(false, Ordering::Release);
                            n.notify_one();
                            break 'main;
                        }
                        Event::KeyDown { keycode: Some(Keycode::Space), repeat: false, .. } => {
                            if let Data::Flag(true) = mpv.get_property("pause", Format::Flag)
                                   .unwrap() {
                                mpv.unpause().unwrap();
                            } else {
                                mpv.pause().unwrap();
                            }
                        }
                        Event::KeyDown { keycode: Some(Keycode::Right), repeat: false, .. } => {
                            mpv.seek_forward(&Duration::from_secs(10)).unwrap();
                        }
                        _ => {}
                    }
                }
                let diff = Instant::now() - initial;
                if diff < sync {
                    thread::sleep(sync - diff);
                }
            }
        });

        // Setup drawing
        let notifier = notifier.clone();
        scope.spawn(move || {
            let wref = renderer.window().unwrap();
            let mut guard = PMutex::new(false);
            loop {
                if RUNNING.load(Ordering::Acquire) {
                    notifier.wait(&mut guard.lock());
                    let (width, height) = wref.size();
                    unsafe {
                        mpv_ogl.draw(0, width as _, -(height as isize)).unwrap();
                    }
                    wref.gl_swap_window();
                }
            }
        });

        // Load specified file
        mpv.playlist_load_files(&[(&path, FileState::AppendPlay, None)]).unwrap();
    });
}

fn gl_update_callback(notifier: &AssertUnwindSafe<Arc<Condvar>>) {
    notifier.notify_one();
}
<commit_msg>[example] properly set gl context to current<commit_after>// Copyright (C) 2016  ParadoxSpiral
//
// This file is part of mpv-rs.
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA

use crossbeam;
use mpv::*;
use mpv::opengl_cb::*;
use parking_lot::Condvar;
use sdl2;
use sdl2::event::Event;
use sdl2::keyboard::Keycode;

use std::env;
use std::panic::AssertUnwindSafe;
use std::sync::{Arc, Mutex};
use std::sync::atomic::{AtomicBool, Ordering};
use std::time::{Duration, Instant};
use std::thread;

static RUNNING: AtomicBool = AtomicBool::new(true);

pub fn exec() {
    let path = env::args().nth(1).expect("Expected path to media as argument, found nil.");

    // Check for driver availability
    let driver_index = if let Some(i) = sdl2::render::drivers().position(|e| e.name == "opengl") {
        i
    } else {
        panic!("OpenGl driver not found!")
    };

    crossbeam::scope(|scope| {
        // Create SDL state
        let sdl_context = sdl2::init().unwrap();
        let video_subsystem = sdl_context.video().unwrap();
        let window = video_subsystem.window("mpv-rs sdl2 example", 1280, 720)
            .resizable()
            .position_centered()
            .opengl()
            .build()
            .unwrap();
        let renderer = window.renderer()
            .index(driver_index as _)
            .build()
            .expect("Failed to create renderer with given parameters");

        // Create mpv state
        let mpv = Parent::with_options(false,
                                       &[("vo", "opengl-cb".into()),
                                         ("cache-initial", 1.into()),
                                         ("volume", 30.into()),
                                         ("ytdl", true.into())])
                .unwrap();
        let mut mpv_ogl = mpv.create_opengl_context(|name| {
            (*AssertUnwindSafe(|name| -> *const () {
                video_subsystem.gl_get_proc_address(name)
            }))(name)
        })
                             .unwrap();
        let notifier = Condvar::new();
        mpv_ogl.set_update_callback(AssertUnwindSafe(&notifier), gl_update_callback);

        // Setup input event polling at 20hz
        scope.spawn(move || {
            let mut event_pump = sdl_context.event_pump().unwrap();
            let sync = Duration::from_millis(1000 / 20);
            'main: loop {
                let initial = Instant::now();
                for event in event_pump.poll_iter() {
                    match event {
                        Event::Quit { .. } |
                        Event::KeyDown { keycode: Some(Keycode::Escape), .. } => {
                            RUNNING.store(false, Ordering::Release);
                            notifier.notify_one();
                            break 'main;
                        }
                        Event::KeyDown { keycode: Some(Keycode::Space), repeat: false, .. } => {
                            if let Data::Flag(true) = mpv.get_property("pause", Format::Flag)
                                   .unwrap() {
                                mpv.unpause().unwrap();
                            } else {
                                mpv.pause().unwrap();
                            }
                        }
                        Event::KeyDown { keycode: Some(Keycode::Right), repeat: false, .. } => {
                            mpv.seek_forward(&Duration::from_secs(10)).unwrap();
                        }
                        _ => {}
                    }
                }
                let diff = Instant::now() - initial;
                if diff < sync {
                    thread::sleep(sync - diff);
                }
            }
        });

        // Setup drawing
        scope.spawn(move || {
            use parking_lot::Mutex;

            let wref = renderer.window().unwrap();
            wref.gl_set_context_to_current().unwrap();
            let mut guard = Mutex::new(false);
            loop {
                if RUNNING.load(Ordering::Acquire) {
                    notifier.wait(&mut guard.lock());
                    let (width, height) = wref.size();
                    unsafe {
                        mpv_ogl.draw(0, width as _, -(height as isize)).unwrap();
                    }
                    wref.gl_swap_window();
                }
            }
        });

        // Load specified file
        mpv.playlist_load_files(&[(&path, FileState::AppendPlay, None)]).unwrap();
    });
}

fn gl_update_callback(notifier: &AssertUnwindSafe<&Condvar>) {
    notifier.notify_one();
}
<|endoftext|>


<commit_before>#![allow(redundant_closure)] // FIXME (#116)
use rustc::lint::*;
use syntax::ast::*;
use syntax::ast_util as ast_util;
use syntax::ptr::P;
use syntax::codemap as code;
use utils::span_lint;

declare_lint! {
    pub EQ_OP,
    Warn,
    "equal operands on both sides of a comparison or bitwise combination (e.g. `x == x`)"
}

#[derive(Copy,Clone)]
pub struct EqOp;

impl LintPass for EqOp {
    fn get_lints(&self) -> LintArray {
        lint_array!(EQ_OP)
    }

    fn check_expr(&mut self, cx: &Context, e: &Expr) {
        if let ExprBinary(ref op, ref left, ref right) = e.node {
            if is_cmp_or_bit(op) && is_exp_equal(left, right) {
                span_lint(cx, EQ_OP, e.span, &format!(
                    "equal expressions as operands to {}",
                        ast_util::binop_to_string(op.node)));
            }
        }
    }
}

pub fn is_exp_equal(left : &Expr, right : &Expr) -> bool {
    match (&left.node, &right.node) {
        (&ExprBinary(ref lop, ref ll, ref lr),
                &ExprBinary(ref rop, ref rl, ref rr)) =>
            lop.node == rop.node &&
            is_exp_equal(ll, rl) && is_exp_equal(lr, rr),
        (&ExprBox(ref lpl, ref lbox), &ExprBox(ref rpl, ref rbox)) =>
            both(lpl, rpl, |l, r| is_exp_equal(l, r)) &&
                is_exp_equal(lbox, rbox),
        (&ExprCall(ref lcallee, ref largs),
         &ExprCall(ref rcallee, ref rargs)) => is_exp_equal(lcallee,
            rcallee) && is_exps_equal(largs, rargs),
        (&ExprCast(ref lc, ref lty), &ExprCast(ref rc, ref rty)) =>
            is_ty_equal(lty, rty) && is_exp_equal(lc, rc),
        (&ExprField(ref lfexp, ref lfident),
                &ExprField(ref rfexp, ref rfident)) =>
            lfident.node == rfident.node && is_exp_equal(lfexp, rfexp),
        (&ExprLit(ref l), &ExprLit(ref r)) => l.node == r.node,
        (&ExprMethodCall(ref lident, ref lcty, ref lmargs),
                &ExprMethodCall(ref rident, ref rcty, ref rmargs)) =>
            lident.node == rident.node && is_tys_equal(lcty, rcty) &&
                is_exps_equal(lmargs, rmargs),
        (&ExprParen(ref lparen), _) => is_exp_equal(lparen, right),
        (_, &ExprParen(ref rparen)) => is_exp_equal(left, rparen),
        (&ExprPath(ref lqself, ref lsubpath),
                &ExprPath(ref rqself, ref rsubpath)) =>
            both(lqself, rqself, |l, r| is_qself_equal(l, r)) &&
                is_path_equal(lsubpath, rsubpath),
        (&ExprTup(ref ltup), &ExprTup(ref rtup)) =>
            is_exps_equal(ltup, rtup),
        (&ExprUnary(lunop, ref l), &ExprUnary(runop, ref r)) =>
            lunop == runop && is_exp_equal(l, r),
        (&ExprVec(ref l), &ExprVec(ref r)) => is_exps_equal(l, r),
        _ => false
    }
}

fn is_exps_equal(left : &[P<Expr>], right : &[P<Expr>]) -> bool {
    over(left, right, |l, r| is_exp_equal(l, r))
}

fn is_path_equal(left : &Path, right : &Path) -> bool {
    // The == of idents doesn't work with different contexts,
    // we have to be explicit about hygiene
    left.global == right.global && over(&left.segments, &right.segments,
        |l, r| l.identifier.name == r.identifier.name
              && l.identifier.ctxt == r.identifier.ctxt
               && l.parameters == r.parameters)
}

fn is_qself_equal(left : &QSelf, right : &QSelf) -> bool {
    left.ty.node == right.ty.node && left.position == right.position
}

fn is_ty_equal(left : &Ty, right : &Ty) -> bool {
    match (&left.node, &right.node) {
    (&TyVec(ref lvec), &TyVec(ref rvec)) => is_ty_equal(lvec, rvec),
    (&TyFixedLengthVec(ref lfvty, ref lfvexp),
            &TyFixedLengthVec(ref rfvty, ref rfvexp)) =>
        is_ty_equal(lfvty, rfvty) && is_exp_equal(lfvexp, rfvexp),
    (&TyPtr(ref lmut), &TyPtr(ref rmut)) => is_mut_ty_equal(lmut, rmut),
    (&TyRptr(ref ltime, ref lrmut), &TyRptr(ref rtime, ref rrmut)) =>
        both(ltime, rtime, is_lifetime_equal) &&
        is_mut_ty_equal(lrmut, rrmut),
    (&TyBareFn(ref lbare), &TyBareFn(ref rbare)) =>
        is_bare_fn_ty_equal(lbare, rbare),
    (&TyTup(ref ltup), &TyTup(ref rtup)) => is_tys_equal(ltup, rtup),
    (&TyPath(ref lq, ref lpath), &TyPath(ref rq, ref rpath)) =>
        both(lq, rq, is_qself_equal) && is_path_equal(lpath, rpath),
    (&TyObjectSum(ref lsumty, ref lobounds),
            &TyObjectSum(ref rsumty, ref robounds)) =>
        is_ty_equal(lsumty, rsumty) &&
        is_param_bounds_equal(lobounds, robounds),
    (&TyPolyTraitRef(ref ltbounds), &TyPolyTraitRef(ref rtbounds)) =>
        is_param_bounds_equal(ltbounds, rtbounds),
    (&TyParen(ref lty), &TyParen(ref rty)) => is_ty_equal(lty, rty),
    (&TyTypeof(ref lof), &TyTypeof(ref rof)) => is_exp_equal(lof, rof),
    (&TyInfer, &TyInfer) => true,
    _ => false
    }
}

fn is_param_bound_equal(left : &TyParamBound, right : &TyParamBound)
        -> bool {
    match(left, right) {
    (&TraitTyParamBound(ref lpoly, ref lmod),
            &TraitTyParamBound(ref rpoly, ref rmod)) =>
        lmod == rmod && is_poly_traitref_equal(lpoly, rpoly),
    (&RegionTyParamBound(ref ltime), &RegionTyParamBound(ref rtime)) =>
        is_lifetime_equal(ltime, rtime),
    _ => false
    }
}

fn is_poly_traitref_equal(left : &PolyTraitRef, right : &PolyTraitRef)
        -> bool {
    is_lifetimedefs_equal(&left.bound_lifetimes, &right.bound_lifetimes)
        && is_path_equal(&left.trait_ref.path, &right.trait_ref.path)
}

fn is_param_bounds_equal(left : &TyParamBounds, right : &TyParamBounds)
        -> bool {
    over(left, right, is_param_bound_equal)
}

fn is_mut_ty_equal(left : &MutTy, right : &MutTy) -> bool {
    left.mutbl == right.mutbl && is_ty_equal(&left.ty, &right.ty)
}

fn is_bare_fn_ty_equal(left : &BareFnTy, right : &BareFnTy) -> bool {
    left.unsafety == right.unsafety && left.abi == right.abi &&
        is_lifetimedefs_equal(&left.lifetimes, &right.lifetimes) &&
            is_fndecl_equal(&left.decl, &right.decl)
}

fn is_fndecl_equal(left : &P<FnDecl>, right : &P<FnDecl>) -> bool {
    left.variadic == right.variadic &&
        is_args_equal(&left.inputs, &right.inputs) &&
        is_fnret_ty_equal(&left.output, &right.output)
}

fn is_fnret_ty_equal(left : &FunctionRetTy, right : &FunctionRetTy)
        -> bool {
    match (left, right) {
    (&NoReturn(_), &NoReturn(_)) |
    (&DefaultReturn(_), &DefaultReturn(_)) => true,
    (&Return(ref lty), &Return(ref rty)) => is_ty_equal(lty, rty),
    _ => false
    }
}

fn is_arg_equal(l: &Arg, r : &Arg) -> bool {
    is_ty_equal(&l.ty, &r.ty) && is_pat_equal(&l.pat, &r.pat)
}

fn is_args_equal(left : &[Arg], right : &[Arg]) -> bool {
    over(left, right, is_arg_equal)
}

fn is_pat_equal(left : &Pat, right : &Pat) -> bool {
    match(&left.node, &right.node) {
    (&PatWild(lwild), &PatWild(rwild)) => lwild == rwild,
    (&PatIdent(ref lmode, ref lident, Option::None),
            &PatIdent(ref rmode, ref rident, Option::None)) =>
        lmode == rmode && is_ident_equal(&lident.node, &rident.node),
    (&PatIdent(ref lmode, ref lident, Option::Some(ref lpat)),
            &PatIdent(ref rmode, ref rident, Option::Some(ref rpat))) =>
        lmode == rmode && is_ident_equal(&lident.node, &rident.node) &&
            is_pat_equal(lpat, rpat),
    (&PatEnum(ref lpath, ref lenum), &PatEnum(ref rpath, ref renum)) =>
        is_path_equal(lpath, rpath) && both(lenum, renum, |l, r|
            is_pats_equal(l, r)),
    (&PatStruct(ref lpath, ref lfieldpat, lbool),
            &PatStruct(ref rpath, ref rfieldpat, rbool)) =>
        lbool == rbool && is_path_equal(lpath, rpath) &&
            is_spanned_fieldpats_equal(lfieldpat, rfieldpat),
    (&PatTup(ref ltup), &PatTup(ref rtup)) => is_pats_equal(ltup, rtup),
    (&PatBox(ref lboxed), &PatBox(ref rboxed)) =>
        is_pat_equal(lboxed, rboxed),
    (&PatRegion(ref lpat, ref lmut), &PatRegion(ref rpat, ref rmut)) =>
        is_pat_equal(lpat, rpat) && lmut == rmut,
    (&PatLit(ref llit), &PatLit(ref rlit)) => is_exp_equal(llit, rlit),
    (&PatRange(ref lfrom, ref lto), &PatRange(ref rfrom, ref rto)) =>
        is_exp_equal(lfrom, rfrom) && is_exp_equal(lto, rto),
    (&PatVec(ref lfirst, Option::None, ref llast),
            &PatVec(ref rfirst, Option::None, ref rlast)) =>
        is_pats_equal(lfirst, rfirst) && is_pats_equal(llast, rlast),
    (&PatVec(ref lfirst, Option::Some(ref lpat), ref llast),
            &PatVec(ref rfirst, Option::Some(ref rpat), ref rlast)) =>
        is_pats_equal(lfirst, rfirst) && is_pat_equal(lpat, rpat) &&
            is_pats_equal(llast, rlast),
    // I don't match macros for now, the code is slow enough as is ;-)
    _ => false
    }
}

fn is_spanned_fieldpats_equal(left : &[code::Spanned<FieldPat>],
        right : &[code::Spanned<FieldPat>]) -> bool {
    over(left, right, |l, r| is_fieldpat_equal(&l.node, &r.node))
}

fn is_fieldpat_equal(left : &FieldPat, right : &FieldPat) -> bool {
    left.is_shorthand == right.is_shorthand &&
        is_ident_equal(&left.ident, &right.ident) &&
        is_pat_equal(&left.pat, &right.pat)
}

fn is_ident_equal(left : &Ident, right : &Ident) -> bool {
    &left.name == &right.name && left.ctxt == right.ctxt
}

fn is_pats_equal(left : &[P<Pat>], right : &[P<Pat>]) -> bool {
    over(left, right, |l, r| is_pat_equal(l, r))
}

fn is_lifetimedef_equal(left : &LifetimeDef, right : &LifetimeDef)
        -> bool {
    is_lifetime_equal(&left.lifetime, &right.lifetime) &&
        over(&left.bounds, &right.bounds, is_lifetime_equal)
}

fn is_lifetimedefs_equal(left : &[LifetimeDef], right : &[LifetimeDef])
        -> bool {
    over(left, right, is_lifetimedef_equal)
}

fn is_lifetime_equal(left : &Lifetime, right : &Lifetime) -> bool {
    left.name == right.name
}

fn is_tys_equal(left : &[P<Ty>], right : &[P<Ty>]) -> bool {
    over(left, right, |l, r| is_ty_equal(l, r))
}

fn over<X, F>(left: &[X], right: &[X], mut eq_fn: F) -> bool
        where F: FnMut(&X, &X) -> bool {
    left.len() == right.len() && left.iter().zip(right).all(|(x, y)|
        eq_fn(x, y))
}

fn both<X, F>(l: &Option<X>, r: &Option<X>, mut eq_fn : F) -> bool
        where F: FnMut(&X, &X) -> bool {
    l.as_ref().map_or_else(|| r.is_none(), |x| r.as_ref().map_or(false,
        |y| eq_fn(x, y)))
}

fn is_cmp_or_bit(op : &BinOp) -> bool {
    match op.node {
        BiEq | BiLt | BiLe | BiGt | BiGe | BiNe | BiAnd | BiOr |
        BiBitXor | BiBitAnd | BiBitOr => true,
        _ => false
    }
}
<commit_msg>Removed #![allow(redundant_closure)] on eq_op<commit_after>use rustc::lint::*;
use syntax::ast::*;
use syntax::ast_util as ast_util;
use syntax::ptr::P;
use syntax::codemap as code;
use utils::span_lint;

declare_lint! {
    pub EQ_OP,
    Warn,
    "equal operands on both sides of a comparison or bitwise combination (e.g. `x == x`)"
}

#[derive(Copy,Clone)]
pub struct EqOp;

impl LintPass for EqOp {
    fn get_lints(&self) -> LintArray {
        lint_array!(EQ_OP)
    }

    fn check_expr(&mut self, cx: &Context, e: &Expr) {
        if let ExprBinary(ref op, ref left, ref right) = e.node {
            if is_cmp_or_bit(op) && is_exp_equal(left, right) {
                span_lint(cx, EQ_OP, e.span, &format!(
                    "equal expressions as operands to {}",
                        ast_util::binop_to_string(op.node)));
            }
        }
    }
}

pub fn is_exp_equal(left : &Expr, right : &Expr) -> bool {
    match (&left.node, &right.node) {
        (&ExprBinary(ref lop, ref ll, ref lr),
                &ExprBinary(ref rop, ref rl, ref rr)) =>
            lop.node == rop.node &&
            is_exp_equal(ll, rl) && is_exp_equal(lr, rr),
        (&ExprBox(ref lpl, ref lbox), &ExprBox(ref rpl, ref rbox)) =>
            both(lpl, rpl, |l, r| is_exp_equal(l, r)) &&
                is_exp_equal(lbox, rbox),
        (&ExprCall(ref lcallee, ref largs),
         &ExprCall(ref rcallee, ref rargs)) => is_exp_equal(lcallee,
            rcallee) && is_exps_equal(largs, rargs),
        (&ExprCast(ref lc, ref lty), &ExprCast(ref rc, ref rty)) =>
            is_ty_equal(lty, rty) && is_exp_equal(lc, rc),
        (&ExprField(ref lfexp, ref lfident),
                &ExprField(ref rfexp, ref rfident)) =>
            lfident.node == rfident.node && is_exp_equal(lfexp, rfexp),
        (&ExprLit(ref l), &ExprLit(ref r)) => l.node == r.node,
        (&ExprMethodCall(ref lident, ref lcty, ref lmargs),
                &ExprMethodCall(ref rident, ref rcty, ref rmargs)) =>
            lident.node == rident.node && is_tys_equal(lcty, rcty) &&
                is_exps_equal(lmargs, rmargs),
        (&ExprParen(ref lparen), _) => is_exp_equal(lparen, right),
        (_, &ExprParen(ref rparen)) => is_exp_equal(left, rparen),
        (&ExprPath(ref lqself, ref lsubpath),
                &ExprPath(ref rqself, ref rsubpath)) =>
            both(lqself, rqself, |l, r| is_qself_equal(l, r)) &&
                is_path_equal(lsubpath, rsubpath),
        (&ExprTup(ref ltup), &ExprTup(ref rtup)) =>
            is_exps_equal(ltup, rtup),
        (&ExprUnary(lunop, ref l), &ExprUnary(runop, ref r)) =>
            lunop == runop && is_exp_equal(l, r),
        (&ExprVec(ref l), &ExprVec(ref r)) => is_exps_equal(l, r),
        _ => false
    }
}

fn is_exps_equal(left : &[P<Expr>], right : &[P<Expr>]) -> bool {
    over(left, right, |l, r| is_exp_equal(l, r))
}

fn is_path_equal(left : &Path, right : &Path) -> bool {
    // The == of idents doesn't work with different contexts,
    // we have to be explicit about hygiene
    left.global == right.global && over(&left.segments, &right.segments,
        |l, r| l.identifier.name == r.identifier.name
              && l.identifier.ctxt == r.identifier.ctxt
               && l.parameters == r.parameters)
}

fn is_qself_equal(left : &QSelf, right : &QSelf) -> bool {
    left.ty.node == right.ty.node && left.position == right.position
}

fn is_ty_equal(left : &Ty, right : &Ty) -> bool {
    match (&left.node, &right.node) {
    (&TyVec(ref lvec), &TyVec(ref rvec)) => is_ty_equal(lvec, rvec),
    (&TyFixedLengthVec(ref lfvty, ref lfvexp),
            &TyFixedLengthVec(ref rfvty, ref rfvexp)) =>
        is_ty_equal(lfvty, rfvty) && is_exp_equal(lfvexp, rfvexp),
    (&TyPtr(ref lmut), &TyPtr(ref rmut)) => is_mut_ty_equal(lmut, rmut),
    (&TyRptr(ref ltime, ref lrmut), &TyRptr(ref rtime, ref rrmut)) =>
        both(ltime, rtime, is_lifetime_equal) &&
        is_mut_ty_equal(lrmut, rrmut),
    (&TyBareFn(ref lbare), &TyBareFn(ref rbare)) =>
        is_bare_fn_ty_equal(lbare, rbare),
    (&TyTup(ref ltup), &TyTup(ref rtup)) => is_tys_equal(ltup, rtup),
    (&TyPath(ref lq, ref lpath), &TyPath(ref rq, ref rpath)) =>
        both(lq, rq, is_qself_equal) && is_path_equal(lpath, rpath),
    (&TyObjectSum(ref lsumty, ref lobounds),
            &TyObjectSum(ref rsumty, ref robounds)) =>
        is_ty_equal(lsumty, rsumty) &&
        is_param_bounds_equal(lobounds, robounds),
    (&TyPolyTraitRef(ref ltbounds), &TyPolyTraitRef(ref rtbounds)) =>
        is_param_bounds_equal(ltbounds, rtbounds),
    (&TyParen(ref lty), &TyParen(ref rty)) => is_ty_equal(lty, rty),
    (&TyTypeof(ref lof), &TyTypeof(ref rof)) => is_exp_equal(lof, rof),
    (&TyInfer, &TyInfer) => true,
    _ => false
    }
}

fn is_param_bound_equal(left : &TyParamBound, right : &TyParamBound)
        -> bool {
    match(left, right) {
    (&TraitTyParamBound(ref lpoly, ref lmod),
            &TraitTyParamBound(ref rpoly, ref rmod)) =>
        lmod == rmod && is_poly_traitref_equal(lpoly, rpoly),
    (&RegionTyParamBound(ref ltime), &RegionTyParamBound(ref rtime)) =>
        is_lifetime_equal(ltime, rtime),
    _ => false
    }
}

fn is_poly_traitref_equal(left : &PolyTraitRef, right : &PolyTraitRef)
        -> bool {
    is_lifetimedefs_equal(&left.bound_lifetimes, &right.bound_lifetimes)
        && is_path_equal(&left.trait_ref.path, &right.trait_ref.path)
}

fn is_param_bounds_equal(left : &TyParamBounds, right : &TyParamBounds)
        -> bool {
    over(left, right, is_param_bound_equal)
}

fn is_mut_ty_equal(left : &MutTy, right : &MutTy) -> bool {
    left.mutbl == right.mutbl && is_ty_equal(&left.ty, &right.ty)
}

fn is_bare_fn_ty_equal(left : &BareFnTy, right : &BareFnTy) -> bool {
    left.unsafety == right.unsafety && left.abi == right.abi &&
        is_lifetimedefs_equal(&left.lifetimes, &right.lifetimes) &&
            is_fndecl_equal(&left.decl, &right.decl)
}

fn is_fndecl_equal(left : &P<FnDecl>, right : &P<FnDecl>) -> bool {
    left.variadic == right.variadic &&
        is_args_equal(&left.inputs, &right.inputs) &&
        is_fnret_ty_equal(&left.output, &right.output)
}

fn is_fnret_ty_equal(left : &FunctionRetTy, right : &FunctionRetTy)
        -> bool {
    match (left, right) {
    (&NoReturn(_), &NoReturn(_)) |
    (&DefaultReturn(_), &DefaultReturn(_)) => true,
    (&Return(ref lty), &Return(ref rty)) => is_ty_equal(lty, rty),
    _ => false
    }
}

fn is_arg_equal(l: &Arg, r : &Arg) -> bool {
    is_ty_equal(&l.ty, &r.ty) && is_pat_equal(&l.pat, &r.pat)
}

fn is_args_equal(left : &[Arg], right : &[Arg]) -> bool {
    over(left, right, is_arg_equal)
}

fn is_pat_equal(left : &Pat, right : &Pat) -> bool {
    match(&left.node, &right.node) {
    (&PatWild(lwild), &PatWild(rwild)) => lwild == rwild,
    (&PatIdent(ref lmode, ref lident, Option::None),
            &PatIdent(ref rmode, ref rident, Option::None)) =>
        lmode == rmode && is_ident_equal(&lident.node, &rident.node),
    (&PatIdent(ref lmode, ref lident, Option::Some(ref lpat)),
            &PatIdent(ref rmode, ref rident, Option::Some(ref rpat))) =>
        lmode == rmode && is_ident_equal(&lident.node, &rident.node) &&
            is_pat_equal(lpat, rpat),
    (&PatEnum(ref lpath, ref lenum), &PatEnum(ref rpath, ref renum)) =>
        is_path_equal(lpath, rpath) && both(lenum, renum, |l, r|
            is_pats_equal(l, r)),
    (&PatStruct(ref lpath, ref lfieldpat, lbool),
            &PatStruct(ref rpath, ref rfieldpat, rbool)) =>
        lbool == rbool && is_path_equal(lpath, rpath) &&
            is_spanned_fieldpats_equal(lfieldpat, rfieldpat),
    (&PatTup(ref ltup), &PatTup(ref rtup)) => is_pats_equal(ltup, rtup),
    (&PatBox(ref lboxed), &PatBox(ref rboxed)) =>
        is_pat_equal(lboxed, rboxed),
    (&PatRegion(ref lpat, ref lmut), &PatRegion(ref rpat, ref rmut)) =>
        is_pat_equal(lpat, rpat) && lmut == rmut,
    (&PatLit(ref llit), &PatLit(ref rlit)) => is_exp_equal(llit, rlit),
    (&PatRange(ref lfrom, ref lto), &PatRange(ref rfrom, ref rto)) =>
        is_exp_equal(lfrom, rfrom) && is_exp_equal(lto, rto),
    (&PatVec(ref lfirst, Option::None, ref llast),
            &PatVec(ref rfirst, Option::None, ref rlast)) =>
        is_pats_equal(lfirst, rfirst) && is_pats_equal(llast, rlast),
    (&PatVec(ref lfirst, Option::Some(ref lpat), ref llast),
            &PatVec(ref rfirst, Option::Some(ref rpat), ref rlast)) =>
        is_pats_equal(lfirst, rfirst) && is_pat_equal(lpat, rpat) &&
            is_pats_equal(llast, rlast),
    // I don't match macros for now, the code is slow enough as is ;-)
    _ => false
    }
}

fn is_spanned_fieldpats_equal(left : &[code::Spanned<FieldPat>],
        right : &[code::Spanned<FieldPat>]) -> bool {
    over(left, right, |l, r| is_fieldpat_equal(&l.node, &r.node))
}

fn is_fieldpat_equal(left : &FieldPat, right : &FieldPat) -> bool {
    left.is_shorthand == right.is_shorthand &&
        is_ident_equal(&left.ident, &right.ident) &&
        is_pat_equal(&left.pat, &right.pat)
}

fn is_ident_equal(left : &Ident, right : &Ident) -> bool {
    &left.name == &right.name && left.ctxt == right.ctxt
}

fn is_pats_equal(left : &[P<Pat>], right : &[P<Pat>]) -> bool {
    over(left, right, |l, r| is_pat_equal(l, r))
}

fn is_lifetimedef_equal(left : &LifetimeDef, right : &LifetimeDef)
        -> bool {
    is_lifetime_equal(&left.lifetime, &right.lifetime) &&
        over(&left.bounds, &right.bounds, is_lifetime_equal)
}

fn is_lifetimedefs_equal(left : &[LifetimeDef], right : &[LifetimeDef])
        -> bool {
    over(left, right, is_lifetimedef_equal)
}

fn is_lifetime_equal(left : &Lifetime, right : &Lifetime) -> bool {
    left.name == right.name
}

fn is_tys_equal(left : &[P<Ty>], right : &[P<Ty>]) -> bool {
    over(left, right, |l, r| is_ty_equal(l, r))
}

fn over<X, F>(left: &[X], right: &[X], mut eq_fn: F) -> bool
        where F: FnMut(&X, &X) -> bool {
    left.len() == right.len() && left.iter().zip(right).all(|(x, y)|
        eq_fn(x, y))
}

fn both<X, F>(l: &Option<X>, r: &Option<X>, mut eq_fn : F) -> bool
        where F: FnMut(&X, &X) -> bool {
    l.as_ref().map_or_else(|| r.is_none(), |x| r.as_ref().map_or(false,
        |y| eq_fn(x, y)))
}

fn is_cmp_or_bit(op : &BinOp) -> bool {
    match op.node {
        BiEq | BiLt | BiLe | BiGt | BiGe | BiNe | BiAnd | BiOr |
        BiBitXor | BiBitAnd | BiBitOr => true,
        _ => false
    }
}
<|endoftext|>


<commit_before>use core::fmt::{self, Display};
use core::result;
use core::ops::Range;

#[cfg(feature = "std")]
use std::io;
#[cfg(feature = "std")]
use std::error;

#[derive(Debug)]
/// A custom Scroll error
pub enum Error<T = usize> {
    /// The type you tried to read was too big
    TooBig { size: T, len: T },
    /// The requested offset to read/write at is invalid
    BadOffset(T),
    /// The requested range to read/write at is invalid for the size of the provided object
    BadRange { range: Range<usize>, size: usize },
    /// The data at the given range is invalid
    BadInput { range: Range<usize>, size: usize, msg: &'static str },
    #[cfg(feature = "std")]
    /// A custom Scroll error for reporting messages to clients
    Custom(String),
    #[cfg(feature = "std")]
    /// Returned when IO based errors are encountered
    IO(io::Error),
}

#[cfg(feature = "std")]
impl error::Error for Error {
    fn description(&self) -> &str {
        match *self {
            Error::TooBig{ .. } => { "TooBig" }
            Error::BadOffset(_) => { "BadOffset" }
            Error::BadRange{ .. } => { "BadRange" }
            Error::BadInput{ .. } => { "BadInput" }
            Error::Custom(_) => { "Custom" }
            Error::IO(_) => { "IO" }
        }
    }
    fn cause(&self) -> Option<&error::Error> {
        match *self {
            Error::TooBig{ .. } => { None }
            Error::BadOffset(_) => { None }
            Error::BadRange{ .. } => { None }
            Error::BadInput{ .. }=> { None }
            Error::Custom(_) => { None }
            Error::IO(ref io) => { io.cause() }
        }
    }
}

#[cfg(feature = "std")]
impl From<io::Error> for Error {
    fn from(err: io::Error) -> Error {
        Error::IO(err)
    }
}

impl Display for Error {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            Error::TooBig{ ref size, ref len } => { write! (fmt, "type is too big ({}) for {}", size, len) },
            Error::BadOffset(ref offset) => { write! (fmt, "bad offset {}", offset) },
            Error::BadRange{ ref range, ref size} => {
                write!(fmt, "requested range [{}..{}) from object of len {}", range.start, range.end, size)
            },
            Error::BadInput{ref range, ref size, msg} => {
                write!(fmt, "{} - range [{}..{}), len {}", msg, range.start, range.end, size)
            },
            #[cfg(feature = "std")]
            Error::Custom(ref msg) => { write! (fmt, "{}", msg) },
            #[cfg(feature = "std")]
            Error::IO(ref err) => { write!(fmt, "{}", err) },
        }
    }
}

pub type Result<T> = result::Result<T, Error>;
<commit_msg>error: remove some unused errors<commit_after>use core::fmt::{self, Display};
use core::result;

#[cfg(feature = "std")]
use std::io;
#[cfg(feature = "std")]
use std::error;

#[derive(Debug)]
/// A custom Scroll error
pub enum Error<T = usize> {
    /// The type you tried to read was too big
    TooBig { size: T, len: T },
    /// The requested offset to read/write at is invalid
    BadOffset(T),
    #[cfg(feature = "std")]
    /// A custom Scroll error for reporting messages to clients
    Custom(String),
    #[cfg(feature = "std")]
    /// Returned when IO based errors are encountered
    IO(io::Error),
}

#[cfg(feature = "std")]
impl error::Error for Error {
    fn description(&self) -> &str {
        match *self {
            Error::TooBig{ .. } => { "TooBig" }
            Error::BadOffset(_) => { "BadOffset" }
            Error::Custom(_) => { "Custom" }
            Error::IO(_) => { "IO" }
        }
    }
    fn cause(&self) -> Option<&error::Error> {
        match *self {
            Error::TooBig{ .. } => { None }
            Error::BadOffset(_) => { None }
            Error::Custom(_) => { None }
            Error::IO(ref io) => { io.cause() }
        }
    }
}

#[cfg(feature = "std")]
impl From<io::Error> for Error {
    fn from(err: io::Error) -> Error {
        Error::IO(err)
    }
}

impl Display for Error {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            Error::TooBig{ ref size, ref len } => { write! (fmt, "type is too big ({}) for {}", size, len) },
            Error::BadOffset(ref offset) => { write! (fmt, "bad offset {}", offset) },
            #[cfg(feature = "std")]
            Error::Custom(ref msg) => { write! (fmt, "{}", msg) },
            #[cfg(feature = "std")]
            Error::IO(ref err) => { write!(fmt, "{}", err) },
        }
    }
}

pub type Result<T> = result::Result<T, Error>;
<|endoftext|>


<commit_before>use crate::libyaml::{emitter, error as libyaml};
use crate::path::Path;
use serde::{de, ser};
use std::error;
use std::fmt::{self, Debug, Display};
use std::io;
use std::result;
use std::string;
use std::sync::Arc;

/// An error that happened serializing or deserializing YAML data.
pub struct Error(Box<ErrorImpl>);

/// Alias for a `Result` with the error type `serde_yaml::Error`.
pub type Result<T> = result::Result<T, Error>;

#[derive(Debug)]
pub(crate) enum ErrorImpl {
    Message(String, Option<Pos>),

    Libyaml(libyaml::Error),
    Io(io::Error),
    FromUtf8(string::FromUtf8Error),

    EndOfStream,
    MoreThanOneDocument,
    RecursionLimitExceeded(libyaml::Mark),
    UnknownAnchor(libyaml::Mark),

    Shared(Arc<ErrorImpl>),
}

#[derive(Debug)]
pub(crate) struct Pos {
    mark: libyaml::Mark,
    path: String,
}

/// The input location that an error occured.
#[derive(Debug)]
pub struct Location {
    index: usize,
    line: usize,
    column: usize,
}

impl Location {
    /// The byte index of the error
    pub fn index(&self) -> usize {
        self.index
    }

    /// The line of the error
    pub fn line(&self) -> usize {
        self.line
    }

    /// The column of the error
    pub fn column(&self) -> usize {
        self.column
    }

    // This is to keep decoupled with the yaml crate
    #[doc(hidden)]
    fn from_mark(mark: libyaml::Mark) -> Self {
        Location {
            index: mark.index() as usize,
            // `line` and `column` returned from libyaml are 0-indexed but all error messages add +1 to this value
            line: mark.line() as usize + 1,
            column: mark.column() as usize + 1,
        }
    }
}

impl Error {
    /// Returns the Location from the error if one exists.
    ///
    /// Not all types of errors have a location so this can return `None`.
    ///
    /// # Examples
    ///
    /// ```
    /// # use serde_yaml::{Value, Error};
    /// #
    /// // The `@` character as the first character makes this invalid yaml
    /// let invalid_yaml: Result<Value, Error> = serde_yaml::from_str("@invalid_yaml");
    ///
    /// let location = invalid_yaml.unwrap_err().location().unwrap();
    ///
    /// assert_eq!(location.line(), 1);
    /// assert_eq!(location.column(), 1);
    /// ```
    pub fn location(&self) -> Option<Location> {
        match self.0.as_ref() {
            ErrorImpl::Message(_, Some(pos)) => Some(Location::from_mark(pos.mark)),
            ErrorImpl::Libyaml(err) => Some(Location::from_mark(err.mark())),
            _ => None,
        }
    }
}

pub(crate) fn end_of_stream() -> Error {
    Error(Box::new(ErrorImpl::EndOfStream))
}

pub(crate) fn more_than_one_document() -> Error {
    Error(Box::new(ErrorImpl::MoreThanOneDocument))
}

pub(crate) fn io(err: io::Error) -> Error {
    Error(Box::new(ErrorImpl::Io(err)))
}

pub(crate) fn string_utf8(err: string::FromUtf8Error) -> Error {
    Error(Box::new(ErrorImpl::FromUtf8(err)))
}

pub(crate) fn recursion_limit_exceeded(mark: libyaml::Mark) -> Error {
    Error(Box::new(ErrorImpl::RecursionLimitExceeded(mark)))
}

pub(crate) fn unknown_anchor(mark: libyaml::Mark) -> Error {
    Error(Box::new(ErrorImpl::UnknownAnchor(mark)))
}

pub(crate) fn shared(shared: Arc<ErrorImpl>) -> Error {
    Error(Box::new(ErrorImpl::Shared(shared)))
}

pub(crate) fn fix_mark(mut error: Error, mark: libyaml::Mark, path: Path) -> Error {
    if let ErrorImpl::Message(_, none @ None) = error.0.as_mut() {
        *none = Some(Pos {
            mark,
            path: path.to_string(),
        });
    }
    error
}

impl Error {
    pub(crate) fn shared(self) -> Arc<ErrorImpl> {
        if let ErrorImpl::Shared(err) = *self.0 {
            err
        } else {
            Arc::from(self.0)
        }
    }
}

impl From<libyaml::Error> for Error {
    fn from(err: libyaml::Error) -> Self {
        Error(Box::new(ErrorImpl::Libyaml(err)))
    }
}

impl From<emitter::Error> for Error {
    fn from(err: emitter::Error) -> Self {
        match err {
            emitter::Error::Libyaml(err) => Self::from(err),
            emitter::Error::Io(err) => io(err),
        }
    }
}

impl error::Error for Error {
    fn source(&self) -> Option<&(dyn error::Error + 'static)> {
        self.0.source()
    }
}

impl Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        self.0.display(f)
    }
}

// Remove two layers of verbosity from the debug representation. Humans often
// end up seeing this representation because it is what unwrap() shows.
impl Debug for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        self.0.debug(f)
    }
}

impl ser::Error for Error {
    fn custom<T: Display>(msg: T) -> Self {
        Error(Box::new(ErrorImpl::Message(msg.to_string(), None)))
    }
}

impl de::Error for Error {
    fn custom<T: Display>(msg: T) -> Self {
        Error(Box::new(ErrorImpl::Message(msg.to_string(), None)))
    }
}

impl ErrorImpl {
    fn source(&self) -> Option<&(dyn error::Error + 'static)> {
        match self {
            ErrorImpl::Io(err) => Some(err),
            ErrorImpl::FromUtf8(err) => Some(err),
            ErrorImpl::Shared(err) => err.source(),
            _ => None,
        }
    }

    fn display(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self {
            ErrorImpl::Message(msg, None) => Display::fmt(msg, f),
            ErrorImpl::Message(msg, Some(Pos { mark, path })) => {
                if path == "." {
                    write!(f, "{} at {}", msg, mark)
                } else {
                    write!(f, "{}: {} at {}", path, msg, mark)
                }
            }
            ErrorImpl::Libyaml(err) => Display::fmt(err, f),
            ErrorImpl::Io(err) => Display::fmt(err, f),
            ErrorImpl::FromUtf8(err) => Display::fmt(err, f),
            ErrorImpl::EndOfStream => f.write_str("EOF while parsing a value"),
            ErrorImpl::MoreThanOneDocument => f.write_str(
                "deserializing from YAML containing more than one document is not supported",
            ),
            ErrorImpl::RecursionLimitExceeded(mark) => {
                write!(f, "recursion limit exceeded at {}", mark)
            }
            ErrorImpl::UnknownAnchor(mark) => write!(f, "unknown anchor at {}", mark),
            ErrorImpl::Shared(err) => err.display(f),
        }
    }

    fn debug(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self {
            ErrorImpl::Message(msg, pos) => f.debug_tuple("Message").field(msg).field(pos).finish(),
            ErrorImpl::Libyaml(err) => f.debug_tuple("Libyaml").field(err).finish(),
            ErrorImpl::Io(io) => f.debug_tuple("Io").field(io).finish(),
            ErrorImpl::FromUtf8(from_utf8) => f.debug_tuple("FromUtf8").field(from_utf8).finish(),
            ErrorImpl::EndOfStream => f.debug_tuple("EndOfStream").finish(),
            ErrorImpl::MoreThanOneDocument => f.debug_tuple("MoreThanOneDocument").finish(),
            ErrorImpl::RecursionLimitExceeded(mark) => {
                f.debug_tuple("RecursionLimitExceeded").field(mark).finish()
            }
            ErrorImpl::UnknownAnchor(mark) => f.debug_tuple("UnknownAnchor").field(mark).finish(),
            ErrorImpl::Shared(err) => err.debug(f),
        }
    }
}
<commit_msg>Propagate location of Shared errors<commit_after>use crate::libyaml::{emitter, error as libyaml};
use crate::path::Path;
use serde::{de, ser};
use std::error;
use std::fmt::{self, Debug, Display};
use std::io;
use std::result;
use std::string;
use std::sync::Arc;

/// An error that happened serializing or deserializing YAML data.
pub struct Error(Box<ErrorImpl>);

/// Alias for a `Result` with the error type `serde_yaml::Error`.
pub type Result<T> = result::Result<T, Error>;

#[derive(Debug)]
pub(crate) enum ErrorImpl {
    Message(String, Option<Pos>),

    Libyaml(libyaml::Error),
    Io(io::Error),
    FromUtf8(string::FromUtf8Error),

    EndOfStream,
    MoreThanOneDocument,
    RecursionLimitExceeded(libyaml::Mark),
    UnknownAnchor(libyaml::Mark),

    Shared(Arc<ErrorImpl>),
}

#[derive(Debug)]
pub(crate) struct Pos {
    mark: libyaml::Mark,
    path: String,
}

/// The input location that an error occured.
#[derive(Debug)]
pub struct Location {
    index: usize,
    line: usize,
    column: usize,
}

impl Location {
    /// The byte index of the error
    pub fn index(&self) -> usize {
        self.index
    }

    /// The line of the error
    pub fn line(&self) -> usize {
        self.line
    }

    /// The column of the error
    pub fn column(&self) -> usize {
        self.column
    }

    // This is to keep decoupled with the yaml crate
    #[doc(hidden)]
    fn from_mark(mark: libyaml::Mark) -> Self {
        Location {
            index: mark.index() as usize,
            // `line` and `column` returned from libyaml are 0-indexed but all error messages add +1 to this value
            line: mark.line() as usize + 1,
            column: mark.column() as usize + 1,
        }
    }
}

impl Error {
    /// Returns the Location from the error if one exists.
    ///
    /// Not all types of errors have a location so this can return `None`.
    ///
    /// # Examples
    ///
    /// ```
    /// # use serde_yaml::{Value, Error};
    /// #
    /// // The `@` character as the first character makes this invalid yaml
    /// let invalid_yaml: Result<Value, Error> = serde_yaml::from_str("@invalid_yaml");
    ///
    /// let location = invalid_yaml.unwrap_err().location().unwrap();
    ///
    /// assert_eq!(location.line(), 1);
    /// assert_eq!(location.column(), 1);
    /// ```
    pub fn location(&self) -> Option<Location> {
        self.0.location()
    }
}

pub(crate) fn end_of_stream() -> Error {
    Error(Box::new(ErrorImpl::EndOfStream))
}

pub(crate) fn more_than_one_document() -> Error {
    Error(Box::new(ErrorImpl::MoreThanOneDocument))
}

pub(crate) fn io(err: io::Error) -> Error {
    Error(Box::new(ErrorImpl::Io(err)))
}

pub(crate) fn string_utf8(err: string::FromUtf8Error) -> Error {
    Error(Box::new(ErrorImpl::FromUtf8(err)))
}

pub(crate) fn recursion_limit_exceeded(mark: libyaml::Mark) -> Error {
    Error(Box::new(ErrorImpl::RecursionLimitExceeded(mark)))
}

pub(crate) fn unknown_anchor(mark: libyaml::Mark) -> Error {
    Error(Box::new(ErrorImpl::UnknownAnchor(mark)))
}

pub(crate) fn shared(shared: Arc<ErrorImpl>) -> Error {
    Error(Box::new(ErrorImpl::Shared(shared)))
}

pub(crate) fn fix_mark(mut error: Error, mark: libyaml::Mark, path: Path) -> Error {
    if let ErrorImpl::Message(_, none @ None) = error.0.as_mut() {
        *none = Some(Pos {
            mark,
            path: path.to_string(),
        });
    }
    error
}

impl Error {
    pub(crate) fn shared(self) -> Arc<ErrorImpl> {
        if let ErrorImpl::Shared(err) = *self.0 {
            err
        } else {
            Arc::from(self.0)
        }
    }
}

impl From<libyaml::Error> for Error {
    fn from(err: libyaml::Error) -> Self {
        Error(Box::new(ErrorImpl::Libyaml(err)))
    }
}

impl From<emitter::Error> for Error {
    fn from(err: emitter::Error) -> Self {
        match err {
            emitter::Error::Libyaml(err) => Self::from(err),
            emitter::Error::Io(err) => io(err),
        }
    }
}

impl error::Error for Error {
    fn source(&self) -> Option<&(dyn error::Error + 'static)> {
        self.0.source()
    }
}

impl Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        self.0.display(f)
    }
}

// Remove two layers of verbosity from the debug representation. Humans often
// end up seeing this representation because it is what unwrap() shows.
impl Debug for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        self.0.debug(f)
    }
}

impl ser::Error for Error {
    fn custom<T: Display>(msg: T) -> Self {
        Error(Box::new(ErrorImpl::Message(msg.to_string(), None)))
    }
}

impl de::Error for Error {
    fn custom<T: Display>(msg: T) -> Self {
        Error(Box::new(ErrorImpl::Message(msg.to_string(), None)))
    }
}

impl ErrorImpl {
    fn location(&self) -> Option<Location> {
        match self {
            ErrorImpl::Message(_, Some(pos)) => Some(Location::from_mark(pos.mark)),
            ErrorImpl::Libyaml(err) => Some(Location::from_mark(err.mark())),
            ErrorImpl::Shared(err) => err.location(),
            _ => None,
        }
    }

    fn source(&self) -> Option<&(dyn error::Error + 'static)> {
        match self {
            ErrorImpl::Io(err) => Some(err),
            ErrorImpl::FromUtf8(err) => Some(err),
            ErrorImpl::Shared(err) => err.source(),
            _ => None,
        }
    }

    fn display(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self {
            ErrorImpl::Message(msg, None) => Display::fmt(msg, f),
            ErrorImpl::Message(msg, Some(Pos { mark, path })) => {
                if path == "." {
                    write!(f, "{} at {}", msg, mark)
                } else {
                    write!(f, "{}: {} at {}", path, msg, mark)
                }
            }
            ErrorImpl::Libyaml(err) => Display::fmt(err, f),
            ErrorImpl::Io(err) => Display::fmt(err, f),
            ErrorImpl::FromUtf8(err) => Display::fmt(err, f),
            ErrorImpl::EndOfStream => f.write_str("EOF while parsing a value"),
            ErrorImpl::MoreThanOneDocument => f.write_str(
                "deserializing from YAML containing more than one document is not supported",
            ),
            ErrorImpl::RecursionLimitExceeded(mark) => {
                write!(f, "recursion limit exceeded at {}", mark)
            }
            ErrorImpl::UnknownAnchor(mark) => write!(f, "unknown anchor at {}", mark),
            ErrorImpl::Shared(err) => err.display(f),
        }
    }

    fn debug(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self {
            ErrorImpl::Message(msg, pos) => f.debug_tuple("Message").field(msg).field(pos).finish(),
            ErrorImpl::Libyaml(err) => f.debug_tuple("Libyaml").field(err).finish(),
            ErrorImpl::Io(io) => f.debug_tuple("Io").field(io).finish(),
            ErrorImpl::FromUtf8(from_utf8) => f.debug_tuple("FromUtf8").field(from_utf8).finish(),
            ErrorImpl::EndOfStream => f.debug_tuple("EndOfStream").finish(),
            ErrorImpl::MoreThanOneDocument => f.debug_tuple("MoreThanOneDocument").finish(),
            ErrorImpl::RecursionLimitExceeded(mark) => {
                f.debug_tuple("RecursionLimitExceeded").field(mark).finish()
            }
            ErrorImpl::UnknownAnchor(mark) => f.debug_tuple("UnknownAnchor").field(mark).finish(),
            ErrorImpl::Shared(err) => err.debug(f),
        }
    }
}
<|endoftext|>


<commit_before>//! Defines error types used by this library.

use Value;

use reqwest::Error as ReqwestError;
use xml::reader::Error as XmlError;
use xml::common::TextPosition;

use std::io;
use std::fmt::{self, Formatter, Display};
use std::error::Error;

/// A request could not be executed.
///
/// This is either a lower-level error (for example, the HTTP request failed), or a problem with the
/// server (maybe it's not implementing XML-RPC correctly). If the server sends a valid response,
/// this error will not occur.
#[derive(Debug)]
pub enum RequestError {
    /// An HTTP communication error occurred while sending the request or receiving the response.
    HttpError(ReqwestError),

    /// The HTTP status code did not indicate success.
    HttpStatus(String),

    /// The response could not be parsed. This can happen when the server doesn't correctly
    /// implement the XML-RPC spec.
    ParseError(ParseError),

    // TODO make this extensible. anything missing?
}

impl From<ReqwestError> for RequestError {
    fn from(e: ReqwestError) -> Self {
        RequestError::HttpError(e)
    }
}

impl From<ParseError> for RequestError {
    fn from(e: ParseError) -> Self {
        RequestError::ParseError(e)
    }
}

impl Display for RequestError {
    fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
        match *self {
            RequestError::HttpError(ref err) => write!(fmt, "HTTP error: {}", err),
            RequestError::HttpStatus(ref err) => write!(fmt, "HTTP status: {}", err),
            RequestError::ParseError(ref err) => write!(fmt, "parse error: {}", err),
        }
    }
}

impl Error for RequestError {
    fn description(&self) -> &str {
        match *self {
            RequestError::HttpError(ref err) => err.description(),
            RequestError::HttpStatus(ref err) => &err,
            RequestError::ParseError(ref err) => err.description(),
        }
    }
}

/// Describes possible error that can occur when parsing a `Response`.
#[derive(Debug, PartialEq)]
pub enum ParseError {
    /// Error while parsing (malformed?) XML.
    XmlError(XmlError),

    /// Could not parse the given CDATA as XML-RPC value.
    ///
    /// For example, `<value><int>AAA</int></value>` describes an invalid value.
    InvalidValue {
        /// The type for which an invalid value was supplied (eg. `int` or `dateTime.iso8601`).
        for_type: &'static str,
        /// The value we encountered, as a string.
        found: String,
        /// The position of the invalid value inside the XML document.
        position: TextPosition,
    },

    /// Found an unexpected tag, attribute, etc.
    UnexpectedXml {
        /// A short description of the kind of data that was expected.
        expected: String,
        found: Option<String>,
        /// The position of the unexpected data inside the XML document.
        position: TextPosition,
    }
}

impl From<XmlError> for ParseError {
    fn from(e: XmlError) -> Self {
        ParseError::XmlError(e)
    }
}

impl From<io::Error> for ParseError {
    fn from(e: io::Error) -> Self {
        ParseError::XmlError(XmlError::from(e))
    }
}

impl Display for ParseError {
    fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
        match *self {
            ParseError::XmlError(ref err) => write!(fmt, "malformed XML: {}", err),
            ParseError::InvalidValue {
                for_type,
                ref found,
                ref position,
            } => write!(fmt, "invalid value for type '{}' at {}: {}", for_type, position, found),
            ParseError::UnexpectedXml {
                ref expected,
                ref position,
                found: None,
            } => {
                write!(fmt, "unexpected XML at {} (expected {})", position, expected)
            }
            ParseError::UnexpectedXml {
                ref expected,
                ref position,
                found: Some(ref found),
            } => {
                write!(fmt, "unexpected XML at {} (expected {}, found {})", position, expected, found)
            }
        }
    }
}

impl Error for ParseError {
    fn description(&self) -> &str {
        match *self {
            ParseError::XmlError(ref err) => err.description(),
            ParseError::InvalidValue { .. } => "invalid value for type",
            ParseError::UnexpectedXml { .. } => "unexpected XML content",
        }
    }
}

/// A `<fault>` response - The call failed.
///
/// The XML-RPC specification requires that a `<faultCode>` and `<faultString>` is returned in the
/// `<fault>` case, further describing the error.
#[derive(Debug, PartialEq, Eq)]
pub struct Fault {
    pub fault_code: i32,
    pub fault_string: String,
}

impl Fault {
    /// Creates a `Fault` from a `Value`.
    ///
    /// The `Value` must be a `Value::Struct` with a `faultCode` and `faultString` field.
    ///
    /// Returns `None` if the value isn't a valid `Fault`.
    pub fn from_value(value: &Value) -> Option<Self> {
        match *value {
            Value::Struct(ref map) => {
                if map.len() != 2 {
                    // incorrect field count
                    return None;
                }

                match (map.get("faultCode"), map.get("faultString")) {
                    (Some(&Value::Int(fault_code)), Some(&Value::String(ref fault_string))) => {
                        Some(Fault {
                            fault_code,
                            fault_string: fault_string.to_string(),
                        })
                    }
                    _ => None
                }
            }
            _ => None
        }
    }
}
<commit_msg>Add `Fault::to_value` to complement `from_value`<commit_after>//! Defines error types used by this library.

use Value;

use reqwest::Error as ReqwestError;
use xml::reader::Error as XmlError;
use xml::common::TextPosition;

use std::io;
use std::fmt::{self, Formatter, Display};
use std::error::Error;
use std::collections::BTreeMap;

/// A request could not be executed.
///
/// This is either a lower-level error (for example, the HTTP request failed), or a problem with the
/// server (maybe it's not implementing XML-RPC correctly). If the server sends a valid response,
/// this error will not occur.
#[derive(Debug)]
pub enum RequestError {
    /// An HTTP communication error occurred while sending the request or receiving the response.
    HttpError(ReqwestError),

    /// The HTTP status code did not indicate success.
    HttpStatus(String),

    /// The response could not be parsed. This can happen when the server doesn't correctly
    /// implement the XML-RPC spec.
    ParseError(ParseError),

    // TODO make this extensible. anything missing?
}

impl From<ReqwestError> for RequestError {
    fn from(e: ReqwestError) -> Self {
        RequestError::HttpError(e)
    }
}

impl From<ParseError> for RequestError {
    fn from(e: ParseError) -> Self {
        RequestError::ParseError(e)
    }
}

impl Display for RequestError {
    fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
        match *self {
            RequestError::HttpError(ref err) => write!(fmt, "HTTP error: {}", err),
            RequestError::HttpStatus(ref err) => write!(fmt, "HTTP status: {}", err),
            RequestError::ParseError(ref err) => write!(fmt, "parse error: {}", err),
        }
    }
}

impl Error for RequestError {
    fn description(&self) -> &str {
        match *self {
            RequestError::HttpError(ref err) => err.description(),
            RequestError::HttpStatus(ref err) => &err,
            RequestError::ParseError(ref err) => err.description(),
        }
    }
}

/// Describes possible error that can occur when parsing a `Response`.
#[derive(Debug, PartialEq)]
pub enum ParseError {
    /// Error while parsing (malformed?) XML.
    XmlError(XmlError),

    /// Could not parse the given CDATA as XML-RPC value.
    ///
    /// For example, `<value><int>AAA</int></value>` describes an invalid value.
    InvalidValue {
        /// The type for which an invalid value was supplied (eg. `int` or `dateTime.iso8601`).
        for_type: &'static str,
        /// The value we encountered, as a string.
        found: String,
        /// The position of the invalid value inside the XML document.
        position: TextPosition,
    },

    /// Found an unexpected tag, attribute, etc.
    UnexpectedXml {
        /// A short description of the kind of data that was expected.
        expected: String,
        found: Option<String>,
        /// The position of the unexpected data inside the XML document.
        position: TextPosition,
    }
}

impl From<XmlError> for ParseError {
    fn from(e: XmlError) -> Self {
        ParseError::XmlError(e)
    }
}

impl From<io::Error> for ParseError {
    fn from(e: io::Error) -> Self {
        ParseError::XmlError(XmlError::from(e))
    }
}

impl Display for ParseError {
    fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
        match *self {
            ParseError::XmlError(ref err) => write!(fmt, "malformed XML: {}", err),
            ParseError::InvalidValue {
                for_type,
                ref found,
                ref position,
            } => write!(fmt, "invalid value for type '{}' at {}: {}", for_type, position, found),
            ParseError::UnexpectedXml {
                ref expected,
                ref position,
                found: None,
            } => {
                write!(fmt, "unexpected XML at {} (expected {})", position, expected)
            }
            ParseError::UnexpectedXml {
                ref expected,
                ref position,
                found: Some(ref found),
            } => {
                write!(fmt, "unexpected XML at {} (expected {}, found {})", position, expected, found)
            }
        }
    }
}

impl Error for ParseError {
    fn description(&self) -> &str {
        match *self {
            ParseError::XmlError(ref err) => err.description(),
            ParseError::InvalidValue { .. } => "invalid value for type",
            ParseError::UnexpectedXml { .. } => "unexpected XML content",
        }
    }
}

/// A `<fault>` response - The call failed.
///
/// The XML-RPC specification requires that a `<faultCode>` and `<faultString>` is returned in the
/// `<fault>` case, further describing the error.
#[derive(Debug, PartialEq, Eq)]
pub struct Fault {
    pub fault_code: i32,
    pub fault_string: String,
}

impl Fault {
    /// Creates a `Fault` from a `Value`.
    ///
    /// The `Value` must be a `Value::Struct` with a `faultCode` and `faultString` field.
    ///
    /// Returns `None` if the value isn't a valid `Fault`.
    pub fn from_value(value: &Value) -> Option<Self> {
        match *value {
            Value::Struct(ref map) => {
                if map.len() != 2 {
                    // incorrect field count
                    return None;
                }

                match (map.get("faultCode"), map.get("faultString")) {
                    (Some(&Value::Int(fault_code)), Some(&Value::String(ref fault_string))) => {
                        Some(Fault {
                            fault_code,
                            fault_string: fault_string.to_string(),
                        })
                    }
                    _ => None
                }
            }
            _ => None
        }
    }

    /// Turns this `Fault` into an equivalent `Value`.
    ///
    /// The returned value can be parsed back into a `Fault` using `Fault::from_value` or returned
    /// as a `<fault>` error response by serializing it into a `<fault></fault>` tag.
    pub fn to_value(&self) -> Value {
        let mut map = BTreeMap::new();
        map.insert("faultCode".to_string(), Value::from(self.fault_code));
        map.insert("faultString".to_string(), Value::from(self.fault_string.as_ref()));

        Value::Struct(map)
    }
}

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

    #[test]
    fn fault_roundtrip() {
        let input = Fault {
            fault_code: -123456,
            fault_string: "The Bald Lazy House Jumps Over The Hyperactive Kitten".to_string()
        };

        assert_eq!(Fault::from_value(&input.to_value()), Some(input));
    }
}
<|endoftext|>